diff options
author | David Schneiderbauer <daviian@users.noreply.github.com> | 2018-05-15 12:07:32 +0200 |
---|---|---|
committer | Lauris BH <lauris@nix.lv> | 2018-05-15 13:07:32 +0300 |
commit | 099372d76c411c598285d637bd85c9b2dbc40948 (patch) | |
tree | bce801f16b8534e2ca0dadcbc24455de95f0501c /routers/user | |
parent | 1546458f7df4a4f0e77b7ae5cb65baed6feae394 (diff) | |
download | gitea-099372d76c411c598285d637bd85c9b2dbc40948.tar.gz gitea-099372d76c411c598285d637bd85c9b2dbc40948.zip |
Refactor User Settings (#3900)
* moved avatar to profile page
* combined password change, email and account deletion into account settings page
* combined totp, access tokens, linked accounts and openid into security settings page
* move access tokens to applications settings page
* small change to restart drone build
* fix change avatar url on profile page
* redirect old settings urls to new ones
* enforce only one autofocus attribute on settings pages
* set correct redirect status code
* fmt fix
Diffstat (limited to 'routers/user')
-rw-r--r-- | routers/user/setting.go | 379 | ||||
-rw-r--r-- | routers/user/setting_openid.go | 47 | ||||
-rw-r--r-- | routers/user/setting_test.go | 2 |
3 files changed, 194 insertions, 234 deletions
diff --git a/routers/user/setting.go b/routers/user/setting.go index f4326bf0f5..1c760e210c 100644 --- a/routers/user/setting.go +++ b/routers/user/setting.go @@ -30,18 +30,13 @@ import ( const ( tplSettingsProfile base.TplName = "user/settings/profile" - tplSettingsAvatar base.TplName = "user/settings/avatar" - tplSettingsEmails base.TplName = "user/settings/email" - tplSettingsKeys base.TplName = "user/settings/keys" - tplSettingsSocial base.TplName = "user/settings/social" - tplSettingsApplications base.TplName = "user/settings/applications" - tplSettingsTwofa base.TplName = "user/settings/twofa" + tplSettingsAccount base.TplName = "user/settings/account" + tplSettingsSecurity base.TplName = "user/settings/security" tplSettingsTwofaEnroll base.TplName = "user/settings/twofa_enroll" - tplSettingsAccountLink base.TplName = "user/settings/account_link" + tplSettingsApplications base.TplName = "user/settings/applications" + tplSettingsKeys base.TplName = "user/settings/keys" tplSettingsOrganization base.TplName = "user/settings/organization" tplSettingsRepositories base.TplName = "user/settings/repos" - tplSettingsDelete base.TplName = "user/settings/delete" - tplSettingsSecurity base.TplName = "user/settings/security" ) // Settings render user's profile page @@ -168,13 +163,6 @@ func UpdateAvatarSetting(ctx *context.Context, form auth.AvatarForm, ctxUser *mo return nil } -// SettingsAvatar render user avatar page -func SettingsAvatar(ctx *context.Context) { - ctx.Data["Title"] = ctx.Tr("settings") - ctx.Data["PageIsSettingsAvatar"] = true - ctx.HTML(200, tplSettingsAvatar) -} - // SettingsAvatarPost response for change user's avatar request func SettingsAvatarPost(ctx *context.Context, form auth.AvatarForm) { if err := UpdateAvatarSetting(ctx, form, ctx.User); err != nil { @@ -183,7 +171,7 @@ func SettingsAvatarPost(ctx *context.Context, form auth.AvatarForm) { ctx.Flash.Success(ctx.Tr("settings.update_avatar_success")) } - ctx.Redirect(setting.AppSubURL + "/user/settings/avatar") + ctx.Redirect(setting.AppSubURL + "/user/settings") } // SettingsDeleteAvatar render delete avatar page @@ -192,38 +180,32 @@ func SettingsDeleteAvatar(ctx *context.Context) { ctx.Flash.Error(err.Error()) } - ctx.Redirect(setting.AppSubURL + "/user/settings/avatar") + ctx.Redirect(setting.AppSubURL + "/user/settings") } -// SettingsSecurity render change user's password page and 2FA -func SettingsSecurity(ctx *context.Context) { +// SettingsAccount renders change user's password, user's email and user suicide page +func SettingsAccount(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("settings") - ctx.Data["PageIsSettingsSecurity"] = true + ctx.Data["PageIsSettingsAccount"] = true ctx.Data["Email"] = ctx.User.Email - enrolled := true - _, err := models.GetTwoFactorByUID(ctx.User.ID) + emails, err := models.GetEmailAddresses(ctx.User.ID) if err != nil { - if models.IsErrTwoFactorNotEnrolled(err) { - enrolled = false - } else { - ctx.ServerError("SettingsTwoFactor", err) - return - } + ctx.ServerError("GetEmailAddresses", err) + return } + ctx.Data["Emails"] = emails - ctx.Data["TwofaEnrolled"] = enrolled - ctx.HTML(200, tplSettingsSecurity) + ctx.HTML(200, tplSettingsAccount) } -// SettingsSecurityPost response for change user's password -func SettingsSecurityPost(ctx *context.Context, form auth.ChangePasswordForm) { +// SettingsAccountPost response for change user's password +func SettingsAccountPost(ctx *context.Context, form auth.ChangePasswordForm) { ctx.Data["Title"] = ctx.Tr("settings") - ctx.Data["PageIsSettingsSecurity"] = true - ctx.Data["PageIsSettingsDelete"] = true + ctx.Data["PageIsSettingsAccount"] = true if ctx.HasError() { - ctx.HTML(200, tplSettingsSecurity) + ctx.HTML(200, tplSettingsAccount) return } @@ -248,28 +230,13 @@ func SettingsSecurityPost(ctx *context.Context, form auth.ChangePasswordForm) { ctx.Flash.Success(ctx.Tr("settings.change_password_success")) } - ctx.Redirect(setting.AppSubURL + "/user/settings/security") -} - -// SettingsEmails render user's emails page -func SettingsEmails(ctx *context.Context) { - ctx.Data["Title"] = ctx.Tr("settings") - ctx.Data["PageIsSettingsEmails"] = true - - emails, err := models.GetEmailAddresses(ctx.User.ID) - if err != nil { - ctx.ServerError("GetEmailAddresses", err) - return - } - ctx.Data["Emails"] = emails - - ctx.HTML(200, tplSettingsEmails) + ctx.Redirect(setting.AppSubURL + "/user/settings/account") } // SettingsEmailPost response for change user's email func SettingsEmailPost(ctx *context.Context, form auth.AddEmailForm) { ctx.Data["Title"] = ctx.Tr("settings") - ctx.Data["PageIsSettingsEmails"] = true + ctx.Data["PageIsSettingsAccount"] = true // Make emailaddress primary. if ctx.Query("_method") == "PRIMARY" { @@ -279,7 +246,7 @@ func SettingsEmailPost(ctx *context.Context, form auth.AddEmailForm) { } log.Trace("Email made primary: %s", ctx.User.Name) - ctx.Redirect(setting.AppSubURL + "/user/settings/email") + ctx.Redirect(setting.AppSubURL + "/user/settings/account") return } @@ -292,7 +259,7 @@ func SettingsEmailPost(ctx *context.Context, form auth.AddEmailForm) { ctx.Data["Emails"] = emails if ctx.HasError() { - ctx.HTML(200, tplSettingsEmails) + ctx.HTML(200, tplSettingsAccount) return } @@ -303,7 +270,7 @@ func SettingsEmailPost(ctx *context.Context, form auth.AddEmailForm) { } if err := models.AddEmailAddress(email); err != nil { if models.IsErrEmailAlreadyUsed(err) { - ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplSettingsEmails, &form) + ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplSettingsAccount, &form) return } ctx.ServerError("AddEmailAddress", err) @@ -323,7 +290,7 @@ func SettingsEmailPost(ctx *context.Context, form auth.AddEmailForm) { } log.Trace("Email address added: %s", email.Email) - ctx.Redirect(setting.AppSubURL + "/user/settings/email") + ctx.Redirect(setting.AppSubURL + "/user/settings/account") } // DeleteEmail response for delete user's email @@ -336,7 +303,164 @@ func DeleteEmail(ctx *context.Context) { ctx.Flash.Success(ctx.Tr("settings.email_deletion_success")) ctx.JSON(200, map[string]interface{}{ - "redirect": setting.AppSubURL + "/user/settings/email", + "redirect": setting.AppSubURL + "/user/settings/account", + }) +} + +// SettingsDelete render user suicide page and response for delete user himself +func SettingsDelete(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("settings") + ctx.Data["PageIsSettingsAccount"] = true + + if _, err := models.UserSignIn(ctx.User.Name, ctx.Query("password")); err != nil { + if models.IsErrUserNotExist(err) { + ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_password"), tplSettingsAccount, nil) + } else { + ctx.ServerError("UserSignIn", err) + } + return + } + + if err := models.DeleteUser(ctx.User); err != nil { + switch { + case models.IsErrUserOwnRepos(err): + ctx.Flash.Error(ctx.Tr("form.still_own_repo")) + ctx.Redirect(setting.AppSubURL + "/user/settings/account") + case models.IsErrUserHasOrgs(err): + ctx.Flash.Error(ctx.Tr("form.still_has_org")) + ctx.Redirect(setting.AppSubURL + "/user/settings/account") + default: + ctx.ServerError("DeleteUser", err) + } + } else { + log.Trace("Account deleted: %s", ctx.User.Name) + ctx.Redirect(setting.AppSubURL + "/") + } +} + +// SettingsSecurity render change user's password page and 2FA +func SettingsSecurity(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("settings") + ctx.Data["PageIsSettingsSecurity"] = true + + enrolled := true + _, err := models.GetTwoFactorByUID(ctx.User.ID) + if err != nil { + if models.IsErrTwoFactorNotEnrolled(err) { + enrolled = false + } else { + ctx.ServerError("SettingsTwoFactor", err) + return + } + } + ctx.Data["TwofaEnrolled"] = enrolled + + accountLinks, err := models.ListAccountLinks(ctx.User) + if err != nil { + ctx.ServerError("ListAccountLinks", err) + return + } + + // map the provider display name with the LoginSource + sources := make(map[*models.LoginSource]string) + for _, externalAccount := range accountLinks { + if loginSource, err := models.GetLoginSourceByID(externalAccount.LoginSourceID); err == nil { + var providerDisplayName string + if loginSource.IsOAuth2() { + providerTechnicalName := loginSource.OAuth2().Provider + providerDisplayName = models.OAuth2Providers[providerTechnicalName].DisplayName + } else { + providerDisplayName = loginSource.Name + } + sources[loginSource] = providerDisplayName + } + } + ctx.Data["AccountLinks"] = sources + + if ctx.Query("openid.return_to") != "" { + settingsOpenIDVerify(ctx) + return + } + + openid, err := models.GetUserOpenIDs(ctx.User.ID) + if err != nil { + ctx.ServerError("GetUserOpenIDs", err) + return + } + ctx.Data["OpenIDs"] = openid + + ctx.HTML(200, tplSettingsSecurity) +} + +// SettingsDeleteAccountLink delete a single account link +func SettingsDeleteAccountLink(ctx *context.Context) { + if _, err := models.RemoveAccountLink(ctx.User, ctx.QueryInt64("loginSourceID")); err != nil { + ctx.Flash.Error("RemoveAccountLink: " + err.Error()) + } else { + ctx.Flash.Success(ctx.Tr("settings.remove_account_link_success")) + } + + ctx.JSON(200, map[string]interface{}{ + "redirect": setting.AppSubURL + "/user/settings/security", + }) +} + +// SettingsApplications render manage access token page +func SettingsApplications(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("settings") + ctx.Data["PageIsSettingsApplications"] = true + + tokens, err := models.ListAccessTokens(ctx.User.ID) + if err != nil { + ctx.ServerError("ListAccessTokens", err) + return + } + ctx.Data["Tokens"] = tokens + + ctx.HTML(200, tplSettingsApplications) +} + +// SettingsApplicationsPost response for add user's access token +func SettingsApplicationsPost(ctx *context.Context, form auth.NewAccessTokenForm) { + ctx.Data["Title"] = ctx.Tr("settings") + ctx.Data["PageIsSettingsApplications"] = true + + if ctx.HasError() { + tokens, err := models.ListAccessTokens(ctx.User.ID) + if err != nil { + ctx.ServerError("ListAccessTokens", err) + return + } + ctx.Data["Tokens"] = tokens + ctx.HTML(200, tplSettingsApplications) + return + } + + t := &models.AccessToken{ + UID: ctx.User.ID, + Name: form.Name, + } + if err := models.NewAccessToken(t); err != nil { + ctx.ServerError("NewAccessToken", err) + return + } + + ctx.Flash.Success(ctx.Tr("settings.generate_token_success")) + ctx.Flash.Info(t.Sha1) + + ctx.Redirect(setting.AppSubURL + "/user/settings/applications") +} + +// SettingsDeleteApplication response for delete user access token +func SettingsDeleteApplication(ctx *context.Context) { + if err := models.DeleteAccessTokenByID(ctx.QueryInt64("id"), ctx.User.ID); err != nil { + ctx.Flash.Error("DeleteAccessTokenByID: " + err.Error()) + } else { + ctx.Flash.Success(ctx.Tr("settings.delete_token_success")) + } + + ctx.JSON(200, map[string]interface{}{ + "redirect": setting.AppSubURL + "/user/settings/applications", }) } @@ -471,65 +595,6 @@ func DeleteKey(ctx *context.Context) { }) } -// SettingsApplications render user's access tokens page -func SettingsApplications(ctx *context.Context) { - ctx.Data["Title"] = ctx.Tr("settings") - ctx.Data["PageIsSettingsApplications"] = true - - tokens, err := models.ListAccessTokens(ctx.User.ID) - if err != nil { - ctx.ServerError("ListAccessTokens", err) - return - } - ctx.Data["Tokens"] = tokens - - ctx.HTML(200, tplSettingsApplications) -} - -// SettingsApplicationsPost response for add user's access token -func SettingsApplicationsPost(ctx *context.Context, form auth.NewAccessTokenForm) { - ctx.Data["Title"] = ctx.Tr("settings") - ctx.Data["PageIsSettingsApplications"] = true - - if ctx.HasError() { - tokens, err := models.ListAccessTokens(ctx.User.ID) - if err != nil { - ctx.ServerError("ListAccessTokens", err) - return - } - ctx.Data["Tokens"] = tokens - ctx.HTML(200, tplSettingsApplications) - return - } - - t := &models.AccessToken{ - UID: ctx.User.ID, - Name: form.Name, - } - if err := models.NewAccessToken(t); err != nil { - ctx.ServerError("NewAccessToken", err) - return - } - - ctx.Flash.Success(ctx.Tr("settings.generate_token_success")) - ctx.Flash.Info(t.Sha1) - - ctx.Redirect(setting.AppSubURL + "/user/settings/applications") -} - -// SettingsDeleteApplication response for delete user access token -func SettingsDeleteApplication(ctx *context.Context) { - if err := models.DeleteAccessTokenByID(ctx.QueryInt64("id"), ctx.User.ID); err != nil { - ctx.Flash.Error("DeleteAccessTokenByID: " + err.Error()) - } else { - ctx.Flash.Success(ctx.Tr("settings.delete_token_success")) - } - - ctx.JSON(200, map[string]interface{}{ - "redirect": setting.AppSubURL + "/user/settings/applications", - }) -} - // SettingsTwoFactorRegenerateScratch regenerates the user's 2FA scratch code. func SettingsTwoFactorRegenerateScratch(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("settings") @@ -695,86 +760,6 @@ func SettingsTwoFactorEnrollPost(ctx *context.Context, form auth.TwoFactorAuthFo ctx.Redirect(setting.AppSubURL + "/user/settings/security") } -// SettingsAccountLinks render the account links settings page -func SettingsAccountLinks(ctx *context.Context) { - ctx.Data["Title"] = ctx.Tr("settings") - ctx.Data["PageIsSettingsAccountLink"] = true - - accountLinks, err := models.ListAccountLinks(ctx.User) - if err != nil { - ctx.ServerError("ListAccountLinks", err) - return - } - - // map the provider display name with the LoginSource - sources := make(map[*models.LoginSource]string) - for _, externalAccount := range accountLinks { - if loginSource, err := models.GetLoginSourceByID(externalAccount.LoginSourceID); err == nil { - var providerDisplayName string - if loginSource.IsOAuth2() { - providerTechnicalName := loginSource.OAuth2().Provider - providerDisplayName = models.OAuth2Providers[providerTechnicalName].DisplayName - } else { - providerDisplayName = loginSource.Name - } - sources[loginSource] = providerDisplayName - } - } - ctx.Data["AccountLinks"] = sources - - ctx.HTML(200, tplSettingsAccountLink) -} - -// SettingsDeleteAccountLink delete a single account link -func SettingsDeleteAccountLink(ctx *context.Context) { - if _, err := models.RemoveAccountLink(ctx.User, ctx.QueryInt64("loginSourceID")); err != nil { - ctx.Flash.Error("RemoveAccountLink: " + err.Error()) - } else { - ctx.Flash.Success(ctx.Tr("settings.remove_account_link_success")) - } - - ctx.JSON(200, map[string]interface{}{ - "redirect": setting.AppSubURL + "/user/settings/account_link", - }) -} - -// SettingsDelete render user suicide page and response for delete user himself -func SettingsDelete(ctx *context.Context) { - ctx.Data["Title"] = ctx.Tr("settings") - ctx.Data["PageIsSettingsDelete"] = true - ctx.Data["Email"] = ctx.User.Email - - if ctx.Req.Method == "POST" { - if _, err := models.UserSignIn(ctx.User.Name, ctx.Query("password")); err != nil { - if models.IsErrUserNotExist(err) { - ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_password"), tplSettingsDelete, nil) - } else { - ctx.ServerError("UserSignIn", err) - } - return - } - - if err := models.DeleteUser(ctx.User); err != nil { - switch { - case models.IsErrUserOwnRepos(err): - ctx.Flash.Error(ctx.Tr("form.still_own_repo")) - ctx.Redirect(setting.AppSubURL + "/user/settings/delete") - case models.IsErrUserHasOrgs(err): - ctx.Flash.Error(ctx.Tr("form.still_has_org")) - ctx.Redirect(setting.AppSubURL + "/user/settings/delete") - default: - ctx.ServerError("DeleteUser", err) - } - } else { - log.Trace("Account deleted: %s", ctx.User.Name) - ctx.Redirect(setting.AppSubURL + "/") - } - return - } - - ctx.HTML(200, tplSettingsDelete) -} - // SettingsOrganization render all the organization of the user func SettingsOrganization(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("settings") diff --git a/routers/user/setting_openid.go b/routers/user/setting_openid.go index 92eb636e29..7716466120 100644 --- a/routers/user/setting_openid.go +++ b/routers/user/setting_openid.go @@ -8,40 +8,15 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/auth" "code.gitea.io/gitea/modules/auth/openid" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" ) -const ( - tplSettingsOpenID base.TplName = "user/settings/openid" -) - -// SettingsOpenID renders change user's openid page -func SettingsOpenID(ctx *context.Context) { - ctx.Data["Title"] = ctx.Tr("settings") - ctx.Data["PageIsSettingsOpenID"] = true - - if ctx.Query("openid.return_to") != "" { - settingsOpenIDVerify(ctx) - return - } - - openid, err := models.GetUserOpenIDs(ctx.User.ID) - if err != nil { - ctx.ServerError("GetUserOpenIDs", err) - return - } - ctx.Data["OpenIDs"] = openid - - ctx.HTML(200, tplSettingsOpenID) -} - // SettingsOpenIDPost response for change user's openid func SettingsOpenIDPost(ctx *context.Context, form auth.AddOpenIDForm) { ctx.Data["Title"] = ctx.Tr("settings") - ctx.Data["PageIsSettingsOpenID"] = true + ctx.Data["PageIsSettingsSecurity"] = true if ctx.HasError() { openid, err := models.GetUserOpenIDs(ctx.User.ID) @@ -50,7 +25,7 @@ func SettingsOpenIDPost(ctx *context.Context, form auth.AddOpenIDForm) { return } ctx.Data["OpenIDs"] = openid - ctx.HTML(200, tplSettingsOpenID) + ctx.HTML(200, tplSettingsSecurity) return } @@ -62,7 +37,7 @@ func SettingsOpenIDPost(ctx *context.Context, form auth.AddOpenIDForm) { id, err := openid.Normalize(form.Openid) if err != nil { - ctx.RenderWithErr(err.Error(), tplSettingsOpenID, &form) + ctx.RenderWithErr(err.Error(), tplSettingsSecurity, &form) return } form.Openid = id @@ -78,15 +53,15 @@ func SettingsOpenIDPost(ctx *context.Context, form auth.AddOpenIDForm) { // Check that the OpenID is not already used for _, obj := range oids { if obj.URI == id { - ctx.RenderWithErr(ctx.Tr("form.openid_been_used", id), tplSettingsOpenID, &form) + ctx.RenderWithErr(ctx.Tr("form.openid_been_used", id), tplSettingsSecurity, &form) return } } - redirectTo := setting.AppURL + "user/settings/openid" + redirectTo := setting.AppURL + "user/settings/security" url, err := openid.RedirectURL(id, redirectTo, setting.AppURL) if err != nil { - ctx.RenderWithErr(err.Error(), tplSettingsOpenID, &form) + ctx.RenderWithErr(err.Error(), tplSettingsSecurity, &form) return } ctx.Redirect(url) @@ -107,7 +82,7 @@ func settingsOpenIDVerify(ctx *context.Context) { id, err := openid.Verify(fullURL) if err != nil { - ctx.RenderWithErr(err.Error(), tplSettingsOpenID, &auth.AddOpenIDForm{ + ctx.RenderWithErr(err.Error(), tplSettingsSecurity, &auth.AddOpenIDForm{ Openid: id, }) return @@ -118,7 +93,7 @@ func settingsOpenIDVerify(ctx *context.Context) { oid := &models.UserOpenID{UID: ctx.User.ID, URI: id} if err = models.AddUserOpenID(oid); err != nil { if models.IsErrOpenIDAlreadyUsed(err) { - ctx.RenderWithErr(ctx.Tr("form.openid_been_used", id), tplSettingsOpenID, &auth.AddOpenIDForm{Openid: id}) + ctx.RenderWithErr(ctx.Tr("form.openid_been_used", id), tplSettingsSecurity, &auth.AddOpenIDForm{Openid: id}) return } ctx.ServerError("AddUserOpenID", err) @@ -127,7 +102,7 @@ func settingsOpenIDVerify(ctx *context.Context) { log.Trace("Associated OpenID %s to user %s", id, ctx.User.Name) ctx.Flash.Success(ctx.Tr("settings.add_openid_success")) - ctx.Redirect(setting.AppSubURL + "/user/settings/openid") + ctx.Redirect(setting.AppSubURL + "/user/settings/security") } // DeleteOpenID response for delete user's openid @@ -140,7 +115,7 @@ func DeleteOpenID(ctx *context.Context) { ctx.Flash.Success(ctx.Tr("settings.openid_deletion_success")) ctx.JSON(200, map[string]interface{}{ - "redirect": setting.AppSubURL + "/user/settings/openid", + "redirect": setting.AppSubURL + "/user/settings/security", }) } @@ -151,5 +126,5 @@ func ToggleOpenIDVisibility(ctx *context.Context) { return } - ctx.Redirect(setting.AppSubURL + "/user/settings/openid") + ctx.Redirect(setting.AppSubURL + "/user/settings/security") } diff --git a/routers/user/setting_test.go b/routers/user/setting_test.go index 72b1b83143..6aa9a07439 100644 --- a/routers/user/setting_test.go +++ b/routers/user/setting_test.go @@ -56,7 +56,7 @@ func TestChangePassword(t *testing.T) { test.LoadUser(t, ctx, 2) test.LoadRepo(t, ctx, 1) - SettingsSecurityPost(ctx, auth.ChangePasswordForm{ + SettingsAccountPost(ctx, auth.ChangePasswordForm{ OldPassword: req.OldPassword, Password: req.NewPassword, Retype: req.Retype, |