feat: add pronoun privacy option (#6773)

This commit contains UI changes, tests and migrations for a feature
that lets users optionally hide their pronouns from the general
public. This is useful if a person wants to disclose that
information to a smaller set of people on a local instance
belonging to a local community/association.

Co-authored-by: Gusted <gusted@noreply.codeberg.org>
Co-authored-by: Beowulf <beowulf@beocode.eu>
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/6773
Reviewed-by: Gusted <gusted@noreply.codeberg.org>
Co-authored-by: Panagiotis "Ivory" Vasilopoulos <git@n0toose.net>
Co-committed-by: Panagiotis "Ivory" Vasilopoulos <git@n0toose.net>
This commit is contained in:
Panagiotis "Ivory" Vasilopoulos 2025-02-15 13:07:15 +00:00 committed by Gusted
parent 7104c73c96
commit a1486b0ee4
17 changed files with 158 additions and 25 deletions

View file

@ -45,6 +45,7 @@
full_name: ' < U<se>r Tw<o > >< ' full_name: ' < U<se>r Tw<o > >< '
email: user2@example.com email: user2@example.com
keep_email_private: true keep_email_private: true
keep_pronouns_private: true
email_notifications_preference: enabled email_notifications_preference: enabled
passwd: ZogKvWdyEx:password passwd: ZogKvWdyEx:password
passwd_hash_algo: dummy passwd_hash_algo: dummy
@ -350,6 +351,7 @@
full_name: User Ten full_name: User Ten
email: user10@example.com email: user10@example.com
keep_email_private: false keep_email_private: false
keep_pronouns_private: true
email_notifications_preference: enabled email_notifications_preference: enabled
passwd: ZogKvWdyEx:password passwd: ZogKvWdyEx:password
passwd_hash_algo: dummy passwd_hash_algo: dummy

View file

@ -92,6 +92,8 @@ var migrations = []*Migration{
NewMigration("Add `hash_blake2b` column to `package_blob` table", AddHashBlake2bToPackageBlob), NewMigration("Add `hash_blake2b` column to `package_blob` table", AddHashBlake2bToPackageBlob),
// v27 -> v28 // v27 -> v28
NewMigration("Add `created_unix` column to `user_redirect` table", AddCreatedUnixToRedirect), NewMigration("Add `created_unix` column to `user_redirect` table", AddCreatedUnixToRedirect),
// v28 -> v29
NewMigration("Add pronoun privacy settings to user", AddHidePronounsOptionToUser),
} }
// GetCurrentDBVersion returns the current Forgejo database version. // GetCurrentDBVersion returns the current Forgejo database version.

View file

@ -0,0 +1,15 @@
// Copyright 2024 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package forgejo_migrations //nolint:revive
import "xorm.io/xorm"
func AddHidePronounsOptionToUser(x *xorm.Engine) error {
type User struct {
ID int64 `xorm:"pk autoincr"`
KeepPronounsPrivate bool `xorm:"NOT NULL DEFAULT false"`
}
return x.Sync(&User{})
}

View file

@ -154,6 +154,7 @@ type User struct {
DiffViewStyle string `xorm:"NOT NULL DEFAULT ''"` DiffViewStyle string `xorm:"NOT NULL DEFAULT ''"`
Theme string `xorm:"NOT NULL DEFAULT ''"` Theme string `xorm:"NOT NULL DEFAULT ''"`
KeepActivityPrivate bool `xorm:"NOT NULL DEFAULT false"` KeepActivityPrivate bool `xorm:"NOT NULL DEFAULT false"`
KeepPronounsPrivate bool `xorm:"NOT NULL DEFAULT false"`
EnableRepoUnitHints bool `xorm:"NOT NULL DEFAULT true"` EnableRepoUnitHints bool `xorm:"NOT NULL DEFAULT true"`
} }
@ -500,6 +501,16 @@ func (u *User) GetCompleteName() string {
return u.Name return u.Name
} }
// GetPronouns returns an empty string, if the user has set to keep his
// pronouns private from non-logged in users, otherwise the pronouns
// are returned.
func (u *User) GetPronouns(signed bool) string {
if u.KeepPronounsPrivate && !signed {
return ""
}
return u.Pronouns
}
func gitSafeName(name string) string { func gitSafeName(name string) string {
return strings.TrimSpace(strings.NewReplacer("\n", "", "<", "", ">", "").Replace(name)) return strings.TrimSpace(strings.NewReplacer("\n", "", "<", "", ">", "").Replace(name))
} }

View file

@ -795,3 +795,42 @@ func TestGetInactiveUsers(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.Empty(t, users) require.Empty(t, users)
} }
func TestPronounsPrivacy(t *testing.T) {
require.NoError(t, unittest.PrepareTestDatabase())
t.Run("EmptyPronounsIfNoneSet", func(t *testing.T) {
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
user.Pronouns = ""
user.KeepPronounsPrivate = false
assert.Equal(t, "", user.GetPronouns(false))
})
t.Run("EmptyPronounsIfSetButPrivateAndNotLoggedIn", func(t *testing.T) {
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
user.Pronouns = "any"
user.KeepPronounsPrivate = true
assert.Equal(t, "", user.GetPronouns(false))
})
t.Run("ReturnPronounsIfSetAndNotPrivateAndNotLoggedIn", func(t *testing.T) {
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
user.Pronouns = "any"
user.KeepPronounsPrivate = false
assert.Equal(t, "any", user.GetPronouns(false))
})
t.Run("ReturnPronounsIfSetAndPrivateAndLoggedIn", func(t *testing.T) {
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
user.Pronouns = "any"
user.KeepPronounsPrivate = false
assert.Equal(t, "any", user.GetPronouns(true))
})
t.Run("ReturnPronounsIfSetAndNotPrivateAndLoggedIn", func(t *testing.T) {
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
user.Pronouns = "any"
user.KeepPronounsPrivate = true
assert.Equal(t, "any", user.GetPronouns(true))
})
}

View file

@ -84,6 +84,7 @@ type UserSettings struct {
EnableRepoUnitHints bool `json:"enable_repo_unit_hints"` EnableRepoUnitHints bool `json:"enable_repo_unit_hints"`
// Privacy // Privacy
HideEmail bool `json:"hide_email"` HideEmail bool `json:"hide_email"`
HidePronouns bool `json:"hide_pronouns"`
HideActivity bool `json:"hide_activity"` HideActivity bool `json:"hide_activity"`
} }
@ -101,6 +102,7 @@ type UserSettingsOptions struct {
EnableRepoUnitHints *bool `json:"enable_repo_unit_hints"` EnableRepoUnitHints *bool `json:"enable_repo_unit_hints"`
// Privacy // Privacy
HideEmail *bool `json:"hide_email"` HideEmail *bool `json:"hide_email"`
HidePronouns *bool `json:"hide_pronouns"`
HideActivity *bool `json:"hide_activity"` HideActivity *bool `json:"hide_activity"`
} }

View file

@ -853,6 +853,8 @@ email_preference_set_success = Email preference has been set successfully.
add_openid_success = The new OpenID address has been added. add_openid_success = The new OpenID address has been added.
keep_email_private = Hide email address keep_email_private = Hide email address
keep_email_private_popup = Your email address will not be shown on your profile and will not be the default for commits made via the web interface, like file uploads, edits, and merge commits. Instead, a special address %s can be used to link commits to your account. This option will not affect existing commits. keep_email_private_popup = Your email address will not be shown on your profile and will not be the default for commits made via the web interface, like file uploads, edits, and merge commits. Instead, a special address %s can be used to link commits to your account. This option will not affect existing commits.
keep_pronouns_private = Only show pronouns to authenticated users
keep_pronouns_private.description = This will hide your pronouns from visitors that are not logged in.
openid_desc = OpenID lets you delegate authentication to an external provider. openid_desc = OpenID lets you delegate authentication to an external provider.
manage_ssh_keys = Manage SSH keys manage_ssh_keys = Manage SSH keys
@ -3935,4 +3937,4 @@ filepreview.lines = Lines %[1]d to %[2]d in %[3]s
filepreview.truncated = Preview has been truncated filepreview.truncated = Preview has been truncated
[translation_meta] [translation_meta]
test = This is a test string. It is not displayed in Forgejo UI but is used for testing purposes. Feel free to enter "ok" to save time (or a fun fact of your choice) to hit that sweet 100% completion mark :) test = This is a test string. It is not displayed in Forgejo UI but is used for testing purposes. Feel free to enter "ok" to save time (or a fun fact of your choice) to hit that sweet 100% completion mark :)

View file

@ -63,6 +63,7 @@ func UpdateUserSettings(ctx *context.APIContext) {
Theme: optional.FromPtr(form.Theme), Theme: optional.FromPtr(form.Theme),
DiffViewStyle: optional.FromPtr(form.DiffViewStyle), DiffViewStyle: optional.FromPtr(form.DiffViewStyle),
KeepEmailPrivate: optional.FromPtr(form.HideEmail), KeepEmailPrivate: optional.FromPtr(form.HideEmail),
KeepPronounsPrivate: optional.FromPtr(form.HidePronouns),
KeepActivityPrivate: optional.FromPtr(form.HideActivity), KeepActivityPrivate: optional.FromPtr(form.HideActivity),
EnableRepoUnitHints: optional.FromPtr(form.EnableRepoUnitHints), EnableRepoUnitHints: optional.FromPtr(form.EnableRepoUnitHints),
} }

View file

@ -31,6 +31,7 @@ func AuthShared(ctx *context.Base, sessionStore auth_service.SessionStore, authM
ctx.Data["SignedUserID"] = ar.Doer.ID ctx.Data["SignedUserID"] = ar.Doer.ID
ctx.Data["IsAdmin"] = ar.Doer.IsAdmin ctx.Data["IsAdmin"] = ar.Doer.IsAdmin
} else { } else {
ctx.Data["IsSigned"] = false
ctx.Data["SignedUserID"] = int64(0) ctx.Data["SignedUserID"] = int64(0)
} }
return ar, nil return ar, nil

View file

@ -106,6 +106,7 @@ func ProfilePost(ctx *context.Context) {
Location: optional.Some(form.Location), Location: optional.Some(form.Location),
Visibility: optional.Some(form.Visibility), Visibility: optional.Some(form.Visibility),
KeepActivityPrivate: optional.Some(form.KeepActivityPrivate), KeepActivityPrivate: optional.Some(form.KeepActivityPrivate),
KeepPronounsPrivate: optional.Some(form.KeepPronounsPrivate),
} }
if err := user_service.UpdateUser(ctx, ctx.Doer, opts); err != nil { if err := user_service.UpdateUser(ctx, ctx.Doer, opts); err != nil {
ctx.ServerError("UpdateUser", err) ctx.ServerError("UpdateUser", err)

View file

@ -57,7 +57,7 @@ func toUser(ctx context.Context, user *user_model.User, signed, authed bool) *ap
Created: user.CreatedUnix.AsTime(), Created: user.CreatedUnix.AsTime(),
Restricted: user.IsRestricted, Restricted: user.IsRestricted,
Location: user.Location, Location: user.Location,
Pronouns: user.Pronouns, Pronouns: user.GetPronouns(signed),
Website: user.Website, Website: user.Website,
Description: user.Description, Description: user.Description,
// counter's // counter's
@ -97,6 +97,7 @@ func User2UserSettings(user *user_model.User) api.UserSettings {
Description: user.Description, Description: user.Description,
Theme: user.Theme, Theme: user.Theme,
HideEmail: user.KeepEmailPrivate, HideEmail: user.KeepEmailPrivate,
HidePronouns: user.KeepPronounsPrivate,
HideActivity: user.KeepActivityPrivate, HideActivity: user.KeepActivityPrivate,
DiffViewStyle: user.DiffViewStyle, DiffViewStyle: user.DiffViewStyle,
EnableRepoUnitHints: user.EnableRepoUnitHints, EnableRepoUnitHints: user.EnableRepoUnitHints,

View file

@ -224,6 +224,7 @@ type UpdateProfileForm struct {
Biography string `binding:"MaxSize(255)"` Biography string `binding:"MaxSize(255)"`
Visibility structs.VisibleType Visibility structs.VisibleType
KeepActivityPrivate bool KeepActivityPrivate bool
KeepPronounsPrivate bool
} }
// Validate validates the fields // Validate validates the fields

View file

@ -40,6 +40,7 @@ type UpdateOptions struct {
SetLastLogin bool SetLastLogin bool
RepoAdminChangeTeamAccess optional.Option[bool] RepoAdminChangeTeamAccess optional.Option[bool]
EnableRepoUnitHints optional.Option[bool] EnableRepoUnitHints optional.Option[bool]
KeepPronounsPrivate optional.Option[bool]
} }
func UpdateUser(ctx context.Context, u *user_model.User, opts *UpdateOptions) error { func UpdateUser(ctx context.Context, u *user_model.User, opts *UpdateOptions) error {
@ -97,6 +98,12 @@ func UpdateUser(ctx context.Context, u *user_model.User, opts *UpdateOptions) er
cols = append(cols, "enable_repo_unit_hints") cols = append(cols, "enable_repo_unit_hints")
} }
if opts.KeepPronounsPrivate.Has() {
u.KeepPronounsPrivate = opts.KeepPronounsPrivate.Value()
cols = append(cols, "keep_pronouns_private")
}
if opts.AllowGitHook.Has() { if opts.AllowGitHook.Has() {
u.AllowGitHook = opts.AllowGitHook.Value() u.AllowGitHook = opts.AllowGitHook.Value()

View file

@ -16,7 +16,7 @@
</div> </div>
<div class="content tw-break-anywhere profile-avatar-name"> <div class="content tw-break-anywhere profile-avatar-name">
{{if .ContextUser.FullName}}<span class="header text center">{{.ContextUser.FullName}}</span>{{end}} {{if .ContextUser.FullName}}<span class="header text center">{{.ContextUser.FullName}}</span>{{end}}
<span class="username text center">{{.ContextUser.Name}}{{if .ContextUser.Pronouns}} · {{.ContextUser.Pronouns}}{{end}} {{if .IsAdmin}} <span class="username text center">{{.ContextUser.Name}} {{if .ContextUser.GetPronouns .IsSigned}} · {{.ContextUser.GetPronouns .IsSigned}}{{end}} {{if .IsAdmin}}
<a class="muted" href="{{AppSubUrl}}/admin/users/{{.ContextUser.ID}}" data-tooltip-content="{{ctx.Locale.Tr "admin.users.details"}}"> <a class="muted" href="{{AppSubUrl}}/admin/users/{{.ContextUser.ID}}" data-tooltip-content="{{ctx.Locale.Tr "admin.users.details"}}">
{{svg "octicon-gear" 18}} {{svg "octicon-gear" 18}}
</a> </a>

View file

@ -27954,6 +27954,10 @@
"type": "boolean", "type": "boolean",
"x-go-name": "HideEmail" "x-go-name": "HideEmail"
}, },
"hide_pronouns": {
"type": "boolean",
"x-go-name": "HidePronouns"
},
"language": { "language": {
"type": "string", "type": "string",
"x-go-name": "Language" "x-go-name": "Language"
@ -28006,6 +28010,10 @@
"type": "boolean", "type": "boolean",
"x-go-name": "HideEmail" "x-go-name": "HideEmail"
}, },
"hide_pronouns": {
"type": "boolean",
"x-go-name": "HidePronouns"
},
"language": { "language": {
"type": "string", "type": "string",
"x-go-name": "Language" "x-go-name": "Language"

View file

@ -120,6 +120,12 @@
{{ctx.Locale.Tr "settings.keep_activity_private"}} {{ctx.Locale.Tr "settings.keep_activity_private"}}
<span class="help">{{ctx.Locale.Tr "settings.keep_activity_private.description" (printf "/%s?tab=activity" .SignedUser.Name)}}</span> <span class="help">{{ctx.Locale.Tr "settings.keep_activity_private.description" (printf "/%s?tab=activity" .SignedUser.Name)}}</span>
</label> </label>
<label>
<input name="keep_pronouns_private" type="checkbox" {{if .SignedUser.KeepPronounsPrivate}}checked{{end}}>
{{ctx.Locale.Tr "settings.keep_pronouns_private"}}
<span class="help">{{ctx.Locale.Tr "settings.keep_pronouns_private.description"}}</span>
</label>
</fieldset> </fieldset>
<button class="ui primary button">{{ctx.Locale.Tr "settings.update_profile"}}</button> <button class="ui primary button">{{ctx.Locale.Tr "settings.update_profile"}}</button>

View file

@ -438,8 +438,16 @@ func TestUserHints(t *testing.T) {
func TestUserPronouns(t *testing.T) { func TestUserPronouns(t *testing.T) {
defer tests.PrepareTestEnv(t)() defer tests.PrepareTestEnv(t)()
session := loginUser(t, "user2") // user1 is admin, using user2 and user10 respectively instead.
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteUser) // This is explicitly mentioned here because of the unconventional
// variable naming scheme.
firstUserSession := loginUser(t, "user2")
firstUserToken := getTokenForLoggedInUser(t, firstUserSession, auth_model.AccessTokenScopeWriteUser)
// This user has the HidePronouns setting enabled.
// Check the fixture!
secondUserSession := loginUser(t, "user10")
secondUserToken := getTokenForLoggedInUser(t, secondUserSession, auth_model.AccessTokenScopeWriteUser)
adminUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{IsAdmin: true}) adminUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{IsAdmin: true})
adminSession := loginUser(t, adminUser.Name) adminSession := loginUser(t, adminUser.Name)
@ -449,8 +457,10 @@ func TestUserPronouns(t *testing.T) {
t.Run("user", func(t *testing.T) { t.Run("user", func(t *testing.T) {
defer tests.PrintCurrentTest(t)() defer tests.PrintCurrentTest(t)()
req := NewRequest(t, "GET", "/api/v1/user").AddTokenAuth(token) // secondUserToken was chosen arbitrarily and should have no impact.
resp := MakeRequest(t, req, http.StatusOK) // See next comment.
req := NewRequest(t, "GET", "/api/v1/user").AddTokenAuth(secondUserToken)
resp := firstUserSession.MakeRequest(t, req, http.StatusOK)
// We check the raw JSON, because we want to test the response, not // We check the raw JSON, because we want to test the response, not
// what it decodes into. Contents doesn't matter, we're testing the // what it decodes into. Contents doesn't matter, we're testing the
@ -468,16 +478,22 @@ func TestUserPronouns(t *testing.T) {
// what it decodes into. Contents doesn't matter, we're testing the // what it decodes into. Contents doesn't matter, we're testing the
// presence only. // presence only.
assert.Contains(t, resp.Body.String(), `"pronouns":`) assert.Contains(t, resp.Body.String(), `"pronouns":`)
req = NewRequest(t, "GET", "/api/v1/users/user10")
resp = MakeRequest(t, req, http.StatusOK)
// Same deal here.
assert.Contains(t, resp.Body.String(), `"pronouns":`)
}) })
t.Run("user/settings", func(t *testing.T) { t.Run("user/settings", func(t *testing.T) {
defer tests.PrintCurrentTest(t)() defer tests.PrintCurrentTest(t)()
// Set pronouns first // Set pronouns first for user2
pronouns := "they/them" pronouns := "they/them"
req := NewRequestWithJSON(t, "PATCH", "/api/v1/user/settings", &api.UserSettingsOptions{ req := NewRequestWithJSON(t, "PATCH", "/api/v1/user/settings", &api.UserSettingsOptions{
Pronouns: &pronouns, Pronouns: &pronouns,
}).AddTokenAuth(token) }).AddTokenAuth(firstUserToken)
resp := MakeRequest(t, req, http.StatusOK) resp := MakeRequest(t, req, http.StatusOK)
// Verify the response // Verify the response
@ -486,7 +502,7 @@ func TestUserPronouns(t *testing.T) {
assert.Equal(t, pronouns, user.Pronouns) assert.Equal(t, pronouns, user.Pronouns)
// Verify retrieving the settings again // Verify retrieving the settings again
req = NewRequest(t, "GET", "/api/v1/user/settings").AddTokenAuth(token) req = NewRequest(t, "GET", "/api/v1/user/settings").AddTokenAuth(firstUserToken)
resp = MakeRequest(t, req, http.StatusOK) resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &user) DecodeJSON(t, resp, &user)
@ -497,22 +513,40 @@ func TestUserPronouns(t *testing.T) {
defer tests.PrintCurrentTest(t)() defer tests.PrintCurrentTest(t)()
// Set the pronouns for user2 // Set the pronouns for user2
pronouns := "she/her" pronouns := "he/him"
req := NewRequestWithJSON(t, "PATCH", "/api/v1/admin/users/user2", &api.EditUserOption{ req := NewRequestWithJSON(t, "PATCH", "/api/v1/admin/users/user2", &api.EditUserOption{
Pronouns: &pronouns, Pronouns: &pronouns,
}).AddTokenAuth(adminToken) }).AddTokenAuth(adminToken)
resp := MakeRequest(t, req, http.StatusOK) resp := MakeRequest(t, req, http.StatusOK)
// Verify the API response // Verify the API response
var user *api.User var user2 *api.User
DecodeJSON(t, resp, &user) DecodeJSON(t, resp, &user2)
assert.Equal(t, pronouns, user.Pronouns) assert.Equal(t, pronouns, user2.Pronouns)
// Verify via user2 too // Verify via user2
req = NewRequest(t, "GET", "/api/v1/user").AddTokenAuth(token) req = NewRequest(t, "GET", "/api/v1/user").AddTokenAuth(firstUserToken)
resp = MakeRequest(t, req, http.StatusOK) resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &user) DecodeJSON(t, resp, &user2)
assert.Equal(t, pronouns, user.Pronouns) assert.Equal(t, pronouns, user2.Pronouns) // TODO: This fails for some reason
// Set the pronouns for user10
pronouns = "he/him"
req = NewRequestWithJSON(t, "PATCH", "/api/v1/admin/users/user10", &api.EditUserOption{
Pronouns: &pronouns,
}).AddTokenAuth(adminToken)
resp = MakeRequest(t, req, http.StatusOK)
// Verify the API response
var user10 *api.User
DecodeJSON(t, resp, &user10)
assert.Equal(t, pronouns, user10.Pronouns)
// Verify via user10
req = NewRequest(t, "GET", "/api/v1/user").AddTokenAuth(secondUserToken)
resp = MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &user10)
assert.Equal(t, pronouns, user10.Pronouns)
}) })
}) })
@ -520,10 +554,10 @@ func TestUserPronouns(t *testing.T) {
defer tests.PrintCurrentTest(t)() defer tests.PrintCurrentTest(t)()
// Set the pronouns to a known state via the API // Set the pronouns to a known state via the API
pronouns := "she/her" pronouns := "they/them"
req := NewRequestWithJSON(t, "PATCH", "/api/v1/user/settings", &api.UserSettingsOptions{ req := NewRequestWithJSON(t, "PATCH", "/api/v1/user/settings", &api.UserSettingsOptions{
Pronouns: &pronouns, Pronouns: &pronouns,
}).AddTokenAuth(token) }).AddTokenAuth(firstUserToken)
MakeRequest(t, req, http.StatusOK) MakeRequest(t, req, http.StatusOK)
t.Run("profile view", func(t *testing.T) { t.Run("profile view", func(t *testing.T) {
@ -534,14 +568,14 @@ func TestUserPronouns(t *testing.T) {
htmlDoc := NewHTMLParser(t, resp.Body) htmlDoc := NewHTMLParser(t, resp.Body)
userNameAndPronouns := strings.TrimSpace(htmlDoc.Find(".profile-avatar-name .username").Text()) userNameAndPronouns := strings.TrimSpace(htmlDoc.Find(".profile-avatar-name .username").Text())
assert.Contains(t, userNameAndPronouns, pronouns) assert.NotContains(t, userNameAndPronouns, pronouns)
}) })
t.Run("settings", func(t *testing.T) { t.Run("settings", func(t *testing.T) {
defer tests.PrintCurrentTest(t)() defer tests.PrintCurrentTest(t)()
req := NewRequest(t, "GET", "/user/settings") req := NewRequest(t, "GET", "/user/settings")
resp := session.MakeRequest(t, req, http.StatusOK) resp := firstUserSession.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body) htmlDoc := NewHTMLParser(t, resp.Body)
// Check that the field is present // Check that the field is present
@ -550,12 +584,12 @@ func TestUserPronouns(t *testing.T) {
assert.Equal(t, pronouns, pronounField) assert.Equal(t, pronouns, pronounField)
// Check that updating the field works // Check that updating the field works
newPronouns := "they/them" newPronouns := "she/her"
req = NewRequestWithValues(t, "POST", "/user/settings", map[string]string{ req = NewRequestWithValues(t, "POST", "/user/settings", map[string]string{
"_csrf": GetCSRF(t, session, "/user/settings"), "_csrf": GetCSRF(t, firstUserSession, "/user/settings"),
"pronouns": newPronouns, "pronouns": newPronouns,
}) })
session.MakeRequest(t, req, http.StatusSeeOther) firstUserSession.MakeRequest(t, req, http.StatusSeeOther)
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user2"}) user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user2"})
assert.Equal(t, newPronouns, user2.Pronouns) assert.Equal(t, newPronouns, user2.Pronouns)