diff --git a/pkg/modules/avatar/gravatar/gravatar.go b/pkg/modules/avatar/gravatar/gravatar.go index 01144650b..c7b8d444b 100644 --- a/pkg/modules/avatar/gravatar/gravatar.go +++ b/pkg/modules/avatar/gravatar/gravatar.go @@ -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 } diff --git a/pkg/modules/avatar/initials/initials.go b/pkg/modules/avatar/initials/initials.go index 7a9632563..61b1a5caa 100644 --- a/pkg/modules/avatar/initials/initials.go +++ b/pkg/modules/avatar/initials/initials.go @@ -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 } diff --git a/pkg/modules/avatar/upload/upload.go b/pkg/modules/avatar/upload/upload.go index 2ab3ac16d..34349d4fb 100644 --- a/pkg/modules/avatar/upload/upload.go +++ b/pkg/modules/avatar/upload/upload.go @@ -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