feat(ui): show size constraints of custom avatar (#7998)

Closes #7862
This adds a note for the user profile settings page about the avatar constraints.

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/7998
Reviewed-by: 0ko <0ko@noreply.codeberg.org>
Co-authored-by: Thomas Böhler <witcher@wiredspace.de>
Co-committed-by: Thomas Böhler <witcher@wiredspace.de>
This commit is contained in:
Thomas Böhler 2025-06-14 16:35:50 +02:00 committed by 0ko
parent 6cdf2cd66e
commit 53d5e6d754
10 changed files with 65 additions and 0 deletions

View file

@ -94,5 +94,6 @@
"editor.textarea.shift_tab_hint": "No indentation on this line. Press <kbd>Shift</kbd> + <kbd>Tab</kbd> again or <kbd>Escape</kbd> to leave the editor.",
"admin.dashboard.cleanup_offline_runners": "Cleanup offline runners",
"settings.visibility.description": "Profile visibility affects others' ability to access your non-private repositories. <a href=\"%s\" target=\"_blank\">Learn more</a>",
"avatar.constraints_hint": "Custom avatar may not exceed %[1]s in size or be larger than %[2]dx%[3]d pixels",
"meta.last_line": "Thank you for translating Forgejo! This line isn't seen by the users but it serves other purposes in the translation management. You can place a fun fact in the translation instead of translating it."
}

View file

@ -313,6 +313,9 @@ func editUserCommon(ctx *context.Context) {
ctx.Data["DisableMigrations"] = setting.Repository.DisableMigrations
ctx.Data["AllowedUserVisibilityModes"] = setting.Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice()
ctx.Data["DisableGravatar"] = setting.Config().Picture.DisableGravatar.Value(ctx)
ctx.Data["MaxAvatarFileSize"] = setting.Avatar.MaxFileSize
ctx.Data["MaxAvatarWidth"] = setting.Avatar.MaxWidth
ctx.Data["MaxAvatarHeight"] = setting.Avatar.MaxHeight
}
// EditUser show editing user page

View file

@ -50,6 +50,9 @@ func Settings(ctx *context.Context) {
ctx.Data["RepoAdminChangeTeamAccess"] = ctx.Org.Organization.RepoAdminChangeTeamAccess
ctx.Data["ContextUser"] = ctx.ContextUser
ctx.Data["CooldownPeriod"] = setting.Service.UsernameCooldownPeriod
ctx.Data["MaxAvatarFileSize"] = setting.Avatar.MaxFileSize
ctx.Data["MaxAvatarWidth"] = setting.Avatar.MaxWidth
ctx.Data["MaxAvatarHeight"] = setting.Avatar.MaxHeight
err := shared_user.LoadHeaderCount(ctx)
if err != nil {

View file

@ -64,6 +64,9 @@ func SettingsCtxData(ctx *context.Context) {
ctx.Data["DisableNewPushMirrors"] = setting.Mirror.DisableNewPush
ctx.Data["DefaultMirrorInterval"] = setting.Mirror.DefaultInterval
ctx.Data["MinimumMirrorInterval"] = setting.Mirror.MinInterval
ctx.Data["MaxAvatarFileSize"] = setting.Avatar.MaxFileSize
ctx.Data["MaxAvatarWidth"] = setting.Avatar.MaxWidth
ctx.Data["MaxAvatarHeight"] = setting.Avatar.MaxHeight
signing, _ := asymkey_service.SigningKey(ctx, ctx.Repo.Repository.RepoPath())
ctx.Data["SigningKeyAvailable"] = len(signing) > 0

View file

@ -51,6 +51,9 @@ func Profile(ctx *context.Context) {
ctx.Data["DisableGravatar"] = setting.Config().Picture.DisableGravatar.Value(ctx)
ctx.Data["CooldownPeriod"] = setting.Service.UsernameCooldownPeriod
ctx.Data["CommonPronouns"] = commonPronouns
ctx.Data["MaxAvatarFileSize"] = setting.Avatar.MaxFileSize
ctx.Data["MaxAvatarWidth"] = setting.Avatar.MaxWidth
ctx.Data["MaxAvatarHeight"] = setting.Avatar.MaxHeight
ctx.HTML(http.StatusOK, tplSettingsProfile)
}

View file

@ -208,6 +208,7 @@
<div class="inline field tw-pl-4">
<label for="avatar">{{ctx.Locale.Tr "settings.choose_new_avatar"}}</label>
<input name="avatar" type="file" accept="image/png,image/jpeg,image/gif,image/webp">
<br/><span class=help>{{ctx.Locale.Tr "avatar.constraints_hint" (ctx.Locale.TrSize .MaxAvatarFileSize) .MaxAvatarWidth .MaxAvatarHeight}}</span>
</div>
<div class="field">

View file

@ -94,6 +94,7 @@
<div class="inline field">
<label for="avatar">{{ctx.Locale.Tr "settings.choose_new_avatar"}}</label>
<input name="avatar" type="file" accept="image/png,image/jpeg,image/gif,image/webp">
<br/><span class=help>{{ctx.Locale.Tr "avatar.constraints_hint" (ctx.Locale.TrSize .MaxAvatarFileSize) .MaxAvatarWidth .MaxAvatarHeight}}</span>
</div>
<div class="field">

View file

@ -56,6 +56,7 @@
<div class="inline field">
<label for="avatar">{{ctx.Locale.Tr "settings.choose_new_avatar"}}</label>
<input name="avatar" type="file" accept="image/png,image/jpeg,image/gif,image/webp">
<br/><span class=help>{{ctx.Locale.Tr "avatar.constraints_hint" (ctx.Locale.TrSize .MaxAvatarFileSize) .MaxAvatarWidth .MaxAvatarHeight}}</span>
</div>
<div class="field">
<button class="ui primary button">{{ctx.Locale.Tr "settings.update_avatar"}}</button>

View file

@ -138,6 +138,7 @@
<div class="inline field tw-pl-4">
<label for="new-avatar">{{ctx.Locale.Tr "settings.choose_new_avatar"}}</label>
<input id="new-avatar" name="avatar" type="file" accept="image/png,image/jpeg,image/gif,image/webp">
<br/><span class=help>{{ctx.Locale.Tr "avatar.constraints_hint" (ctx.Locale.TrSize .MaxAvatarFileSize) .MaxAvatarWidth .MaxAvatarHeight}}</span>
</div>
<div class="field">

View file

@ -155,3 +155,51 @@ func TestSettingSecurityAuthSource(t *testing.T) {
assert.Contains(t, resp.Body.String(), `gitlab-active`)
assert.Contains(t, resp.Body.String(), `gitlab-inactive`)
}
func TestUserAvatarSizeNotice(t *testing.T) {
defer tests.PrepareTestEnv(t)()
session := loginUser(t, "user1")
req := NewRequest(t, "GET", "/user/settings")
resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
assert.Contains(t,
htmlDoc.doc.Find("form div:has(input#new-avatar) .help").Text(),
"Custom avatar may not exceed 1 MiB in size or be larger than 4096x4096 pixels")
}
func TestRepoAvatarSizeNotice(t *testing.T) {
defer tests.PrepareTestEnv(t)()
session := loginUser(t, "user2")
req := NewRequest(t, "GET", "/user2/repo1/settings")
resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
assert.Contains(t,
htmlDoc.doc.Find("form div:has(input[name=\"avatar\"]) .help").Text(),
"Custom avatar may not exceed 1 MiB in size or be larger than 4096x4096 pixels")
}
func TestOrgAvatarSizeNotice(t *testing.T) {
defer tests.PrepareTestEnv(t)()
session := loginUser(t, "user2")
req := NewRequest(t, "GET", "/org/org3/settings")
resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
assert.Contains(t,
htmlDoc.doc.Find("form div:has(input[name=\"avatar\"]) .help").Text(),
"Custom avatar may not exceed 1 MiB in size or be larger than 4096x4096 pixels")
}
func TestAdminAvatarSizeNotice(t *testing.T) {
defer tests.PrepareTestEnv(t)()
session := loginUser(t, "user1")
req := NewRequest(t, "GET", "/admin/users/2/edit")
resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
assert.Contains(t,
htmlDoc.doc.Find("form div:has(input[name=\"avatar\"]) .help").Text(),
"Custom avatar may not exceed 1 MiB in size or be larger than 4096x4096 pixels")
}