From 48f39133d73eff4e39ec4eee36fa0dd8be424757 Mon Sep 17 00:00:00 2001 From: Leon Mika Date: Mon, 2 Mar 2026 22:26:40 +1100 Subject: [PATCH] Started working on the view upload page --- assets/js/controllers/upload.js | 1 + cmds/server.go | 2 + go.mod | 2 + go.sum | 6 ++ handlers/uploads.go | 67 ++++++++++++++++- models/uploads.go | 1 + providers/db/gen/sqlgen/models.go | 5 +- .../db/gen/sqlgen/pending_uploads.sql.go | 4 +- providers/db/gen/sqlgen/uploads.sql.go | 54 ++++++++++--- providers/db/uploads.go | 25 +++++-- providers/uploadfiles/exif.go | 32 ++++++++ providers/uploadfiles/provider.go | 19 +++-- services/uploads/manage.go | 75 +++++++++++++++++++ services/uploads/pending.go | 19 ++++- sql/queries/uploads.sql | 13 +++- sql/schema/02_upload.up.sql | 25 ++++--- views/uploads/index.html | 14 ++++ views/uploads/show.html | 8 ++ 18 files changed, 327 insertions(+), 45 deletions(-) create mode 100644 providers/uploadfiles/exif.go create mode 100644 services/uploads/manage.go create mode 100644 views/uploads/show.html diff --git a/assets/js/controllers/upload.js b/assets/js/controllers/upload.js index a810d41..e2953a3 100644 --- a/assets/js/controllers/upload.js +++ b/assets/js/controllers/upload.js @@ -33,6 +33,7 @@ export default class UploadController extends Controller { for (let file of files) { await this._doUpload(file); } + window.location.reload(); } async _doUpload(file) { diff --git a/cmds/server.go b/cmds/server.go index e12d265..92ac2ba 100644 --- a/cmds/server.go +++ b/cmds/server.go @@ -124,6 +124,8 @@ Starting weiro without any arguments will start the server. siteGroup.Delete("/posts/:postID", ph.Delete) siteGroup.Get("/uploads", uh.Index) + siteGroup.Get("/uploads/:uploadID", uh.Show) + siteGroup.Get("/uploads/:uploadID/raw", uh.ShowRaw) siteGroup.Post("/uploads/pending", uh.New) siteGroup.Post("/uploads/pending/:guid", uh.UploadPart) siteGroup.Post("/uploads/pending/:guid/finalize", uh.UploadComplete) diff --git a/go.mod b/go.mod index c6e73c1..2afe966 100644 --- a/go.mod +++ b/go.mod @@ -23,6 +23,7 @@ require ( github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/andybalholm/brotli v1.2.0 // indirect github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef // indirect + github.com/barasher/go-exiftool v1.10.0 // indirect github.com/cenkalti/backoff/v4 v4.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect @@ -80,6 +81,7 @@ require ( golang.org/x/sys v0.41.0 // indirect golang.org/x/text v0.34.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect + lmika.dev/pkg/modash v0.1.1-0.20260302110707-31c6b125c997 // indirect modernc.org/libc v1.67.6 // indirect modernc.org/mathutil v1.7.1 // indirect modernc.org/memory v1.11.0 // indirect diff --git a/go.sum b/go.sum index 6f783dd..7138969 100644 --- a/go.sum +++ b/go.sum @@ -57,6 +57,8 @@ github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:o github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef h1:46PFijGLmAjMPwCCCo7Jf0W6f9slllCkkv7vyc1yOSg= github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48= +github.com/barasher/go-exiftool v1.10.0 h1:f5JY5jc42M7tzR6tbL9508S2IXdIcG9QyieEXNMpIhs= +github.com/barasher/go-exiftool v1.10.0/go.mod h1:F9s/a3uHSM8YniVfwF+sbQUtP8Gmh9nyzigNF+8vsWo= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= @@ -731,6 +733,10 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= lmika.dev/pkg/litemigrate v0.1.0 h1:DBEJahbQO7W3uEmAOQGg1URBWYimg0ClWHi83M2MZwk= lmika.dev/pkg/litemigrate v0.1.0/go.mod h1:GQWWDiMZGQaVspcwKNq8vIBPN5H+KsUo/VBIeh9OfLg= +lmika.dev/pkg/modash v0.1.0 h1:fltroSvP0nKj9K0E6G+S9LULvB9Qhj47+SZ2b9v/v/c= +lmika.dev/pkg/modash v0.1.0/go.mod h1:8NDl/yR1eCCEhip9FJlVuMNXIeaztQ0Ks/tizExFcTI= +lmika.dev/pkg/modash v0.1.1-0.20260302110707-31c6b125c997 h1:XGdi5Ca5IJgGXPd057R2QHENQ6PwIUUfhBTGGF6yuLM= +lmika.dev/pkg/modash v0.1.1-0.20260302110707-31c6b125c997/go.mod h1:8NDl/yR1eCCEhip9FJlVuMNXIeaztQ0Ks/tizExFcTI= modernc.org/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis= modernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= modernc.org/ccgo/v4 v4.30.1 h1:4r4U1J6Fhj98NKfSjnPUN7Ze2c6MnAdL0hWw6+LrJpc= diff --git a/handlers/uploads.go b/handlers/uploads.go index 3d6e891..6b60313 100644 --- a/handlers/uploads.go +++ b/handlers/uploads.go @@ -1,8 +1,15 @@ package handlers import ( + "bufio" + "io" + "log" + "net/http" + "strconv" + "github.com/gofiber/fiber/v3" "lmika.dev/lmika/weiro/services/uploads" + "lmika.dev/pkg/modash/moslice" ) type UploadsHandler struct { @@ -10,7 +17,65 @@ type UploadsHandler struct { } func (uh UploadsHandler) Index(c fiber.Ctx) error { - return c.Render("uploads/index", nil) + uploads, err := uh.UploadsService.ListUploads(c.Context()) + if err != nil { + return err + } + + rows := moslice.Batch(uploads, 5) + + return c.Render("uploads/index", fiber.Map{"uploads": rows}) +} + +func (uh UploadsHandler) Show(c fiber.Ctx) error { + uploadIDStr := c.Params("uploadID") + if uploadIDStr == "" { + return fiber.ErrBadRequest + } + uploadID, err := strconv.ParseInt(uploadIDStr, 10, 64) + if err != nil { + return fiber.ErrBadRequest + } + + upload, err := uh.UploadsService.FetchUpload(c.Context(), uploadID) + if err != nil { + return err + } + + return c.Render("uploads/show", fiber.Map{"upload": upload}) +} + +func (uh UploadsHandler) ShowRaw(c fiber.Ctx) error { + uploadIDStr := c.Params("uploadID") + if uploadIDStr == "" { + return fiber.ErrBadRequest + } + uploadID, err := strconv.ParseInt(uploadIDStr, 10, 64) + if err != nil { + return fiber.ErrBadRequest + } + + upload, rwFn, err := uh.UploadsService.OpenUpload(c.Context(), uploadID) + if err != nil { + log.Print(err) + return err + } + + c.Set("Content-Type", upload.MIMEType) + c.Status(http.StatusOK) + return c.SendStreamWriter(func(w *bufio.Writer) { + rw, err := rwFn() + if err != nil { + return + } + defer rw.Close() + + _, err = io.Copy(w, rw) + if err != nil { + return + } + }) + } func (uh UploadsHandler) New(c fiber.Ctx) error { diff --git a/models/uploads.go b/models/uploads.go index 995de60..110f639 100644 --- a/models/uploads.go +++ b/models/uploads.go @@ -10,6 +10,7 @@ type Upload struct { MIMEType string `json:"mime_type"` Filename string `json:"filename"` CreatedAt time.Time `json:"created_at"` + Slug string `json:"slug"` Alt string `json:"alt"` } diff --git a/providers/db/gen/sqlgen/models.go b/providers/db/gen/sqlgen/models.go index 5b22452..1de5ce3 100644 --- a/providers/db/gen/sqlgen/models.go +++ b/providers/db/gen/sqlgen/models.go @@ -5,7 +5,7 @@ package sqlgen type PendingUpload struct { - ID interface{} + ID int64 SiteID int64 Guid string UserID int64 @@ -50,12 +50,13 @@ type Site struct { } type Upload struct { - ID interface{} + ID int64 SiteID int64 Guid string MimeType string Filename string FileSize int64 + Slug string Alt string CreatedAt int64 } diff --git a/providers/db/gen/sqlgen/pending_uploads.sql.go b/providers/db/gen/sqlgen/pending_uploads.sql.go index 96d8c3b..a831bbe 100644 --- a/providers/db/gen/sqlgen/pending_uploads.sql.go +++ b/providers/db/gen/sqlgen/pending_uploads.sql.go @@ -41,7 +41,7 @@ type InsertPendingUploadParams struct { UploadStartedAt int64 } -func (q *Queries) InsertPendingUpload(ctx context.Context, arg InsertPendingUploadParams) (interface{}, error) { +func (q *Queries) InsertPendingUpload(ctx context.Context, arg InsertPendingUploadParams) (int64, error) { row := q.db.QueryRowContext(ctx, insertPendingUpload, arg.SiteID, arg.Guid, @@ -51,7 +51,7 @@ func (q *Queries) InsertPendingUpload(ctx context.Context, arg InsertPendingUplo arg.MimeType, arg.UploadStartedAt, ) - var id interface{} + var id int64 err := row.Scan(&id) return id, err } diff --git a/providers/db/gen/sqlgen/uploads.sql.go b/providers/db/gen/sqlgen/uploads.sql.go index 6173374..0433ae9 100644 --- a/providers/db/gen/sqlgen/uploads.sql.go +++ b/providers/db/gen/sqlgen/uploads.sql.go @@ -13,7 +13,7 @@ const deleteUpload = `-- name: DeleteUpload :exec DELETE FROM uploads WHERE id = ? ` -func (q *Queries) DeleteUpload(ctx context.Context, id interface{}) error { +func (q *Queries) DeleteUpload(ctx context.Context, id int64) error { _, err := q.db.ExecContext(ctx, deleteUpload, id) return err } @@ -24,9 +24,11 @@ INSERT INTO uploads ( guid, mime_type, filename, - created_at, - alt -) VALUES (?, ?, ?, ?, ?, ?) + file_size, + slug, + alt, + created_at +) VALUES (?, ?, ?, ?, ?, ?, ?, ?) RETURNING id ` @@ -35,8 +37,10 @@ type InsertUploadParams struct { Guid string MimeType string Filename string - CreatedAt int64 + FileSize int64 + Slug string Alt string + CreatedAt int64 } func (q *Queries) InsertUpload(ctx context.Context, arg InsertUploadParams) error { @@ -45,17 +49,19 @@ func (q *Queries) InsertUpload(ctx context.Context, arg InsertUploadParams) erro arg.Guid, arg.MimeType, arg.Filename, - arg.CreatedAt, + arg.FileSize, + arg.Slug, arg.Alt, + arg.CreatedAt, ) return err } const selectUploadByID = `-- name: SelectUploadByID :one -SELECT id, site_id, guid, mime_type, filename, file_size, alt, created_at FROM uploads WHERE id = ? +SELECT id, site_id, guid, mime_type, filename, file_size, slug, alt, created_at FROM uploads WHERE id = ? LIMIT 1 ` -func (q *Queries) SelectUploadByID(ctx context.Context, id interface{}) (Upload, error) { +func (q *Queries) SelectUploadByID(ctx context.Context, id int64) (Upload, error) { row := q.db.QueryRowContext(ctx, selectUploadByID, id) var i Upload err := row.Scan( @@ -65,6 +71,33 @@ func (q *Queries) SelectUploadByID(ctx context.Context, id interface{}) (Upload, &i.MimeType, &i.Filename, &i.FileSize, + &i.Slug, + &i.Alt, + &i.CreatedAt, + ) + return i, err +} + +const selectUploadBySiteIDAndSlug = `-- name: SelectUploadBySiteIDAndSlug :one +SELECT id, site_id, guid, mime_type, filename, file_size, slug, alt, created_at FROM uploads WHERE site_id = ? AND slug = ? LIMIT 1 +` + +type SelectUploadBySiteIDAndSlugParams struct { + SiteID int64 + Slug string +} + +func (q *Queries) SelectUploadBySiteIDAndSlug(ctx context.Context, arg SelectUploadBySiteIDAndSlugParams) (Upload, error) { + row := q.db.QueryRowContext(ctx, selectUploadBySiteIDAndSlug, arg.SiteID, arg.Slug) + var i Upload + err := row.Scan( + &i.ID, + &i.SiteID, + &i.Guid, + &i.MimeType, + &i.Filename, + &i.FileSize, + &i.Slug, &i.Alt, &i.CreatedAt, ) @@ -72,7 +105,7 @@ func (q *Queries) SelectUploadByID(ctx context.Context, id interface{}) (Upload, } const selectUploadsOfSite = `-- name: SelectUploadsOfSite :many -SELECT id, site_id, guid, mime_type, filename, file_size, alt, created_at FROM uploads WHERE site_id = ? ORDER BY created_at DESC +SELECT id, site_id, guid, mime_type, filename, file_size, slug, alt, created_at FROM uploads WHERE site_id = ? ORDER BY created_at DESC ` func (q *Queries) SelectUploadsOfSite(ctx context.Context, siteID int64) ([]Upload, error) { @@ -91,6 +124,7 @@ func (q *Queries) SelectUploadsOfSite(ctx context.Context, siteID int64) ([]Uplo &i.MimeType, &i.Filename, &i.FileSize, + &i.Slug, &i.Alt, &i.CreatedAt, ); err != nil { @@ -113,7 +147,7 @@ UPDATE uploads SET alt = ? WHERE id = ? type UpdateUploadParams struct { Alt string - ID interface{} + ID int64 } func (q *Queries) UpdateUpload(ctx context.Context, arg UpdateUploadParams) error { diff --git a/providers/db/uploads.go b/providers/db/uploads.go index 2c7dc11..006b7cc 100644 --- a/providers/db/uploads.go +++ b/providers/db/uploads.go @@ -30,6 +30,18 @@ func (db *Provider) SelectUploadsOfSite(ctx context.Context, siteID int64) ([]mo return uploads, nil } +func (db *Provider) SelectUploadBySiteIDAndSlug(ctx context.Context, siteID int64, slug string) (models.Upload, error) { + row, err := db.queries.SelectUploadBySiteIDAndSlug(ctx, sqlgen.SelectUploadBySiteIDAndSlugParams{ + SiteID: siteID, + Slug: slug, + }) + if err != nil { + return models.Upload{}, err + } + + return dbUploadToUpload(row), nil +} + func (db *Provider) SaveUpload(ctx context.Context, upload *models.Upload) error { if upload.ID == 0 { if err := db.queries.InsertUpload(ctx, sqlgen.InsertUploadParams{ @@ -37,8 +49,10 @@ func (db *Provider) SaveUpload(ctx context.Context, upload *models.Upload) error Guid: upload.GUID, MimeType: upload.MIMEType, Filename: upload.Filename, - CreatedAt: upload.CreatedAt.Unix(), + FileSize: upload.FileSize, + Slug: upload.Slug, Alt: upload.Alt, + CreatedAt: upload.CreatedAt.Unix(), }); err != nil { return err } @@ -82,17 +96,14 @@ func (db *Provider) DeletePendingUpload(ctx context.Context, guid string) error } func dbUploadToUpload(row sqlgen.Upload) models.Upload { - var id int64 - if idVal, ok := row.ID.(int64); ok { - id = idVal - } - return models.Upload{ - ID: id, + ID: row.ID, SiteID: row.SiteID, GUID: row.Guid, MIMEType: row.MimeType, + FileSize: row.FileSize, Filename: row.Filename, + Slug: row.Slug, Alt: row.Alt, CreatedAt: time.Unix(row.CreatedAt, 0).UTC(), } diff --git a/providers/uploadfiles/exif.go b/providers/uploadfiles/exif.go new file mode 100644 index 0000000..a6f2ae7 --- /dev/null +++ b/providers/uploadfiles/exif.go @@ -0,0 +1,32 @@ +package uploadfiles + +import ( + "emperror.dev/errors" + "github.com/barasher/go-exiftool" + "lmika.dev/lmika/weiro/models" +) + +func (p *Provider) StripeEXIFData(site models.Site, up models.Upload) error { + uploadFilename := p.uploadFileName(site, up) + + et, err := exiftool.NewExiftool() + if err != nil { + return err + } + defer et.Close() + + fileInfos := et.ExtractMetadata(uploadFilename) + if len(fileInfos) == 0 { + return errors.New("no exif data found") + } + fileInfo := fileInfos[0] + fileInfo.ClearAll() + + fileOut := []exiftool.FileMetadata{fileInfo} + et.WriteMetadata(fileOut) + if fileOut[0].Err != nil { + return fileOut[0].Err + } + + return nil +} diff --git a/providers/uploadfiles/provider.go b/providers/uploadfiles/provider.go index ea9698d..bbc5d44 100644 --- a/providers/uploadfiles/provider.go +++ b/providers/uploadfiles/provider.go @@ -1,7 +1,7 @@ package uploadfiles import ( - "fmt" + "io" "os" "path/filepath" @@ -19,17 +19,24 @@ func New(baseDir string) *Provider { } func (p *Provider) AdoptFile(site models.Site, up models.Upload, filename string) error { - baseDir := filepath.Join(p.baseDir, site.GUID, - fmt.Sprintf("%04d", up.CreatedAt.Year()), - fmt.Sprintf("%02d", up.CreatedAt.Month())) + fullPath := p.uploadFileName(site, up) + baseDir := filepath.Dir(fullPath) if err := os.MkdirAll(baseDir, 0755); err != nil { return err } - targetFilename := filepath.Join(baseDir, up.GUID) - if err := os.Rename(filename, targetFilename); err != nil { + if err := os.Rename(filename, fullPath); err != nil { return err } return nil } + +func (p *Provider) OpenUpload(site models.Site, up models.Upload) (io.ReadCloser, error) { + fullPath := p.uploadFileName(site, up) + return os.Open(fullPath) +} + +func (p *Provider) uploadFileName(site models.Site, up models.Upload) string { + return filepath.Join(p.baseDir, site.GUID, up.Slug) +} diff --git a/services/uploads/manage.go b/services/uploads/manage.go new file mode 100644 index 0000000..3bfe4e7 --- /dev/null +++ b/services/uploads/manage.go @@ -0,0 +1,75 @@ +package uploads + +import ( + "context" + "fmt" + "io" + + "lmika.dev/lmika/weiro/models" +) + +type UploadWithURL struct { + Upload models.Upload + URL string +} + +func (s *Service) FetchUpload(ctx context.Context, uploadID int64) (res UploadWithURL, _ error) { + site, _, err := s.fetchSiteAndUser(ctx) + if err != nil { + return UploadWithURL{}, err + } + + upload, err := s.db.SelectUploadByID(ctx, uploadID) + if err != nil { + return UploadWithURL{}, err + } + + return UploadWithURL{ + Upload: upload, + URL: fmt.Sprintf("/sites/%v/uploads/%v/raw", site.ID, upload.ID), + }, nil +} + +func (s *Service) ListUploads(ctx context.Context) (res []UploadWithURL, _ error) { + site, _, err := s.fetchSiteAndUser(ctx) + if err != nil { + return nil, err + } + + uploads, err := s.db.SelectUploadsOfSite(ctx, site.ID) + if err != nil { + return nil, err + } + + res = make([]UploadWithURL, len(uploads)) + for i, upload := range uploads { + res[i] = UploadWithURL{ + Upload: upload, + URL: fmt.Sprintf("/sites/%v/uploads/%v/raw", site.ID, upload.ID), + } + } + + return res, nil +} + +func (s *Service) OpenUpload(ctx context.Context, id int64) (models.Upload, func() (io.ReadCloser, error), error) { + site, _, err := s.fetchSiteAndUser(ctx) + if err != nil { + return models.Upload{}, nil, err + } + + upload, err := s.db.SelectUploadByID(ctx, id) + if err != nil { + return models.Upload{}, nil, err + } else if upload.SiteID != site.ID { + return models.Upload{}, nil, models.NotFoundError + } + + return upload, func() (io.ReadCloser, error) { + rw, err := s.up.OpenUpload(site, upload) + if err != nil { + return nil, err + } + return rw, nil + }, nil +} diff --git a/services/uploads/pending.go b/services/uploads/pending.go index 1745610..0e281c3 100644 --- a/services/uploads/pending.go +++ b/services/uploads/pending.go @@ -5,7 +5,9 @@ import ( "context" "crypto/sha256" "encoding/hex" + "fmt" "io" + "log" "os" "path/filepath" "time" @@ -100,13 +102,22 @@ func (s *Service) FinalizePending(ctx context.Context, pendingGUID string, expec return err } + newUploadGUID := models.NewNanoID() + newTime := time.Now().UTC() + newSlug := filepath.Join( + fmt.Sprintf("%04d", newTime.Year()), + fmt.Sprintf("%02d", newTime.Month()), + newUploadGUID+filepath.Ext(pu.Filename), + ) + newUpload := models.Upload{ SiteID: site.ID, GUID: models.NewNanoID(), FileSize: pu.FileSize, MIMEType: pu.MIMEType, Filename: pu.Filename, - CreatedAt: time.Now().UTC(), + CreatedAt: newTime, + Slug: newSlug, } if err := s.db.SaveUpload(ctx, &newUpload); err != nil { return err @@ -115,6 +126,12 @@ func (s *Service) FinalizePending(ctx context.Context, pendingGUID string, expec if err := s.up.AdoptFile(site, newUpload, pendingDataFilename); err != nil { return err } + if err := s.db.DeletePendingUpload(ctx, newUpload.GUID); err != nil { + return err + } + if err := s.up.StripeEXIFData(site, newUpload); err != nil { + log.Printf("warn: failed to extract exif data from %s: %v\n", newUpload.Slug, err) + } return nil } diff --git a/sql/queries/uploads.sql b/sql/queries/uploads.sql index 2c37525..fc8b82d 100644 --- a/sql/queries/uploads.sql +++ b/sql/queries/uploads.sql @@ -2,7 +2,10 @@ SELECT * FROM uploads WHERE site_id = ? ORDER BY created_at DESC; -- name: SelectUploadByID :one -SELECT * FROM uploads WHERE id = ?; +SELECT * FROM uploads WHERE id = ? LIMIT 1; + +-- name: SelectUploadBySiteIDAndSlug :one +SELECT * FROM uploads WHERE site_id = ? AND slug = ? LIMIT 1; -- name: InsertUpload :exec INSERT INTO uploads ( @@ -10,9 +13,11 @@ INSERT INTO uploads ( guid, mime_type, filename, - created_at, - alt -) VALUES (?, ?, ?, ?, ?, ?) + file_size, + slug, + alt, + created_at +) VALUES (?, ?, ?, ?, ?, ?, ?, ?) RETURNING id; -- name: UpdateUpload :exec diff --git a/sql/schema/02_upload.up.sql b/sql/schema/02_upload.up.sql index f87d92b..b0bba74 100644 --- a/sql/schema/02_upload.up.sql +++ b/sql/schema/02_upload.up.sql @@ -1,27 +1,28 @@ CREATE TABLE uploads ( - id SERIAL PRIMARY KEY, + id INTEGER PRIMARY KEY AUTOINCREMENT, site_id INT NOT NULL, guid TEXT NOT NULL, mime_type TEXT NOT NULL, filename TEXT NOT NULL, - file_size INT NOT NULL, + file_size INT NOT NULL, + slug TEXT NOT NULL, alt TEXT NOT NULL, created_at INT NOT NULL, - FOREIGN KEY (site_id) REFERENCES sites (id) ON DELETE CASCADE ); CREATE INDEX idx_uploads_site ON uploads (site_id); -CREATE UNIQUE INDEX idx_uploads_guid ON sites (guid); +CREATE UNIQUE INDEX idx_uploads_guid ON uploads (guid); +CREATE UNIQUE INDEX idx_uploads_site_slug ON uploads (site_id, slug); CREATE TABLE pending_uploads ( - id SERIAL PRIMARY KEY, - site_id INT NOT NULL, - guid TEXT NOT NULL, - user_id INT NOT NULL, - filename TEXT NOT NULL, - file_size INT NOT NULL, - mime_type TEXT NOT NULL, - upload_started_at INT NOT NULL, + id INTEGER PRIMARY KEY AUTOINCREMENT, + site_id INT NOT NULL, + guid TEXT NOT NULL, + user_id INT NOT NULL, + filename TEXT NOT NULL, + file_size INT NOT NULL, + mime_type TEXT NOT NULL, + upload_started_at INT NOT NULL, FOREIGN KEY (site_id) REFERENCES sites (id) ON DELETE CASCADE, FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE ); diff --git a/views/uploads/index.html b/views/uploads/index.html index 4bc9627..a510c99 100644 --- a/views/uploads/index.html +++ b/views/uploads/index.html @@ -3,4 +3,18 @@ data-controller="upload" data-upload-site-id-value="{{ .site.ID }}"> + + {{ range .uploads }} +
+ {{ range . }} + + {{ end }} +
+ {{ end }} \ No newline at end of file diff --git a/views/uploads/show.html b/views/uploads/show.html new file mode 100644 index 0000000..979b11e --- /dev/null +++ b/views/uploads/show.html @@ -0,0 +1,8 @@ +
+
+ +
+ + {{ .Upload.Alt }} +
\ No newline at end of file