Skip to content

Commit

Permalink
Add arbitrary meta field to media. Closes #938.
Browse files Browse the repository at this point in the history
- Add new `meta` JSONB field to `media` table.
- Start storing image width and height as meta with media uploads.
  • Loading branch information
knadh committed Oct 2, 2022
1 parent c3d04a5 commit c381004
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 19 deletions.
24 changes: 16 additions & 8 deletions cmd/media.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"strconv"

"github.com/disintegration/imaging"
"github.com/knadh/listmonk/models"
"github.com/labstack/echo/v4"
)

Expand Down Expand Up @@ -78,7 +79,7 @@ func handleUploadMedia(c echo.Context) error {
}()

// Create thumbnail from file.
thumbFile, err := createThumbnail(file)
thumbFile, width, height, err := processImage(file)
if err != nil {
cleanUp = true
app.log.Printf("error resizing image: %v", err)
Expand All @@ -96,7 +97,11 @@ func handleUploadMedia(c echo.Context) error {
}

// Write to the DB.
m, err := app.core.InsertMedia(fName, thumbfName, app.constants.MediaProvider, app.media)
meta := models.JSON{
"width": width,
"height": height,
}
m, err := app.core.InsertMedia(fName, thumbfName, meta, app.constants.MediaProvider, app.media)
if err != nil {
cleanUp = true
return err
Expand Down Expand Up @@ -150,17 +155,18 @@ func handleDeleteMedia(c echo.Context) error {
return c.JSON(http.StatusOK, okResp{true})
}

// createThumbnail reads the file object and returns a smaller image
func createThumbnail(file *multipart.FileHeader) (*bytes.Reader, error) {
// processImage reads the image file and returns thumbnail bytes and
// the original image's width, and height.
func processImage(file *multipart.FileHeader) (*bytes.Reader, int, int, error) {
src, err := file.Open()
if err != nil {
return nil, err
return nil, 0, 0, err
}
defer src.Close()

img, err := imaging.Decode(src)
if err != nil {
return nil, err
return nil, 0, 0, err
}

// Encode the image into a byte slice as PNG.
Expand All @@ -169,7 +175,9 @@ func createThumbnail(file *multipart.FileHeader) (*bytes.Reader, error) {
out bytes.Buffer
)
if err := imaging.Encode(&out, thumb, imaging.PNG); err != nil {
return nil, err
return nil, 0, 0, err
}
return bytes.NewReader(out.Bytes()), nil

b := img.Bounds().Max
return bytes.NewReader(out.Bytes()), b.X, b.Y, nil
}
1 change: 1 addition & 0 deletions cmd/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ var migList = []migFunc{
{"v2.0.0", migrations.V2_0_0},
{"v2.1.0", migrations.V2_1_0},
{"v2.2.0", migrations.V2_2_0},
{"v2.3.0", migrations.V2_3_0},
}

// upgrade upgrades the database to the current version by running SQL migration files
Expand Down
5 changes: 3 additions & 2 deletions internal/core/media.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/gofrs/uuid"
"github.com/knadh/listmonk/internal/media"
"github.com/knadh/listmonk/models"
"github.com/labstack/echo/v4"
)

Expand Down Expand Up @@ -45,7 +46,7 @@ func (c *Core) GetMedia(id int, uuid string, s media.Store) (media.Media, error)
}

// InsertMedia inserts a new media file into the DB.
func (c *Core) InsertMedia(fileName, thumbName string, provider string, s media.Store) (media.Media, error) {
func (c *Core) InsertMedia(fileName, thumbName string, meta models.JSON, provider string, s media.Store) (media.Media, error) {
uu, err := uuid.NewV4()
if err != nil {
c.log.Printf("error generating UUID: %v", err)
Expand All @@ -55,7 +56,7 @@ func (c *Core) InsertMedia(fileName, thumbName string, provider string, s media.

// Write to the DB.
var newID int
if err := c.q.InsertMedia.Get(&newID, uu, fileName, thumbName, provider); err != nil {
if err := c.q.InsertMedia.Get(&newID, uu, fileName, thumbName, provider, meta); err != nil {
c.log.Printf("error inserting uploaded file to db: %v", err)
return media.Media{}, echo.NewHTTPError(http.StatusInternalServerError,
c.i18n.Ts("globals.messages.errorCreating", "name", "{globals.terms.media}", "error", pqErrMsg(err)))
Expand Down
18 changes: 10 additions & 8 deletions internal/media/media.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,21 @@ package media
import (
"io"

"github.com/knadh/listmonk/models"
"gopkg.in/volatiletech/null.v6"
)

// Media represents an uploaded object.
type Media struct {
ID int `db:"id" json:"id"`
UUID string `db:"uuid" json:"uuid"`
Filename string `db:"filename" json:"filename"`
Thumb string `db:"thumb" json:"thumb"`
CreatedAt null.Time `db:"created_at" json:"created_at"`
ThumbURL string `json:"thumb_url"`
Provider string `json:"provider"`
URL string `json:"url"`
ID int `db:"id" json:"id"`
UUID string `db:"uuid" json:"uuid"`
Filename string `db:"filename" json:"filename"`
Thumb string `db:"thumb" json:"thumb"`
CreatedAt null.Time `db:"created_at" json:"created_at"`
ThumbURL string `json:"thumb_url"`
Provider string `json:"provider"`
Meta models.JSON `db:"meta" json:"meta"`
URL string `json:"url"`
}

// Store represents functions to store and retrieve media (files).
Expand Down
16 changes: 16 additions & 0 deletions internal/migrations/v2.3.0.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package migrations

import (
"github.com/jmoiron/sqlx"
"github.com/knadh/koanf"
"github.com/knadh/stuffbin"
)

// V2_2_0 performs the DB migrations for v.2.2.0.
func V2_3_0(db *sqlx.DB, fs stuffbin.FileSystem, ko *koanf.Koanf) error {
if _, err := db.Exec(`ALTER TABLE media ADD COLUMN IF NOT EXISTS "meta" JSONB NOT NULL DEFAULT '{}'`); err != nil {
return err
}

return nil
}
2 changes: 1 addition & 1 deletion queries.sql
Original file line number Diff line number Diff line change
Expand Up @@ -811,7 +811,7 @@ SELECT id FROM tpl;

-- media
-- name: insert-media
INSERT INTO media (uuid, filename, thumb, provider, created_at) VALUES($1, $2, $3, $4, NOW()) RETURNING id;
INSERT INTO media (uuid, filename, thumb, provider, meta, created_at) VALUES($1, $2, $3, $4, $5, NOW()) RETURNING id;

-- name: get-all-media
SELECT * FROM media WHERE provider=$1 ORDER BY created_at DESC;
Expand Down
1 change: 1 addition & 0 deletions schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ CREATE TABLE media (
provider TEXT NOT NULL DEFAULT '',
filename TEXT NOT NULL,
thumb TEXT NOT NULL,
meta JSONB NOT NULL DEFAULT '{}',
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

Expand Down

0 comments on commit c381004

Please sign in to comment.