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:
		
					parent
					
						
							
								6cdf2cd66e
							
						
					
				
			
			
				commit
				
					
						53d5e6d754
					
				
			
		
					 10 changed files with 65 additions and 0 deletions
				
			
		|  | @ -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.", |     "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", |     "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>", |     "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." |     "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." | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -313,6 +313,9 @@ func editUserCommon(ctx *context.Context) { | ||||||
| 	ctx.Data["DisableMigrations"] = setting.Repository.DisableMigrations | 	ctx.Data["DisableMigrations"] = setting.Repository.DisableMigrations | ||||||
| 	ctx.Data["AllowedUserVisibilityModes"] = setting.Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice() | 	ctx.Data["AllowedUserVisibilityModes"] = setting.Service.AllowedUserVisibilityModesSlice.ToVisibleTypeSlice() | ||||||
| 	ctx.Data["DisableGravatar"] = setting.Config().Picture.DisableGravatar.Value(ctx) | 	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 | // EditUser show editing user page | ||||||
|  |  | ||||||
|  | @ -50,6 +50,9 @@ func Settings(ctx *context.Context) { | ||||||
| 	ctx.Data["RepoAdminChangeTeamAccess"] = ctx.Org.Organization.RepoAdminChangeTeamAccess | 	ctx.Data["RepoAdminChangeTeamAccess"] = ctx.Org.Organization.RepoAdminChangeTeamAccess | ||||||
| 	ctx.Data["ContextUser"] = ctx.ContextUser | 	ctx.Data["ContextUser"] = ctx.ContextUser | ||||||
| 	ctx.Data["CooldownPeriod"] = setting.Service.UsernameCooldownPeriod | 	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) | 	err := shared_user.LoadHeaderCount(ctx) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  |  | ||||||
|  | @ -64,6 +64,9 @@ func SettingsCtxData(ctx *context.Context) { | ||||||
| 	ctx.Data["DisableNewPushMirrors"] = setting.Mirror.DisableNewPush | 	ctx.Data["DisableNewPushMirrors"] = setting.Mirror.DisableNewPush | ||||||
| 	ctx.Data["DefaultMirrorInterval"] = setting.Mirror.DefaultInterval | 	ctx.Data["DefaultMirrorInterval"] = setting.Mirror.DefaultInterval | ||||||
| 	ctx.Data["MinimumMirrorInterval"] = setting.Mirror.MinInterval | 	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()) | 	signing, _ := asymkey_service.SigningKey(ctx, ctx.Repo.Repository.RepoPath()) | ||||||
| 	ctx.Data["SigningKeyAvailable"] = len(signing) > 0 | 	ctx.Data["SigningKeyAvailable"] = len(signing) > 0 | ||||||
|  |  | ||||||
|  | @ -51,6 +51,9 @@ func Profile(ctx *context.Context) { | ||||||
| 	ctx.Data["DisableGravatar"] = setting.Config().Picture.DisableGravatar.Value(ctx) | 	ctx.Data["DisableGravatar"] = setting.Config().Picture.DisableGravatar.Value(ctx) | ||||||
| 	ctx.Data["CooldownPeriod"] = setting.Service.UsernameCooldownPeriod | 	ctx.Data["CooldownPeriod"] = setting.Service.UsernameCooldownPeriod | ||||||
| 	ctx.Data["CommonPronouns"] = commonPronouns | 	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) | 	ctx.HTML(http.StatusOK, tplSettingsProfile) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -208,6 +208,7 @@ | ||||||
| 				<div class="inline field tw-pl-4"> | 				<div class="inline field tw-pl-4"> | ||||||
| 					<label for="avatar">{{ctx.Locale.Tr "settings.choose_new_avatar"}}</label> | 					<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"> | 					<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> | ||||||
| 
 | 
 | ||||||
| 				<div class="field"> | 				<div class="field"> | ||||||
|  |  | ||||||
|  | @ -94,6 +94,7 @@ | ||||||
| 						<div class="inline field"> | 						<div class="inline field"> | ||||||
| 							<label for="avatar">{{ctx.Locale.Tr "settings.choose_new_avatar"}}</label> | 							<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"> | 							<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> | ||||||
| 
 | 
 | ||||||
| 						<div class="field"> | 						<div class="field"> | ||||||
|  |  | ||||||
|  | @ -56,6 +56,7 @@ | ||||||
| 				<div class="inline field"> | 				<div class="inline field"> | ||||||
| 					<label for="avatar">{{ctx.Locale.Tr "settings.choose_new_avatar"}}</label> | 					<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"> | 					<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> | ||||||
| 				<div class="field"> | 				<div class="field"> | ||||||
| 					<button class="ui primary button">{{ctx.Locale.Tr "settings.update_avatar"}}</button> | 					<button class="ui primary button">{{ctx.Locale.Tr "settings.update_avatar"}}</button> | ||||||
|  |  | ||||||
|  | @ -138,6 +138,7 @@ | ||||||
| 				<div class="inline field tw-pl-4"> | 				<div class="inline field tw-pl-4"> | ||||||
| 					<label for="new-avatar">{{ctx.Locale.Tr "settings.choose_new_avatar"}}</label> | 					<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"> | 					<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> | ||||||
| 
 | 
 | ||||||
| 				<div class="field"> | 				<div class="field"> | ||||||
|  |  | ||||||
|  | @ -155,3 +155,51 @@ func TestSettingSecurityAuthSource(t *testing.T) { | ||||||
| 	assert.Contains(t, resp.Body.String(), `gitlab-active`) | 	assert.Contains(t, resp.Body.String(), `gitlab-active`) | ||||||
| 	assert.Contains(t, resp.Body.String(), `gitlab-inactive`) | 	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") | ||||||
|  | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Thomas Böhler
				Thomas Böhler