diff --git a/.gitignore b/.gitignore index 1ef5d60..3d71d76 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ explorer/node_modules explorer/dist .idea dist/* -assets/bindata.go \ No newline at end of file +assets/bindata.go +.DS_Store \ No newline at end of file diff --git a/commands/server/cli_app.go b/commands/server/cli_app.go index 60cea0b..74c7265 100644 --- a/commands/server/cli_app.go +++ b/commands/server/cli_app.go @@ -102,6 +102,11 @@ func ConfigureServer(l *goapp.Lifecycle, conf *config.ServerConfig) { Manager: app.Get("gonode.manager").(*core.PgNodeManager), }, "core.raw": &raw.RawViewHandler{}, + "media.image": &media.MediaViewHandler{ + Vault: app.Get("gonode.vault.fs").(*vault.Vault), + MaxWidth: conf.Media.Image.MaxWidth, + AllowedWidths: conf.Media.Image.AllowedWidths, + }, } }) diff --git a/docs/modules/guard.md b/docs/modules/guard.md index 94fe0da..aae0549 100644 --- a/docs/modules/guard.md +++ b/docs/modules/guard.md @@ -2,6 +2,7 @@ Guard ===== Introduction +------------ Guard plugin handle request authentification. The modules comes with a dedicated middleware and request authenticators. For now there is only 2 authenticators implemented: diff --git a/docs/modules/media.md b/docs/modules/media.md new file mode 100644 index 0000000..b061615 --- /dev/null +++ b/docs/modules/media.md @@ -0,0 +1,86 @@ +Media +===== + +Introduction +------------ + +Media stores information about a media, for now only image and youtube videos are supported. + +Image Type +---------- + +The image type provides the current fields: + +Meta: + + - ``Width`` + - ``Height`` + - ``Size`` + - ``ContentType`` + - ``Length`` + - ``Exif``: not used yet + - ``Hash``: not used yet + - ``SourceStatus``: SourceUrl processing status + - ``SourceError``: SourceUrl processing result on error + +Data: + + - ``Reference``: contextual information about the media + - ``Name``: image name + - ``SourceUrl``: can be used to provided an url to retrieve the media + +You can retrieve the binary through an api call by adding the ``?raw=1`` into the query string. The prism handler can +also be used, this entry point will provide crop and resize option. + + - ``http://localhost:2405/prism/bcb537ab-b349-4b3d-87e2-e43e17519af7`` => get the original image + - ``http://localhost:2405/prism/bcb537ab-b349-4b3d-87e2-e43e17519af7?mr=250`` => resize the media with the provided width + - ``http://localhost:2405/prism/bcb537ab-b349-4b3d-87e2-e43e17519af7?mf=200,200`` => crop the media using a 200x200 square from + the center of the image. + - ``http://localhost:2405/prism/bcb537ab-b349-4b3d-87e2-e43e17519af7?mf=200,200,50,50`` => crop the media using a 200x200 square from + the 50x50 top left corner. + +The image resize and crop only works with: ``jpg``, ``png`` and ``jpg`` files. + +YouTube Type +------------ + +The YouTube type provided the following fields: + +Meta (from youtube metadata) + + - ``Type`` + - ``Html`` + - ``Width`` + - ``Height`` + - ``Version`` + - ``Title`` + - ``ProviderName`` + - ``AuthorName`` + - ``AuthorUrl`` + - ``ProviderUrl`` + - ``ThumbnailUrl`` + - ``ThumbnailWidth`` + - ``ThumbnailHeight`` + +Data: + + - ``Vid``: The video id + - ``Status``: processing status + - ``Error``: processing error + +The downloaded thumbnail will become a media type. + +Configuration +------------- + +```toml +[media] + [media.image] + allowed_widths = [100, 200] + max_width = 300 +``` + + - ``allowed_widths``: slice of valid widths, if empty all widths are possible + - ``max_width``: max allows width, if empty and ``allowed_width`` is empty then all widths are possible. + +*To avoid any issues, those settings must be set and a cache layer configured* diff --git a/modules/config/config_server.go b/modules/config/config_server.go index 39ab5f1..def8ec3 100644 --- a/modules/config/config_server.go +++ b/modules/config/config_server.go @@ -50,6 +50,15 @@ type ServerSecurity struct { } `toml:"cors"` } +type ServerMediaImage struct { + AllowedWidths []uint `toml:"allowed_widths"` + MaxWidth uint `toml:"max_width"` +} + +type ServerMedia struct { + Image *ServerMediaImage `toml:"image"` +} + type ServerDatabase struct { Name string `toml:"name"` DSN string `toml:"dsn"` @@ -78,6 +87,7 @@ type ServerConfig struct { Security *ServerSecurity `toml:"security"` Search *ServerSearch `toml:"search"` BinData *ServerBinData `toml:"bindata"` + Media *ServerMedia `toml:"media"` } func NewServerConfig() *ServerConfig { @@ -93,5 +103,11 @@ func NewServerConfig() *ServerConfig { Assets: make(map[string]*ServerBinDataAsset, 0), // Templates: make([]string, 0), }, + Media: &ServerMedia{ + Image: &ServerMediaImage{ + MaxWidth: uint(1024), + // AllowedWidths: make([]uint, 0), + }, + }, } } diff --git a/modules/config/config_test.go b/modules/config/config_test.go index a04c58d..6da93bb 100644 --- a/modules/config/config_test.go +++ b/modules/config/config_test.go @@ -72,6 +72,10 @@ key = "ZeSecretKey0oo" public = "/explorer" private = "github.com/rande/gonode/explorer/dist" +[media] + [media.image] + allowed_widths = [100, 200] + max_width = 300 `, config) assert.NoError(t, err) @@ -103,6 +107,10 @@ key = "ZeSecretKey0oo" assert.Equal(t, "/var/go", config.BinData.BasePath) assert.Equal(t, []string{"/path/post/templates", "/path/media/templates"}, config.BinData.Templates) + // test media + assert.Equal(t, uint(300), config.Media.Image.MaxWidth) + assert.Equal(t, []uint{100, 200}, config.Media.Image.AllowedWidths) + // debug config.Guard.Jwt.Login.Path = `^\/nodes\/(.*)$` diff --git a/modules/helper/reader.go b/modules/helper/reader.go new file mode 100644 index 0000000..3e3f79d --- /dev/null +++ b/modules/helper/reader.go @@ -0,0 +1,40 @@ +// Copyright © 2014-2015 Thomas Rabaix . +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file. + +package helper + +import ( + "io" +) + +type PartialReader struct { + Reader io.ReadCloser + Size int + Data []byte + Len int +} + +func (r *PartialReader) Read(p []byte) (n int, err error) { + n, err = r.Reader.Read(p) + + toRead := r.Size - len(r.Data) + + if toRead > 0 { + if n < toRead { + toRead = n + } + + dst := make([]byte, toRead) + n := copy(dst, p) + + r.Data = append(r.Data, dst[0:n]...) + } + + return +} + +func (r *PartialReader) Close() error { + return r.Reader.Close() +} diff --git a/modules/helper/reader_test.go b/modules/helper/reader_test.go new file mode 100644 index 0000000..f666c8b --- /dev/null +++ b/modules/helper/reader_test.go @@ -0,0 +1,59 @@ +// Copyright © 2014-2015 Thomas Rabaix . +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file. + +package helper + +import ( + "github.com/stretchr/testify/assert" + "io/ioutil" + "os" + "testing" +) + +func Test_Parial_Reader_Incomplet_Data(t *testing.T) { + + f, _ := ioutil.TempFile(os.TempDir(), "gonode_test") + f.Write([]byte("hello world")) + f.Seek(0, 0) + + defer f.Close() + + r := PartialReader{ + Reader: f, + Size: 20, + } + + data := make([]byte, 50) + + n, err := r.Read(data) + + assert.NoError(t, err) + assert.Equal(t, 11, n) + assert.Equal(t, []byte("hello world"), data[:n]) + assert.Equal(t, []byte("hello world"), r.Data) +} + +func Test_Parial_Reader_Complet_Data(t *testing.T) { + + f, _ := ioutil.TempFile(os.TempDir(), "gonode_test") + f.Write([]byte("hello world")) + f.Seek(0, 0) + + defer f.Close() + + r := PartialReader{ + Reader: f, + Size: 5, + } + + data := make([]byte, 50) + + n, err := r.Read(data) + + assert.NoError(t, err) + assert.Equal(t, 11, n) + assert.Equal(t, []byte("hello world"), data[:n]) + assert.Equal(t, []byte("hello"), r.Data) +} diff --git a/modules/media/media_image.go b/modules/media/media_image.go index 2445388..4372e70 100644 --- a/modules/media/media_image.go +++ b/modules/media/media_image.go @@ -9,8 +9,10 @@ import ( "fmt" "github.com/lib/pq" "github.com/rande/gonode/core" + "github.com/rande/gonode/modules/helper" "github.com/rande/gonode/modules/vault" "io" + "net/http" ) type ExifMeta map[string]string @@ -165,13 +167,18 @@ func (l *ImageDownloadListener) Handle(notification *pq.Notification, m core.Nod vaultmeta := core.GetVaultMetadata(node) - _, err = l.Vault.Put(node.UniqueId(), vaultmeta, resp.Body) + r := &helper.PartialReader{ + Reader: resp.Body, + Size: 500, + } + + _, err = l.Vault.Put(node.UniqueId(), vaultmeta, r) if err != nil { return core.PubSubListenContinue, err } - meta.ContentType = "application/octet-stream" + meta.ContentType = http.DetectContentType(r.Data) meta.SourceStatus = core.ProcessStatusDone m.Save(node, false) diff --git a/modules/media/media_image_view.go b/modules/media/media_image_view.go new file mode 100644 index 0000000..428aada --- /dev/null +++ b/modules/media/media_image_view.go @@ -0,0 +1,190 @@ +// Copyright © 2014-2015 Thomas Rabaix . +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file. + +package media + +import ( + "errors" + "github.com/nfnt/resize" + "github.com/oliamb/cutter" + "github.com/rande/gonode/core" + "github.com/rande/gonode/modules/vault" + "image" + "image/gif" + "image/jpeg" + "image/png" + "io" + "io/ioutil" + "os" + "strconv" + "strings" +) + +var ( + InvalidFitOptionsError = errors.New("Invalid fit options") + InvalidWidthRangeError = errors.New("Invalid width range") + WidthNotAllowedError = errors.New("Width is not allowed") +) + +func ContainsSize(size uint, allowed []uint) bool { + if len(allowed) == 0 { + return true + } + + for _, v := range allowed { + if v == size { + return true + } + } + + return false +} + +type MediaViewHandler struct { + Vault *vault.Vault + AllowedWidths []uint + MaxWidth uint +} + +func (m *MediaViewHandler) Execute(node *core.Node, request *core.ViewRequest, response *core.ViewResponse) error { + values := request.HttpRequest.URL.Query() + + meta := node.Meta.(*ImageMeta) + + response.HttpResponse.Header().Set("Content-Type", meta.ContentType) + + for _, format := range []string{"image/jpeg", "image/gif", "image/png"} { + if format == meta.ContentType { // only resize supported format + if _, ok := values["mr"]; ok { // ask for binary content + return m.imageResize(node, request, response) + } else if _, ok := values["mf"]; ok { + return m.imageFit(node, request, response) + } + } + } + + _, err := m.Vault.Get(node.UniqueId(), response.HttpResponse) + + return err +} + +func (m *MediaViewHandler) imageResize(node *core.Node, request *core.ViewRequest, response *core.ViewResponse) error { + width, err := strconv.ParseUint(request.HttpRequest.URL.Query().Get("mr"), 10, 0) + + if err != nil { + return err + } + + if m.MaxWidth > 0 && uint(width) > m.MaxWidth { + return InvalidWidthRangeError + } + + if !ContainsSize(uint(width), m.AllowedWidths) { + return WidthNotAllowedError + } + + imageSrc, err := m.getImage(node) + + if err != nil { + return err + } + + imageDst := resize.Resize(uint(width), 0, imageSrc, resize.Bicubic) + + return m.encode(imageDst, node, response.HttpResponse) +} + +func (m *MediaViewHandler) imageFit(node *core.Node, request *core.ViewRequest, response *core.ViewResponse) error { + options := strings.Split(request.HttpRequest.URL.Query().Get("mf"), ",") + + if len(options) != 2 && len(options) != 4 { + return InvalidFitOptionsError + } + + width, err := strconv.ParseInt(options[0], 10, 0) + if err != nil { + return err + } + + height, err := strconv.ParseInt(options[1], 10, 0) + if err != nil { + return err + } + + if m.MaxWidth > 0 && uint(width) > m.MaxWidth { + return InvalidWidthRangeError + } + + if !ContainsSize(uint(width), m.AllowedWidths) { + return WidthNotAllowedError + } + + var cropCenterX, cropCenterY int64 + var mode cutter.AnchorMode + mode = cutter.Centered + + if len(options) == 4 { + cropCenterX, err = strconv.ParseInt(options[2], 10, 0) + if err != nil { + return err + } + + cropCenterY, err = strconv.ParseInt(options[3], 10, 0) + if err != nil { + return err + } + + mode = cutter.TopLeft + } + + imageSrc, err := m.getImage(node) + + if err != nil { + return InvalidFitOptionsError + } + + croppedImg, err := cutter.Crop(imageSrc, cutter.Config{ + Width: int(width), + Height: int(height), + Anchor: image.Point{int(cropCenterX), int(cropCenterY)}, + Mode: mode, + }) + + return m.encode(croppedImg, node, response.HttpResponse) +} + +func (m *MediaViewHandler) getImage(node *core.Node) (image.Image, error) { + source, _ := ioutil.TempFile(os.TempDir(), "gonode_image_resize_") + defer source.Close() + + m.Vault.Get(node.UniqueId(), source) + source.Seek(0, 0) + + meta := node.Meta.(*ImageMeta) + + if meta.ContentType == "image/jpeg" { + return jpeg.Decode(source) + } + + if meta.ContentType == "image/png" { + return png.Decode(source) + } + + return gif.Decode(source) +} + +func (m *MediaViewHandler) encode(image image.Image, node *core.Node, w io.Writer) error { + meta := node.Meta.(*ImageMeta) + + if meta.ContentType == "image/jpeg" { + return jpeg.Encode(w, image, nil) + } + + if meta.ContentType == "image/png" { + return png.Encode(w, image) + } + + return gif.Encode(w, image, nil) +} diff --git a/modules/media/media_image_view_test.go b/modules/media/media_image_view_test.go new file mode 100644 index 0000000..6cc539c --- /dev/null +++ b/modules/media/media_image_view_test.go @@ -0,0 +1,304 @@ +// Copyright © 2014-2015 Thomas Rabaix . +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file. + +package media + +import ( + "errors" + "github.com/rande/gonode/core" + "github.com/rande/gonode/modules/vault" + "github.com/stretchr/testify/assert" + "net/http" + "net/http/httptest" + "os" + "testing" +) + +func Test_ContainsSize(t *testing.T) { + assert.True(t, ContainsSize(200, []uint{})) + assert.True(t, ContainsSize(200, []uint{100, 200, 400})) + + assert.False(t, ContainsSize(200, []uint{100, 300})) +} + +func GetDriver() vault.VaultDriver { + fv, err := os.Open("../../test/fixtures/photo.jpg.vault") + + core.PanicOnError(err) + + driver := &vault.MockedDriver{} + driver. + // default string for 111...111 uuid + On("GetReader", "eb/60/6938046e0b96477b491c35ab8ce174ce96cfef588c827508a14822e16939.bin.vault"). + Return(fv, nil) + + f, err := os.Open("../../test/fixtures/photo.jpg") + core.PanicOnError(err) + driver. + // default string for 111...111 uuid + On("GetReader", "eb/60/6938046e0b96477b491c35ab8ce174ce96cfef588c827508a14822e16939.bin"). + Return(f, nil) + + return driver +} + +func Test_MediaViewHandler_NoError_And_NoParam(t *testing.T) { + n := core.NewNode() + n.Meta = &ImageMeta{ + ContentType: "image/jpeg", + } + + m := &MediaViewHandler{ + Vault: &vault.Vault{ + Algo: "no_op", + Driver: GetDriver(), + }, + } + + req, _ := http.NewRequest("GET", "/we-don-t-care", nil) + + request := &core.ViewRequest{ + HttpRequest: req, + } + + res := httptest.NewRecorder() + response := &core.ViewResponse{ + HttpResponse: res, + } + + err := m.Execute(n, request, response) + + assert.NoError(t, err) + assert.Equal(t, "image/jpeg", res.Header().Get("Content-Type")) + assert.True(t, len(res.Body.Bytes()) > 1024) +} + +func Test_MediaViewHandler_VaultError(t *testing.T) { + driver := &vault.MockedDriver{} + driver. + // default string for 111...111 uuid + On("GetReader", "eb/60/6938046e0b96477b491c35ab8ce174ce96cfef588c827508a14822e16939.bin.vault"). + Return(nil, errors.New("error")) + + n := core.NewNode() + n.Meta = &ImageMeta{ + ContentType: "image/jpeg", + } + + m := &MediaViewHandler{ + Vault: &vault.Vault{ + Algo: "no_op", + Driver: driver, + }, + } + + req, _ := http.NewRequest("GET", "/we-don-t-care", nil) + + request := &core.ViewRequest{ + HttpRequest: req, + } + + res := httptest.NewRecorder() + response := &core.ViewResponse{ + HttpResponse: res, + } + + err := m.Execute(n, request, response) + + assert.Error(t, err) + assert.Equal(t, "image/jpeg", res.Header().Get("Content-Type")) +} + +func Test_MediaViewHandler_InvalidResize_Width(t *testing.T) { + n := core.NewNode() + n.Meta = &ImageMeta{ + ContentType: "image/jpeg", + } + + m := &MediaViewHandler{ + Vault: &vault.Vault{ + Algo: "no_op", + Driver: GetDriver(), + }, + MaxWidth: 300, + } + + req, _ := http.NewRequest("GET", "/we-don-t-care?mr=3000", nil) + + request := &core.ViewRequest{ + HttpRequest: req, + } + + res := httptest.NewRecorder() + response := &core.ViewResponse{ + HttpResponse: res, + } + + err := m.Execute(n, request, response) + + assert.Error(t, err) + assert.Equal(t, err, InvalidWidthRangeError) +} + +func Test_MediaViewHandler_Invalid_Crop_Width(t *testing.T) { + n := core.NewNode() + n.Meta = &ImageMeta{ + ContentType: "image/jpeg", + } + + m := &MediaViewHandler{ + Vault: &vault.Vault{ + Algo: "no_op", + Driver: GetDriver(), + }, + MaxWidth: 300, + } + + req, _ := http.NewRequest("GET", "/we-don-t-care?mf=3000,3000", nil) + + request := &core.ViewRequest{ + HttpRequest: req, + } + + res := httptest.NewRecorder() + response := &core.ViewResponse{ + HttpResponse: res, + } + + err := m.Execute(n, request, response) + + assert.Error(t, err) + assert.Equal(t, err, InvalidWidthRangeError) +} + +func Test_MediaViewHandler_Invalid_Resize_NotAllowedWidth(t *testing.T) { + n := core.NewNode() + n.Meta = &ImageMeta{ + ContentType: "image/jpeg", + } + + m := &MediaViewHandler{ + Vault: &vault.Vault{ + Algo: "no_op", + Driver: GetDriver(), + }, + MaxWidth: 300, + AllowedWidths: []uint{100, 150}, + } + + req, _ := http.NewRequest("GET", "/we-don-t-care?mr=120", nil) + + request := &core.ViewRequest{ + HttpRequest: req, + } + + res := httptest.NewRecorder() + response := &core.ViewResponse{ + HttpResponse: res, + } + + err := m.Execute(n, request, response) + + assert.Error(t, err) + assert.Equal(t, err, WidthNotAllowedError) +} + +func Test_MediaViewHandler_Invalid_Crop_NotAllowedWidth(t *testing.T) { + n := core.NewNode() + n.Meta = &ImageMeta{ + ContentType: "image/jpeg", + } + + m := &MediaViewHandler{ + Vault: &vault.Vault{ + Algo: "no_op", + Driver: GetDriver(), + }, + MaxWidth: 300, + AllowedWidths: []uint{100, 150}, + } + + req, _ := http.NewRequest("GET", "/we-don-t-care?mf=120,120", nil) + + request := &core.ViewRequest{ + HttpRequest: req, + } + + res := httptest.NewRecorder() + response := &core.ViewResponse{ + HttpResponse: res, + } + + err := m.Execute(n, request, response) + + assert.Error(t, err) + assert.Equal(t, err, WidthNotAllowedError) +} + +func Test_MediaViewHandler_Resize(t *testing.T) { + n := core.NewNode() + n.Meta = &ImageMeta{ + ContentType: "image/jpeg", + } + + m := &MediaViewHandler{ + Vault: &vault.Vault{ + Algo: "no_op", + Driver: GetDriver(), + }, + MaxWidth: 300, + AllowedWidths: []uint{100, 150}, + } + + req, _ := http.NewRequest("GET", "/we-don-t-care?mr=150", nil) + + request := &core.ViewRequest{ + HttpRequest: req, + } + + res := httptest.NewRecorder() + response := &core.ViewResponse{ + HttpResponse: res, + } + + err := m.Execute(n, request, response) + + assert.NoError(t, err) + assert.Equal(t, "image/jpeg", res.Header().Get("Content-Type")) + assert.True(t, len(res.Body.Bytes()) > 1024) +} + +func Test_MediaViewHandler_Crop(t *testing.T) { + n := core.NewNode() + n.Meta = &ImageMeta{ + ContentType: "image/jpeg", + } + + m := &MediaViewHandler{ + Vault: &vault.Vault{ + Algo: "no_op", + Driver: GetDriver(), + }, + MaxWidth: 300, + AllowedWidths: []uint{100, 150}, + } + + req, _ := http.NewRequest("GET", "/we-don-t-care?mf=150,150", nil) + + request := &core.ViewRequest{ + HttpRequest: req, + } + + res := httptest.NewRecorder() + response := &core.ViewResponse{ + HttpResponse: res, + } + + err := m.Execute(n, request, response) + + assert.NoError(t, err) + assert.Equal(t, "image/jpeg", res.Header().Get("Content-Type")) + assert.True(t, len(res.Body.Bytes()) > 1024) +} diff --git a/modules/vault/vault_cipher.go b/modules/vault/vault_cipher.go index 7a6351a..f076ee6 100644 --- a/modules/vault/vault_cipher.go +++ b/modules/vault/vault_cipher.go @@ -34,7 +34,7 @@ func GetCipher(mode string) (Encrypter, Decrypter) { return NoopEncrypter, NoopDecrypter default: - panic("Unable to find the cipher") + panic("Unable to find the cipher: " + mode) } } diff --git a/modules/vault/vault_driver_mock.go b/modules/vault/vault_driver_mock.go new file mode 100644 index 0000000..bc413d5 --- /dev/null +++ b/modules/vault/vault_driver_mock.go @@ -0,0 +1,47 @@ +// Copyright © 2014-2015 Thomas Rabaix . +// +// Use of this source code is governed by an MIT-style +// license that can be found in the LICENSE file. + +package vault + +import ( + "github.com/stretchr/testify/mock" + "io" +) + +type MockedDriver struct { + mock.Mock +} + +func (m *MockedDriver) Has(key string) bool { + args := m.Mock.Called(key) + + return args.Bool(0) +} + +func (m *MockedDriver) GetReader(key string) (io.ReadCloser, error) { + args := m.Mock.Called(key) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(io.ReadCloser), args.Error(1) +} + +func (m *MockedDriver) GetWriter(key string) (io.WriteCloser, error) { + args := m.Mock.Called(key) + + if args.Get(0) == nil { + return nil, args.Error(1) + } + + return args.Get(0).(io.WriteCloser), args.Error(1) +} + +func (m *MockedDriver) Remove(key string) error { + args := m.Mock.Called(key) + + return args.Error(0) +} diff --git a/server.toml.dist b/server.toml.dist index ab81021..8fac57a 100644 --- a/server.toml.dist +++ b/server.toml.dist @@ -41,4 +41,9 @@ templates = [ [bindata.assets.explorer] index = "index.html" public = "" - private = "github.com/rande/gonode/explorer/dist" \ No newline at end of file + private = "github.com/rande/gonode/explorer/dist" + +[media] + [media.image] + allowed_widths = [100, 250, 500, 1024] + max_width = 1024 \ No newline at end of file diff --git a/test/config_test.toml b/test/config_test.toml index 87febdd..93448f5 100644 --- a/test/config_test.toml +++ b/test/config_test.toml @@ -38,4 +38,9 @@ templates = [ [bindata.assets] [bindata.assets.explorer] public = "/explorer" - private = "github.com/rande/gonode/explorer/dist" \ No newline at end of file + private = "github.com/rande/gonode/explorer/dist" + +[media] + [media.image] + allowed_widths = [100, 250, 500, 1024] + max_width = 1024 \ No newline at end of file diff --git a/test/config_travis.toml b/test/config_travis.toml index b88a5bf..2ffbfea 100644 --- a/test/config_travis.toml +++ b/test/config_travis.toml @@ -38,4 +38,9 @@ templates = [ [bindata.assets] [bindata.assets.explorer] public = "/explorer" - private = "github.com/rande/gonode/explorer/dist" \ No newline at end of file + private = "github.com/rande/gonode/explorer/dist" + +[media] + [media.image] + allowed_widths = [100, 250, 500, 1024] + max_width = 1024 \ No newline at end of file diff --git a/test/fixtures/fake.go b/test/fixtures/fake.go index e280aa5..a89028f 100644 --- a/test/fixtures/fake.go +++ b/test/fixtures/fake.go @@ -21,7 +21,9 @@ func GetFakeMediaNode(pos int) *core.Node { Name: "Go pic", Reference: "0x0", } - node.Meta = &media.ImageMeta{} + node.Meta = &media.ImageMeta{ + SourceStatus: core.ProcessStatusInit, + } return node } @@ -162,5 +164,25 @@ func LoadFixtures(m *core.PgNodeManager, max int) error { core.PanicOnError(err) + // create real image + image := core.NewNode() + + image.Type = "media.image" + image.Name = "The image for resize" + image.Slug = "the-image-for-resize" + image.Data = &media.Image{ + Name: "Resize.jpg", + Reference: "0x0", + // from: https://github.com/nfnt/resize + SourceUrl: "https://camo.githubusercontent.com/ef6fdc21c7c8e17354524f0982cdb52885335191/687474703a2f2f6e666e742e6769746875622e636f6d2f696d672f494d475f333639345f3732302e6a7067", + } + image.Meta = &media.ImageMeta{ + SourceStatus: core.ProcessStatusInit, + } + + _, err = m.Save(image, false) + + core.PanicOnError(err) + return nil } diff --git a/test/fixtures/photo.jpg b/test/fixtures/photo.jpg new file mode 100755 index 0000000..9b52ba2 Binary files /dev/null and b/test/fixtures/photo.jpg differ diff --git a/test/fixtures/photo.jpg.vault b/test/fixtures/photo.jpg.vault new file mode 100644 index 0000000..f04a496 --- /dev/null +++ b/test/fixtures/photo.jpg.vault @@ -0,0 +1,6 @@ +{ + "meta_key": "", + "bin_key": "", + "algo": "no_op", + "hash": "" +} \ No newline at end of file