From 77c2e6aca2dc0f851f55e30a0f49c9ee7c2c952e Mon Sep 17 00:00:00 2001 From: Max Resnick Date: Sat, 27 Jun 2020 21:23:44 -0700 Subject: adds post meta, basic template for single image --- go.mod | 2 +- internal/db/redis/image.go | 16 ++++++++---- internal/image/handler.go | 32 +++++++++++++++++++++-- internal/image/image_test.go | 61 ++++++++++++++++++++++++++++++++++++++++++-- internal/image/model.go | 2 ++ internal/image/service.go | 14 +++++----- templates/pages/image.tmpl | 3 ++- 7 files changed, 111 insertions(+), 19 deletions(-) diff --git a/go.mod b/go.mod index 0209999..2332a46 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/gomodule/redigo v2.0.0+incompatible github.com/matoous/go-nanoid v1.3.0 github.com/muyo/sno v1.1.0 - github.com/pkg/errors v0.9.1 // indirect + github.com/pkg/errors v0.9.1 github.com/rafaeljusto/redigomock v2.3.0+incompatible github.com/speps/go-hashids v2.0.0+incompatible github.com/stretchr/testify v1.5.1 diff --git a/internal/db/redis/image.go b/internal/db/redis/image.go index 1f4e8fa..f216531 100644 --- a/internal/db/redis/image.go +++ b/internal/db/redis/image.go @@ -1,6 +1,7 @@ package redis import ( + "errors" "fmt" "log" @@ -11,6 +12,8 @@ import ( const V1FilePathFmt = "v1imagepost:%s" +var ErrNotFound error = errors.New("Not Found") + // ImageRepo deps. for storage type ImageRepo struct { db *redis.Pool @@ -23,14 +26,14 @@ func NewRedisImageRepo(conn *redis.Pool) *ImageRepo { } } -func fileKey(filename, V1FilePathFmt string) string { - return fmt.Sprintf(V1FilePathFmt, filename) +func fileKey(imageID, V1FilePathFmt string) string { + return fmt.Sprintf(V1FilePathFmt, imageID) } -func (r *ImageRepo) AddNewFile(filename string, meta *image.PostMeta, timeout int) error { +func (r *ImageRepo) AddNewFile(imageID string, meta *image.PostMeta, timeout int) error { conn := r.db.Get() defer conn.Close() - key := fileKey(filename, V1FilePathFmt) + key := fileKey(imageID, V1FilePathFmt) _, err := conn.Do("HMSET", redis.Args{}.Add(key).AddFlat(meta)...) if err != nil { log.Fatal(err) @@ -45,8 +48,11 @@ func (r *ImageRepo) GetFile(fileUrl string) (*image.PostMeta, error) { key := fileKey(fileUrl, V1FilePathFmt) res, err := redis.Values(conn.Do("HGETALL", key)) if err != nil { - return &image.PostMeta{}, err + return &image.PostMeta{}, ErrNotFound } err = redis.ScanStruct(res, imageMeta) + if imageMeta.FilePath == "" { + return &image.PostMeta{}, ErrNotFound + } return imageMeta, err } diff --git a/internal/image/handler.go b/internal/image/handler.go index 2db4c40..f41ed4d 100644 --- a/internal/image/handler.go +++ b/internal/image/handler.go @@ -2,6 +2,7 @@ package image import ( "fmt" + "html/template" "io/ioutil" "log" "net/http" @@ -40,9 +41,13 @@ func (h *imageHandler) GetImage(w http.ResponseWriter, r *http.Request) { } fileUrl := fmt.Sprintf("/f/%s", fileMeta.FilePath) data := struct { - ImageUrl string + ImageUrl string + ImageTitle string + ImageDesc string }{ fileUrl, + fileMeta.Title, + fileMeta.Desc, } h.service.Render(w, "image.tmpl", data) } @@ -79,7 +84,30 @@ func (h *imageHandler) PostImage(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Incorrect Content Type")) return } - fileName, fileID, err := h.service.AddFile(extension, fileType, fileBytes) + formData := r.PostForm + rawPostTitle := formData.Get("title") + rawPostDesc := formData.Get("desc") + postTitle := template.HTMLEscapeString(rawPostTitle) + postDesc := template.HTMLEscapeString(rawPostDesc) + + if len(rawPostDesc) != len(postDesc) { + log.Printf("description not clean") + w.WriteHeader(400) + w.Write([]byte("Incorrect Content Type")) + return + } + if len(rawPostTitle) != len(postTitle) { + log.Printf("invalid title") + w.WriteHeader(400) + w.Write([]byte("Invalid image meta data")) + return + } + postMeta := &PostMeta{ + MimeType: fileType, + Title: postTitle, + Desc: postDesc, + } + fileName, fileID, err := h.service.AddFile(extension, postMeta, fileBytes) if err != nil { log.Printf("failed to write file") w.WriteHeader(500) diff --git a/internal/image/image_test.go b/internal/image/image_test.go index 3425213..daf4aea 100644 --- a/internal/image/image_test.go +++ b/internal/image/image_test.go @@ -16,6 +16,7 @@ import ( "strings" "testing" + "github.com/go-chi/chi" "github.com/gomodule/redigo/redis" "github.com/rafaeljusto/redigomock" _ "github.com/stretchr/testify/mock" @@ -27,6 +28,7 @@ import ( var ( projectRoot string + emptyBody *bytes.Buffer = bytes.NewBuffer([]byte(``)) ) func init() { @@ -83,6 +85,34 @@ func prepareRequest(t *testing.T, filename, mimeType string) (*multipart.Writer, return writer, body, err } +func prepareImage() (*redigomock.Conn, image.Handler) { + // setup redis for tests + conn := redigomock.NewConn() + pool := &redis.Pool{ + // Return the same connection mock for each Get() call. + Dial: func() (redis.Conn, error) { return conn, nil }, + MaxIdle: 10, + } + repo := db.NewRedisImageRepo(pool) + + // setup image package + imageBuildDir, err := ioutil.TempDir("", "test-images") + if err != nil { + log.Fatal(err) + } + cwd, _ := os.Getwd() + base := filepath.Join(cwd, "templates") + renderer, err := tmpl.NewHTMLTmpl(base) + if err != nil { + log.Fatal(err) + } + defer os.RemoveAll(imageBuildDir) + imageService := image.NewService(repo, imageBuildDir, renderer) + imageHandler := image.NewHandler(imageService) + return conn, imageHandler + +} + func TestPostImage(t *testing.T) { // setup redis for tests conn := redigomock.NewConn() @@ -91,7 +121,14 @@ func TestPostImage(t *testing.T) { Dial: func() (redis.Conn, error) { return conn, nil }, MaxIdle: 10, } - conn.Command("HMSET", redigomock.NewAnyData(), redigomock.NewAnyData(), redigomock.NewAnyData(), redigomock.NewAnyData(), redigomock.NewAnyData(), redigomock.NewAnyData(), redigomock.NewAnyData(), redigomock.NewAnyData(), redigomock.NewAnyData()) + conn.Command("HMSET", + redigomock.NewAnyData(), redigomock.NewAnyData(), + redigomock.NewAnyData(), redigomock.NewAnyData(), + redigomock.NewAnyData(), redigomock.NewAnyData(), + redigomock.NewAnyData(), redigomock.NewAnyData(), + redigomock.NewAnyData(), redigomock.NewAnyData(), + redigomock.NewAnyData(), redigomock.NewAnyData(), + redigomock.NewAnyData()) repo := db.NewRedisImageRepo(pool) // setup image package @@ -176,5 +213,25 @@ func TestPostImage(t *testing.T) { } func TestGetImage(t *testing.T) { - + conn, imageHandler := prepareImage() + getImageResults := []string{"file_path", "imge/name.jpg", "created_at", "'feb 12'", "user_id", "111", "mime_type", "image/jpg", "title", "mine", "desc", "'hoo har'"} + conn.Command("HGETALL", "v1imagepost:fooo").ExpectSlice(getImageResults) + m := chi.NewRouter() + m.Get("/i/{fileName}", imageHandler.GetImage) + srv := httptest.NewServer(m) + defer srv.Close() + // TODO https://github.com/go-chi/chi/blob/39504566046f2c13f4d059bccfe0fe06ed67aab3/mux_test.go#L1662 + r, err := http.NewRequest("GET", fmt.Sprintf("%s/i/fooo", srv.URL), emptyBody) + if err != nil { + t.Errorf("%s", err) + } + resp, err := http.DefaultClient.Do(r) + if err != nil { + t.Errorf("%s", err) + } + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Errorf("%s", err) + } + fmt.Printf("hello: %s", body) } diff --git a/internal/image/model.go b/internal/image/model.go index 0d1cd60..a27d039 100644 --- a/internal/image/model.go +++ b/internal/image/model.go @@ -6,4 +6,6 @@ type PostMeta struct { CreatedAt string `redis:"created_at"` UserID string `redis:"user_id"` MimeType string `redis:"mime_type"` + Title string `redis:"title"` + Desc string `redis:"desc"` } diff --git a/internal/image/service.go b/internal/image/service.go index f953bfa..4ffd513 100644 --- a/internal/image/service.go +++ b/internal/image/service.go @@ -17,7 +17,7 @@ import ( // Servicer image management type Servicer interface { NewID() (string, error) - AddFile(extension, fileType string, fileBytes []byte) (string, string, error) + AddFile(extension string, meta *PostMeta, fileBytes []byte) (string, string, error) GetFile(fileUrl string) (*PostMeta, error) Render(w http.ResponseWriter, templateName string, data interface{}) error } @@ -48,7 +48,7 @@ func (is *Service) NewID() (string, error) { } // AddFile writes to disk, writes meta to db -func (is *Service) AddFile(extension, fileType string, fileBytes []byte) (string, string, error) { +func (is *Service) AddFile(extension string, postMeta *PostMeta, fileBytes []byte) (string, string, error) { fileID, err := is.NewID() if err != nil { return "", "", errors.Wrap(err, "generated id for fileID failed") @@ -64,12 +64,8 @@ func (is *Service) AddFile(extension, fileType string, fileBytes []byte) (string return "", "", errors.Wrap(err, "generating postid for uuid") } t := time.Now().UTC() - postMeta := &PostMeta{ - FilePath: fileName, - CreatedAt: t.Format(time.RFC3339), - UserID: "1", - MimeType: fileType, - } + postMeta.FilePath = fileName + postMeta.CreatedAt = t.Format(time.RFC3339) is.db.AddNewFile(postID, postMeta, 946080000) if err := is.db.AddNewFile(postID, postMeta, 946080000); err != nil { log.Fatal(err) @@ -81,5 +77,7 @@ func (is *Service) AddFile(extension, fileType string, fileBytes []byte) (string // GetFile fetch file from db interface func (is *Service) GetFile(fileUrl string) (*PostMeta, error) { result, err := is.db.GetFile(fileUrl) + if err != nil { + } return result, err } diff --git a/templates/pages/image.tmpl b/templates/pages/image.tmpl index 4c9b7b0..fcebdd5 100644 --- a/templates/pages/image.tmpl +++ b/templates/pages/image.tmpl @@ -1,11 +1,12 @@ {{ define "content" }}
-

Image

+

{{.ImageTitle }}

+ {{.ImageDesc}}
-- cgit v1.2.3