Skip to content

Commit 0817515

Browse files
committed
feat: do not regenerate an existing random avatar
Leave aside the refactoring part of go-gitea/gitea#33433, keep the improvement. Also get a test from go-gitea/gitea#31365 while we're at it. (cherry picked from commit 4ffc54f59a7723eb5aef21955129bdd329ee1d4f)
1 parent 6f97d5d commit 0817515

File tree

2 files changed

+79
-7
lines changed

2 files changed

+79
-7
lines changed

models/user/avatar.go

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,18 @@ func GenerateRandomAvatar(ctx context.Context, u *User) error {
3838

3939
u.Avatar = avatars.HashEmail(seed)
4040

41-
// Don't share the images so that we can delete them easily
42-
if err := storage.SaveFrom(storage.Avatars, u.CustomAvatarRelativePath(), func(w io.Writer) error {
43-
if err := png.Encode(w, img); err != nil {
44-
log.Error("Encode: %v", err)
41+
_, err = storage.Avatars.Stat(u.CustomAvatarRelativePath())
42+
if err != nil {
43+
// If unable to Stat the avatar file (usually it means non-existing), then try to save a new one
44+
// Don't share the images so that we can delete them easily
45+
if err := storage.SaveFrom(storage.Avatars, u.CustomAvatarRelativePath(), func(w io.Writer) error {
46+
if err := png.Encode(w, img); err != nil {
47+
log.Error("Encode: %v", err)
48+
}
49+
return nil
50+
}); err != nil {
51+
return fmt.Errorf("failed to save avatar %s: %w", u.CustomAvatarRelativePath(), err)
4552
}
46-
return err
47-
}); err != nil {
48-
return fmt.Errorf("Failed to create dir %s: %w", u.CustomAvatarRelativePath(), err)
4953
}
5054

5155
if _, err := db.GetEngine(ctx).ID(u.ID).Cols("avatar").Update(u); err != nil {

models/user/avatar_test.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Copyright 2024 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package user
5+
6+
import (
7+
"context"
8+
"io"
9+
"strings"
10+
"testing"
11+
12+
"code.gitea.io/gitea/models/db"
13+
"code.gitea.io/gitea/models/unittest"
14+
"code.gitea.io/gitea/modules/setting"
15+
"code.gitea.io/gitea/modules/storage"
16+
"code.gitea.io/gitea/modules/test"
17+
18+
"github.com/stretchr/testify/assert"
19+
"github.com/stretchr/testify/require"
20+
)
21+
22+
func TestUserAvatarLink(t *testing.T) {
23+
defer test.MockVariableValue(&setting.AppURL, "https://localhost/")()
24+
defer test.MockVariableValue(&setting.AppSubURL, "")()
25+
26+
u := &User{ID: 1, Avatar: "avatar.png"}
27+
link := u.AvatarLink(db.DefaultContext)
28+
assert.Equal(t, "https://localhost/avatars/avatar.png", link)
29+
30+
setting.AppURL = "https://localhost/sub-path/"
31+
setting.AppSubURL = "/sub-path"
32+
link = u.AvatarLink(db.DefaultContext)
33+
assert.Equal(t, "https://localhost/sub-path/avatars/avatar.png", link)
34+
}
35+
36+
func TestUserAvatarGenerate(t *testing.T) {
37+
require.NoError(t, unittest.PrepareTestDatabase())
38+
var err error
39+
tmpDir := t.TempDir()
40+
storage.Avatars, err = storage.NewLocalStorage(context.Background(), &setting.Storage{Path: tmpDir})
41+
require.NoError(t, err)
42+
43+
u := unittest.AssertExistsAndLoadBean(t, &User{ID: 2})
44+
45+
// there was no avatar, generate a new one
46+
assert.Empty(t, u.Avatar)
47+
err = GenerateRandomAvatar(db.DefaultContext, u)
48+
require.NoError(t, err)
49+
assert.NotEmpty(t, u.Avatar)
50+
51+
// make sure the generated one exists
52+
oldAvatarPath := u.CustomAvatarRelativePath()
53+
_, err = storage.Avatars.Stat(u.CustomAvatarRelativePath())
54+
require.NoError(t, err)
55+
// and try to change its content
56+
_, err = storage.Avatars.Save(u.CustomAvatarRelativePath(), strings.NewReader("abcd"), 4)
57+
require.NoError(t, err)
58+
59+
// try to generate again
60+
err = GenerateRandomAvatar(db.DefaultContext, u)
61+
require.NoError(t, err)
62+
assert.Equal(t, oldAvatarPath, u.CustomAvatarRelativePath())
63+
f, err := storage.Avatars.Open(u.CustomAvatarRelativePath())
64+
require.NoError(t, err)
65+
defer f.Close()
66+
content, _ := io.ReadAll(f)
67+
assert.Equal(t, "abcd", string(content))
68+
}

0 commit comments

Comments
 (0)