aboutsummaryrefslogtreecommitdiffstats
path: root/routers/web/user/setting
diff options
context:
space:
mode:
Diffstat (limited to 'routers/web/user/setting')
-rw-r--r--routers/web/user/setting/account.go40
-rw-r--r--routers/web/user/setting/account_test.go2
-rw-r--r--routers/web/user/setting/applications.go5
-rw-r--r--routers/web/user/setting/keys.go14
-rw-r--r--routers/web/user/setting/notifications.go89
-rw-r--r--routers/web/user/setting/oauth2_common.go4
-rw-r--r--routers/web/user/setting/profile.go9
-rw-r--r--routers/web/user/setting/security/2fa.go11
-rw-r--r--routers/web/user/setting/security/webauthn.go3
9 files changed, 123 insertions, 54 deletions
diff --git a/routers/web/user/setting/account.go b/routers/web/user/setting/account.go
index 94577832a9..6b17da50e5 100644
--- a/routers/web/user/setting/account.go
+++ b/routers/web/user/setting/account.go
@@ -6,7 +6,6 @@ package setting
import (
"errors"
- "fmt"
"net/http"
"time"
@@ -36,15 +35,14 @@ const (
// Account renders change user's password, user's email and user suicide page
func Account(ctx *context.Context) {
- if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageCredentials, setting.UserFeatureDeletion) && !setting.Service.EnableNotifyMail {
- ctx.NotFound(fmt.Errorf("account setting are not allowed to be changed"))
+ if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageCredentials, setting.UserFeatureDeletion) {
+ ctx.NotFound(errors.New("account setting are not allowed to be changed"))
return
}
ctx.Data["Title"] = ctx.Tr("settings.account")
ctx.Data["PageIsSettingsAccount"] = true
ctx.Data["Email"] = ctx.Doer.Email
- ctx.Data["EnableNotifyMail"] = setting.Service.EnableNotifyMail
loadAccountData(ctx)
@@ -54,7 +52,7 @@ func Account(ctx *context.Context) {
// AccountPost response for change user's password
func AccountPost(ctx *context.Context) {
if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageCredentials) {
- ctx.NotFound(fmt.Errorf("password setting is not allowed to be changed"))
+ ctx.NotFound(errors.New("password setting is not allowed to be changed"))
return
}
@@ -62,7 +60,6 @@ func AccountPost(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("settings")
ctx.Data["PageIsSettingsAccount"] = true
ctx.Data["Email"] = ctx.Doer.Email
- ctx.Data["EnableNotifyMail"] = setting.Service.EnableNotifyMail
if ctx.HasError() {
loadAccountData(ctx)
@@ -105,7 +102,7 @@ func AccountPost(ctx *context.Context) {
// EmailPost response for change user's email
func EmailPost(ctx *context.Context) {
if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageCredentials) {
- ctx.NotFound(fmt.Errorf("emails are not allowed to be changed"))
+ ctx.NotFound(errors.New("emails are not allowed to be changed"))
return
}
@@ -113,7 +110,6 @@ func EmailPost(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("settings")
ctx.Data["PageIsSettingsAccount"] = true
ctx.Data["Email"] = ctx.Doer.Email
- ctx.Data["EnableNotifyMail"] = setting.Service.EnableNotifyMail
// Make email address primary.
if ctx.FormString("_method") == "PRIMARY" {
@@ -173,30 +169,6 @@ func EmailPost(ctx *context.Context) {
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
return
}
- // Set Email Notification Preference
- if ctx.FormString("_method") == "NOTIFICATION" {
- preference := ctx.FormString("preference")
- if !(preference == user_model.EmailNotificationsEnabled ||
- preference == user_model.EmailNotificationsOnMention ||
- preference == user_model.EmailNotificationsDisabled ||
- preference == user_model.EmailNotificationsAndYourOwn) {
- log.Error("Email notifications preference change returned unrecognized option %s: %s", preference, ctx.Doer.Name)
- ctx.ServerError("SetEmailPreference", errors.New("option unrecognized"))
- return
- }
- opts := &user.UpdateOptions{
- EmailNotificationsPreference: optional.Some(preference),
- }
- if err := user.UpdateUser(ctx, ctx.Doer, opts); err != nil {
- log.Error("Set Email Notifications failed: %v", err)
- ctx.ServerError("UpdateUser", err)
- return
- }
- log.Trace("Email notifications preference made %s: %s", preference, ctx.Doer.Name)
- ctx.Flash.Success(ctx.Tr("settings.email_preference_set_success"))
- ctx.Redirect(setting.AppSubURL + "/user/settings/account")
- return
- }
if ctx.HasError() {
loadAccountData(ctx)
@@ -239,7 +211,7 @@ func EmailPost(ctx *context.Context) {
// DeleteEmail response for delete user's email
func DeleteEmail(ctx *context.Context) {
if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageCredentials) {
- ctx.NotFound(fmt.Errorf("emails are not allowed to be changed"))
+ ctx.NotFound(errors.New("emails are not allowed to be changed"))
return
}
email, err := user_model.GetEmailAddressByID(ctx, ctx.Doer.ID, ctx.FormInt64("id"))
@@ -268,7 +240,6 @@ func DeleteAccount(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("settings")
ctx.Data["PageIsSettingsAccount"] = true
ctx.Data["Email"] = ctx.Doer.Email
- ctx.Data["EnableNotifyMail"] = setting.Service.EnableNotifyMail
if _, _, err := auth.UserSignIn(ctx, ctx.Doer.Name, ctx.FormString("password")); err != nil {
switch {
@@ -343,7 +314,6 @@ func loadAccountData(ctx *context.Context) {
emails[i] = &email
}
ctx.Data["Emails"] = emails
- ctx.Data["EmailNotificationsPreference"] = ctx.Doer.EmailNotificationsPreference
ctx.Data["ActivationsPending"] = pendingActivation
ctx.Data["CanAddEmails"] = !pendingActivation || !setting.Service.RegisterEmailConfirm
ctx.Data["UserDisabledFeatures"] = user_model.DisabledFeaturesWithLoginType(ctx.Doer)
diff --git a/routers/web/user/setting/account_test.go b/routers/web/user/setting/account_test.go
index 13caa33771..9b8cffc868 100644
--- a/routers/web/user/setting/account_test.go
+++ b/routers/web/user/setting/account_test.go
@@ -95,7 +95,7 @@ func TestChangePassword(t *testing.T) {
AccountPost(ctx)
assert.Contains(t, ctx.Flash.ErrorMsg, req.Message)
- assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
+ assert.Equal(t, http.StatusSeeOther, ctx.Resp.WrittenStatus())
})
}
}
diff --git a/routers/web/user/setting/applications.go b/routers/web/user/setting/applications.go
index 1f6c97a5cc..9c43ddd3ea 100644
--- a/routers/web/user/setting/applications.go
+++ b/routers/web/user/setting/applications.go
@@ -43,8 +43,9 @@ func ApplicationsPost(ctx *context.Context) {
_ = ctx.Req.ParseForm()
var scopeNames []string
+ const accessTokenScopePrefix = "scope-"
for k, v := range ctx.Req.Form {
- if strings.HasPrefix(k, "scope-") {
+ if strings.HasPrefix(k, accessTokenScopePrefix) {
scopeNames = append(scopeNames, v...)
}
}
@@ -54,7 +55,7 @@ func ApplicationsPost(ctx *context.Context) {
ctx.ServerError("GetScope", err)
return
}
- if scope == "" || scope == auth_model.AccessTokenScopePublicOnly {
+ if !scope.HasPermissionScope() {
ctx.Flash.Error(ctx.Tr("settings.at_least_one_permission"), true)
}
diff --git a/routers/web/user/setting/keys.go b/routers/web/user/setting/keys.go
index 17e32f5403..6b5a7a2e2a 100644
--- a/routers/web/user/setting/keys.go
+++ b/routers/web/user/setting/keys.go
@@ -5,7 +5,7 @@
package setting
import (
- "fmt"
+ "errors"
"net/http"
asymkey_model "code.gitea.io/gitea/models/asymkey"
@@ -26,7 +26,7 @@ const (
// Keys render user's SSH/GPG public keys page
func Keys(ctx *context.Context) {
if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageSSHKeys, setting.UserFeatureManageGPGKeys) {
- ctx.NotFound(fmt.Errorf("keys setting is not allowed to be changed"))
+ ctx.NotFound(errors.New("keys setting is not allowed to be changed"))
return
}
@@ -87,7 +87,7 @@ func KeysPost(ctx *context.Context) {
ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
case "gpg":
if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageGPGKeys) {
- ctx.NotFound(fmt.Errorf("gpg keys setting is not allowed to be visited"))
+ ctx.NotFound(errors.New("gpg keys setting is not allowed to be visited"))
return
}
@@ -168,7 +168,7 @@ func KeysPost(ctx *context.Context) {
ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
case "ssh":
if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageSSHKeys) {
- ctx.NotFound(fmt.Errorf("ssh keys setting is not allowed to be visited"))
+ ctx.NotFound(errors.New("ssh keys setting is not allowed to be visited"))
return
}
@@ -212,7 +212,7 @@ func KeysPost(ctx *context.Context) {
ctx.Redirect(setting.AppSubURL + "/user/settings/keys")
case "verify_ssh":
if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageSSHKeys) {
- ctx.NotFound(fmt.Errorf("ssh keys setting is not allowed to be visited"))
+ ctx.NotFound(errors.New("ssh keys setting is not allowed to be visited"))
return
}
@@ -249,7 +249,7 @@ func DeleteKey(ctx *context.Context) {
switch ctx.FormString("type") {
case "gpg":
if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageGPGKeys) {
- ctx.NotFound(fmt.Errorf("gpg keys setting is not allowed to be visited"))
+ ctx.NotFound(errors.New("gpg keys setting is not allowed to be visited"))
return
}
if err := asymkey_model.DeleteGPGKey(ctx, ctx.Doer, ctx.FormInt64("id")); err != nil {
@@ -259,7 +259,7 @@ func DeleteKey(ctx *context.Context) {
}
case "ssh":
if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureManageSSHKeys) {
- ctx.NotFound(fmt.Errorf("ssh keys setting is not allowed to be visited"))
+ ctx.NotFound(errors.New("ssh keys setting is not allowed to be visited"))
return
}
diff --git a/routers/web/user/setting/notifications.go b/routers/web/user/setting/notifications.go
new file mode 100644
index 0000000000..8ff6f1d941
--- /dev/null
+++ b/routers/web/user/setting/notifications.go
@@ -0,0 +1,89 @@
+// Copyright 2025 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package setting
+
+import (
+ "net/http"
+
+ "code.gitea.io/gitea/models/unit"
+ user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/optional"
+ "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/templates"
+ "code.gitea.io/gitea/services/context"
+ "code.gitea.io/gitea/services/user"
+)
+
+const tplSettingsNotifications templates.TplName = "user/settings/notifications"
+
+// Notifications render user's notifications settings
+func Notifications(ctx *context.Context) {
+ if !setting.Service.EnableNotifyMail {
+ ctx.NotFound(nil)
+ return
+ }
+
+ ctx.Data["Title"] = ctx.Tr("notifications")
+ ctx.Data["PageIsSettingsNotifications"] = true
+ ctx.Data["EmailNotificationsPreference"] = ctx.Doer.EmailNotificationsPreference
+
+ actionsEmailPref, err := user_model.GetUserSetting(ctx, ctx.Doer.ID, user_model.SettingsKeyEmailNotificationGiteaActions, user_model.SettingEmailNotificationGiteaActionsFailureOnly)
+ if err != nil {
+ ctx.ServerError("GetUserSetting", err)
+ return
+ }
+ ctx.Data["ActionsEmailNotificationsPreference"] = actionsEmailPref
+
+ ctx.HTML(http.StatusOK, tplSettingsNotifications)
+}
+
+// NotificationsEmailPost set user's email notification preference
+func NotificationsEmailPost(ctx *context.Context) {
+ if !setting.Service.EnableNotifyMail {
+ ctx.NotFound(nil)
+ return
+ }
+
+ preference := ctx.FormString("preference")
+ if !(preference == user_model.EmailNotificationsEnabled ||
+ preference == user_model.EmailNotificationsOnMention ||
+ preference == user_model.EmailNotificationsDisabled ||
+ preference == user_model.EmailNotificationsAndYourOwn) {
+ ctx.Flash.Error(ctx.Tr("invalid_data", preference))
+ ctx.Redirect(setting.AppSubURL + "/user/settings/notifications")
+ return
+ }
+ opts := &user.UpdateOptions{
+ EmailNotificationsPreference: optional.Some(preference),
+ }
+ if err := user.UpdateUser(ctx, ctx.Doer, opts); err != nil {
+ ctx.ServerError("UpdateUser", err)
+ return
+ }
+ ctx.Flash.Success(ctx.Tr("settings.email_preference_set_success"))
+ ctx.Redirect(setting.AppSubURL + "/user/settings/notifications")
+}
+
+// NotificationsActionsEmailPost set user's email notification preference on Gitea Actions
+func NotificationsActionsEmailPost(ctx *context.Context) {
+ if !setting.Actions.Enabled || unit.TypeActions.UnitGlobalDisabled() {
+ ctx.NotFound(nil)
+ return
+ }
+
+ preference := ctx.FormString("preference")
+ if !(preference == user_model.SettingEmailNotificationGiteaActionsAll ||
+ preference == user_model.SettingEmailNotificationGiteaActionsDisabled ||
+ preference == user_model.SettingEmailNotificationGiteaActionsFailureOnly) {
+ ctx.Flash.Error(ctx.Tr("invalid_data", preference))
+ ctx.Redirect(setting.AppSubURL + "/user/settings/notifications")
+ return
+ }
+ if err := user_model.SetUserSetting(ctx, ctx.Doer.ID, user_model.SettingsKeyEmailNotificationGiteaActions, preference); err != nil {
+ ctx.ServerError("SetUserSetting", err)
+ return
+ }
+ ctx.Flash.Success(ctx.Tr("settings.email_preference_set_success"))
+ ctx.Redirect(setting.AppSubURL + "/user/settings/notifications")
+}
diff --git a/routers/web/user/setting/oauth2_common.go b/routers/web/user/setting/oauth2_common.go
index d4da468a85..f460acce10 100644
--- a/routers/web/user/setting/oauth2_common.go
+++ b/routers/web/user/setting/oauth2_common.go
@@ -28,8 +28,8 @@ func (oa *OAuth2CommonHandlers) renderEditPage(ctx *context.Context) {
ctx.Data["FormActionPath"] = fmt.Sprintf("%s/%d", oa.BasePathEditPrefix, app.ID)
if ctx.ContextUser != nil && ctx.ContextUser.IsOrganization() {
- if err := shared_user.LoadHeaderCount(ctx); err != nil {
- ctx.ServerError("LoadHeaderCount", err)
+ if _, err := shared_user.RenderUserOrgHeader(ctx); err != nil {
+ ctx.ServerError("RenderUserOrgHeader", err)
return
}
}
diff --git a/routers/web/user/setting/profile.go b/routers/web/user/setting/profile.go
index 7577036a55..98995cd69c 100644
--- a/routers/web/user/setting/profile.go
+++ b/routers/web/user/setting/profile.go
@@ -22,6 +22,7 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/optional"
"code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/translation"
"code.gitea.io/gitea/modules/typesniffer"
@@ -206,8 +207,8 @@ func Organization(ctx *context.Context) {
PageSize: setting.UI.Admin.UserPagingNum,
Page: ctx.FormInt("page"),
},
- UserID: ctx.Doer.ID,
- IncludePrivate: ctx.IsSigned,
+ UserID: ctx.Doer.ID,
+ IncludeVisibility: structs.VisibleTypePrivate,
}
if opts.Page <= 0 {
@@ -284,7 +285,7 @@ func Repos(ctx *context.Context) {
return
}
- userRepos, _, err := repo_model.GetUserRepositories(ctx, &repo_model.SearchRepoOptions{
+ userRepos, _, err := repo_model.GetUserRepositories(ctx, repo_model.SearchRepoOptions{
Actor: ctxUser,
Private: true,
ListOptions: db.ListOptions{
@@ -309,7 +310,7 @@ func Repos(ctx *context.Context) {
ctx.Data["Dirs"] = repoNames
ctx.Data["ReposMap"] = repos
} else {
- repos, count64, err := repo_model.GetUserRepositories(ctx, &repo_model.SearchRepoOptions{Actor: ctxUser, Private: true, ListOptions: opts})
+ repos, count64, err := repo_model.GetUserRepositories(ctx, repo_model.SearchRepoOptions{Actor: ctxUser, Private: true, ListOptions: opts})
if err != nil {
ctx.ServerError("GetUserRepositories", err)
return
diff --git a/routers/web/user/setting/security/2fa.go b/routers/web/user/setting/security/2fa.go
index e5315efc74..e5e23c820c 100644
--- a/routers/web/user/setting/security/2fa.go
+++ b/routers/web/user/setting/security/2fa.go
@@ -15,6 +15,7 @@ import (
"code.gitea.io/gitea/models/auth"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/session"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/services/context"
@@ -163,6 +164,7 @@ func EnrollTwoFactor(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("settings")
ctx.Data["PageIsSettingsSecurity"] = true
+ ctx.Data["ShowTwoFactorRequiredMessage"] = false
t, err := auth.GetTwoFactorByUID(ctx, ctx.Doer.ID)
if t != nil {
@@ -194,6 +196,7 @@ func EnrollTwoFactorPost(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.TwoFactorAuthForm)
ctx.Data["Title"] = ctx.Tr("settings")
ctx.Data["PageIsSettingsSecurity"] = true
+ ctx.Data["ShowTwoFactorRequiredMessage"] = false
t, err := auth.GetTwoFactorByUID(ctx, ctx.Doer.ID)
if t != nil {
@@ -246,6 +249,10 @@ func EnrollTwoFactorPost(ctx *context.Context) {
return
}
+ newTwoFactorErr := auth.NewTwoFactor(ctx, t)
+ if newTwoFactorErr == nil {
+ _ = ctx.Session.Set(session.KeyUserHasTwoFactorAuth, true)
+ }
// Now we have to delete the secrets - because if we fail to insert then it's highly likely that they have already been used
// If we can detect the unique constraint failure below we can move this to after the NewTwoFactor
if err := ctx.Session.Delete("twofaSecret"); err != nil {
@@ -261,10 +268,10 @@ func EnrollTwoFactorPost(ctx *context.Context) {
log.Error("Unable to save changes to the session: %v", err)
}
- if err = auth.NewTwoFactor(ctx, t); err != nil {
+ if newTwoFactorErr != nil {
// FIXME: We need to handle a unique constraint fail here it's entirely possible that another request has beaten us.
// If there is a unique constraint fail we should just tolerate the error
- ctx.ServerError("SettingsTwoFactor: Failed to save two factor", err)
+ ctx.ServerError("SettingsTwoFactor: Failed to save two factor", newTwoFactorErr)
return
}
diff --git a/routers/web/user/setting/security/webauthn.go b/routers/web/user/setting/security/webauthn.go
index 63721343df..eb9f46af52 100644
--- a/routers/web/user/setting/security/webauthn.go
+++ b/routers/web/user/setting/security/webauthn.go
@@ -13,6 +13,7 @@ import (
user_model "code.gitea.io/gitea/models/user"
wa "code.gitea.io/gitea/modules/auth/webauthn"
"code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/session"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/services/context"
@@ -120,7 +121,7 @@ func WebauthnRegisterPost(ctx *context.Context) {
return
}
_ = ctx.Session.Delete("webauthnName")
-
+ _ = ctx.Session.Set(session.KeyUserHasTwoFactorAuth, true)
ctx.JSON(http.StatusCreated, cred)
}