fix(avatars): always return correct mime type for cached avatar

This commit is contained in:
kolaente 2025-03-02 13:33:40 +01:00
parent 2ead48c1e9
commit 734033c843
No known key found for this signature in database
GPG Key ID: F40E70337AB24C9B
3 changed files with 65 additions and 28 deletions

View File

@ -32,6 +32,7 @@ import (
type avatar struct {
content []byte
mimeType string
loadedAt time.Time
}
@ -78,10 +79,18 @@ func (g *Provider) GetAvatar(user *user.User, size int64) ([]byte, string, error
if err != nil {
return nil, "", err
}
// Determine the mime type from the response
mimeType := "image/jpeg"
if contentType := resp.Header.Get("Content-Type"); contentType != "" {
mimeType = contentType
}
avatars[cacheKey] = &avatar{
content: avatarContent,
mimeType: mimeType,
loadedAt: time.Now(),
}
}
return avatars[cacheKey].content, "image/jpg", nil
return avatars[cacheKey].content, avatars[cacheKey].mimeType, nil
}

View File

@ -151,36 +151,51 @@ func getAvatarForUser(u *user.User) (fullSizeAvatar *image.RGBA64, err error) {
return fullSizeAvatar, nil
}
// CachedAvatar represents a cached avatar with its content and mime type
type CachedAvatar struct {
Content []byte
MimeType string
}
// GetAvatar returns an initials avatar for a user
func (p *Provider) GetAvatar(u *user.User, size int64) (avatar []byte, mimeType string, err error) {
cacheKey := getCacheKey("resized", u.ID, size)
exists, err := keyvalue.GetWithValue(cacheKey, &avatar)
var cachedAvatar CachedAvatar
exists, err := keyvalue.GetWithValue(cacheKey, &cachedAvatar)
if err != nil {
return nil, "", err
}
if !exists {
log.Debugf("Initials avatar for user %d and size %d not cached, creating...", u.ID, size)
fullAvatar, err := getAvatarForUser(u)
if err != nil {
return nil, "", err
}
img := imaging.Resize(fullAvatar, int(size), int(size), imaging.Lanczos)
buf := &bytes.Buffer{}
err = png.Encode(buf, img)
if err != nil {
return nil, "", err
}
avatar = buf.Bytes()
err = keyvalue.Put(cacheKey, avatar)
if err != nil {
return nil, "", err
}
} else {
if exists && len(cachedAvatar.Content) > 0 {
log.Debugf("Serving initials avatar for user %d and size %d from cache", u.ID, size)
return cachedAvatar.Content, cachedAvatar.MimeType, nil
}
return avatar, "image/png", nil
log.Debugf("Initials avatar for user %d and size %d not cached, creating...", u.ID, size)
fullAvatar, err := getAvatarForUser(u)
if err != nil {
return nil, "", err
}
img := imaging.Resize(fullAvatar, int(size), int(size), imaging.Lanczos)
buf := &bytes.Buffer{}
err = png.Encode(buf, img)
if err != nil {
return nil, "", err
}
avatar = buf.Bytes()
mimeType = "image/png"
cachedAvatar = CachedAvatar{
Content: avatar,
MimeType: mimeType,
}
err = keyvalue.Put(cacheKey, cachedAvatar)
if err != nil {
return nil, "", err
}
return avatar, mimeType, nil
}

View File

@ -35,12 +35,18 @@ import (
type Provider struct {
}
// CachedAvatar represents a cached avatar with its content and mime type
type CachedAvatar struct {
Content []byte
MimeType string
}
// GetAvatar returns an uploaded user avatar
func (p *Provider) GetAvatar(u *user.User, size int64) (avatar []byte, mimeType string, err error) {
cacheKey := "avatar_upload_" + strconv.Itoa(int(u.ID))
var cached map[int64][]byte
var cached map[int64]*CachedAvatar
exists, err := keyvalue.GetWithValue(cacheKey, &cached)
if err != nil {
return nil, "", err
@ -48,16 +54,16 @@ func (p *Provider) GetAvatar(u *user.User, size int64) (avatar []byte, mimeType
if !exists {
// Nothing ever cached for this user so we need to create the size map to avoid panics
cached = make(map[int64][]byte)
cached = make(map[int64]*CachedAvatar)
} else {
a := cached
if a != nil && a[size] != nil {
log.Debugf("Serving uploaded avatar for user %d and size %d from cache.", u.ID, size)
return a[size], "", nil
return a[size].Content, a[size].MimeType, nil
}
// This means we have a map for the user, but nothing in it.
if a == nil {
cached = make(map[int64][]byte)
cached = make(map[int64]*CachedAvatar)
}
}
@ -87,9 +93,16 @@ func (p *Provider) GetAvatar(u *user.User, size int64) (avatar []byte, mimeType
if err != nil {
return nil, "", err
}
cached[size] = avatar
// Always use image/png for resized avatars since we're encoding with png
mimeType = "image/png"
cached[size] = &CachedAvatar{
Content: avatar,
MimeType: mimeType,
}
err = keyvalue.Put(cacheKey, cached)
return avatar, f.Mime, err
return avatar, mimeType, err
}
// InvalidateCache invalidates the avatar cache for a user