Put timestamp in avatar filenames to avoid cache problems

This commit is contained in:
Ben Visness 2021-09-07 19:55:52 -05:00
parent f1e2e99663
commit 36bb2ce2d5
7 changed files with 102 additions and 10 deletions

View File

@ -42,6 +42,18 @@ var Config = HMNConfig{
AssetsPathPrefix: "", // Empty is fine for production, but may be necessary for dev AssetsPathPrefix: "", // Empty is fine for production, but may be necessary for dev
AssetsPublicUrlRoot: "", // e.g. "https://bucket-name.region.cdn.digitaloceanspaces.com/". Note the trailing slash... AssetsPublicUrlRoot: "", // e.g. "https://bucket-name.region.cdn.digitaloceanspaces.com/". Note the trailing slash...
}, },
Discord: DiscordConfig{
BotToken: "",
BotUserID: "",
OAuthClientID: "",
OAuthClientSecret: "",
GuildID: "",
MemberRoleID: "",
ShowcaseChannelID: "",
LibraryChannelID: "",
},
EpisodeGuide: EpisodeGuide{ EpisodeGuide: EpisodeGuide{
CineraOutputPath: "./annotations/", CineraOutputPath: "./annotations/",
Projects: map[string]string{"hero": "code", "riscy": "riscy", "bitwise": "bitwise"}, Projects: map[string]string{"hero": "code", "riscy": "riscy", "bitwise": "bitwise"},

View File

@ -167,7 +167,7 @@ func Scrape(ctx context.Context, dbConn *pgxpool.Pool, channelID string, earlies
return return
} }
err := handleHistoryMessage(ctx, dbConn, &msg, true) err := handleHistoryMessage(ctx, dbConn, &msg, createSnippets)
if err != nil { if err != nil {
errLog := logging.ExtractLogger(ctx).Error() errLog := logging.ExtractLogger(ctx).Error()
if errors.Is(err, errNotEnoughInfo) { if errors.Is(err, errNotEnoughInfo) {

View File

@ -0,0 +1,52 @@
package migrations
import (
"context"
"time"
"git.handmade.network/hmn/hmn/src/migration/types"
"git.handmade.network/hmn/hmn/src/oops"
"github.com/jackc/pgx/v4"
)
func init() {
registerMigration(ImageFileNotNull{})
}
type ImageFileNotNull struct{}
func (m ImageFileNotNull) Version() types.MigrationVersion {
return types.MigrationVersion(time.Date(2021, 9, 8, 0, 43, 57, 0, time.UTC))
}
func (m ImageFileNotNull) Name() string {
return "ImageFileNotNull"
}
func (m ImageFileNotNull) Description() string {
return "Don't allow the filename of an image file to be null"
}
func (m ImageFileNotNull) Up(ctx context.Context, tx pgx.Tx) error {
_, err := tx.Exec(ctx, `
ALTER TABLE handmade_imagefile
ALTER file SET NOT NULL;
`)
if err != nil {
return oops.New(err, "failed to make imagefile filename not nullable")
}
return nil
}
func (m ImageFileNotNull) Down(ctx context.Context, tx pgx.Tx) error {
_, err := tx.Exec(ctx, `
ALTER TABLE handmade_imagefile
ALTER file SET NULL;
`)
if err != nil {
return oops.New(err, "failed to make imagefile filename nullable again")
}
return nil
}

11
src/models/imagefile.go Normal file
View File

@ -0,0 +1,11 @@
package models
type ImageFile struct {
ID int `db:"id"`
File string `db:"file"` // relative to public/media
Size int `db:"size"`
Sha1Sum string `db:"sha1sum"`
Protected bool `db:"protected"`
Height int `db:"height"`
Width int `db:"width"`
}

View File

@ -11,11 +11,12 @@ import (
"os" "os"
"git.handmade.network/hmn/hmn/src/db" "git.handmade.network/hmn/hmn/src/db"
"git.handmade.network/hmn/hmn/src/models"
"git.handmade.network/hmn/hmn/src/oops" "git.handmade.network/hmn/hmn/src/oops"
) )
type SaveImageFileResult struct { type SaveImageFileResult struct {
ImageFileID int ImageFile *models.ImageFile
ValidationError string ValidationError string
FatalError error FatalError error
} }
@ -88,15 +89,15 @@ func SaveImageFile(c *RequestContext, dbConn db.ConnOrTx, fileFieldName string,
img.Seek(0, io.SeekStart) img.Seek(0, io.SeekStart)
io.Copy(hasher, img) // NOTE(asaf): Writing to hash.Hash never returns an error according to the docs io.Copy(hasher, img) // NOTE(asaf): Writing to hash.Hash never returns an error according to the docs
sha1sum := hasher.Sum(nil) sha1sum := hasher.Sum(nil)
var imageId int // TODO(db): Should use insert helper
err = dbConn.QueryRow(c.Context(), imageFile, err := db.QueryOne(c.Context(), dbConn, models.ImageFile{},
` `
INSERT INTO handmade_imagefile (file, size, sha1sum, protected, width, height) INSERT INTO handmade_imagefile (file, size, sha1sum, protected, width, height)
VALUES ($1, $2, $3, $4, $5, $6) VALUES ($1, $2, $3, $4, $5, $6)
RETURNING id RETURNING $columns
`, `,
filename, header.Size, hex.EncodeToString(sha1sum), false, width, height, filename, header.Size, hex.EncodeToString(sha1sum), false, width, height,
).Scan(&imageId) )
if err != nil { if err != nil {
return SaveImageFileResult{ return SaveImageFileResult{
FatalError: oops.New(err, "Failed to insert image file row"), FatalError: oops.New(err, "Failed to insert image file row"),
@ -104,7 +105,7 @@ func SaveImageFile(c *RequestContext, dbConn db.ConnOrTx, fileFieldName string,
} }
return SaveImageFileResult{ return SaveImageFileResult{
ImageFileID: imageId, ImageFile: imageFile.(*models.ImageFile),
} }
} }

View File

@ -156,7 +156,7 @@ func PodcastEditSubmit(c *RequestContext) ResponseData {
return c.ErrorResponse(http.StatusInternalServerError, oops.New(imageSaveResult.FatalError, "Failed to save podcast image")) return c.ErrorResponse(http.StatusInternalServerError, oops.New(imageSaveResult.FatalError, "Failed to save podcast image"))
} }
if imageSaveResult.ImageFileID != 0 { if imageSaveResult.ImageFile != nil {
_, err = tx.Exec(c.Context(), _, err = tx.Exec(c.Context(),
` `
UPDATE handmade_podcast UPDATE handmade_podcast
@ -168,7 +168,7 @@ func PodcastEditSubmit(c *RequestContext) ResponseData {
`, `,
title, title,
description, description,
imageSaveResult.ImageFileID, imageSaveResult.ImageFile.ID,
podcastResult.Podcast.ID, podcastResult.Podcast.ID,
) )
if err != nil { if err != nil {

View File

@ -6,6 +6,7 @@ import (
"net/http" "net/http"
"sort" "sort"
"strings" "strings"
"time"
"git.handmade.network/hmn/hmn/src/auth" "git.handmade.network/hmn/hmn/src/auth"
"git.handmade.network/hmn/hmn/src/config" "git.handmade.network/hmn/hmn/src/config"
@ -452,11 +453,26 @@ func UserSettingsSave(c *RequestContext) ResponseData {
} }
// Update avatar // Update avatar
imageSaveResult := SaveImageFile(c, tx, "avatar", 1*1024*1024, fmt.Sprintf("members/avatars/%s", c.CurrentUser.Username)) imageSaveResult := SaveImageFile(c, tx, "avatar", 1*1024*1024, fmt.Sprintf("members/avatars/%s-%d", c.CurrentUser.Username, time.Now().UTC().Unix()))
if imageSaveResult.ValidationError != "" { if imageSaveResult.ValidationError != "" {
return RejectRequest(c, imageSaveResult.ValidationError) return RejectRequest(c, imageSaveResult.ValidationError)
} else if imageSaveResult.FatalError != nil { } else if imageSaveResult.FatalError != nil {
return c.ErrorResponse(http.StatusInternalServerError, oops.New(imageSaveResult.FatalError, "failed to save new avatar")) return c.ErrorResponse(http.StatusInternalServerError, oops.New(imageSaveResult.FatalError, "failed to save new avatar"))
} else if imageSaveResult.ImageFile != nil {
_, err = tx.Exec(c.Context(),
`
UPDATE auth_user
SET
avatar = $2
WHERE
id = $1
`,
c.CurrentUser.ID,
imageSaveResult.ImageFile.File,
)
if err != nil {
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to update user"))
}
} }
err = tx.Commit(c.Context()) err = tx.Commit(c.Context())