code.gitea.io/gitea@v1.22.3/services/user/update.go (about) 1 // Copyright 2024 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package user 5 6 import ( 7 "context" 8 "fmt" 9 10 "code.gitea.io/gitea/models" 11 auth_model "code.gitea.io/gitea/models/auth" 12 user_model "code.gitea.io/gitea/models/user" 13 password_module "code.gitea.io/gitea/modules/auth/password" 14 "code.gitea.io/gitea/modules/optional" 15 "code.gitea.io/gitea/modules/setting" 16 "code.gitea.io/gitea/modules/structs" 17 ) 18 19 type UpdateOptions struct { 20 KeepEmailPrivate optional.Option[bool] 21 FullName optional.Option[string] 22 Website optional.Option[string] 23 Location optional.Option[string] 24 Description optional.Option[string] 25 AllowGitHook optional.Option[bool] 26 AllowImportLocal optional.Option[bool] 27 MaxRepoCreation optional.Option[int] 28 IsRestricted optional.Option[bool] 29 Visibility optional.Option[structs.VisibleType] 30 KeepActivityPrivate optional.Option[bool] 31 Language optional.Option[string] 32 Theme optional.Option[string] 33 DiffViewStyle optional.Option[string] 34 AllowCreateOrganization optional.Option[bool] 35 IsActive optional.Option[bool] 36 IsAdmin optional.Option[bool] 37 EmailNotificationsPreference optional.Option[string] 38 SetLastLogin bool 39 RepoAdminChangeTeamAccess optional.Option[bool] 40 } 41 42 func UpdateUser(ctx context.Context, u *user_model.User, opts *UpdateOptions) error { 43 cols := make([]string, 0, 20) 44 45 if opts.KeepEmailPrivate.Has() { 46 u.KeepEmailPrivate = opts.KeepEmailPrivate.Value() 47 48 cols = append(cols, "keep_email_private") 49 } 50 51 if opts.FullName.Has() { 52 u.FullName = opts.FullName.Value() 53 54 cols = append(cols, "full_name") 55 } 56 if opts.Website.Has() { 57 u.Website = opts.Website.Value() 58 59 cols = append(cols, "website") 60 } 61 if opts.Location.Has() { 62 u.Location = opts.Location.Value() 63 64 cols = append(cols, "location") 65 } 66 if opts.Description.Has() { 67 u.Description = opts.Description.Value() 68 69 cols = append(cols, "description") 70 } 71 if opts.Language.Has() { 72 u.Language = opts.Language.Value() 73 74 cols = append(cols, "language") 75 } 76 if opts.Theme.Has() { 77 u.Theme = opts.Theme.Value() 78 79 cols = append(cols, "theme") 80 } 81 if opts.DiffViewStyle.Has() { 82 u.DiffViewStyle = opts.DiffViewStyle.Value() 83 84 cols = append(cols, "diff_view_style") 85 } 86 87 if opts.AllowGitHook.Has() { 88 u.AllowGitHook = opts.AllowGitHook.Value() 89 90 cols = append(cols, "allow_git_hook") 91 } 92 if opts.AllowImportLocal.Has() { 93 u.AllowImportLocal = opts.AllowImportLocal.Value() 94 95 cols = append(cols, "allow_import_local") 96 } 97 98 if opts.MaxRepoCreation.Has() { 99 u.MaxRepoCreation = opts.MaxRepoCreation.Value() 100 101 cols = append(cols, "max_repo_creation") 102 } 103 104 if opts.IsActive.Has() { 105 u.IsActive = opts.IsActive.Value() 106 107 cols = append(cols, "is_active") 108 } 109 if opts.IsRestricted.Has() { 110 u.IsRestricted = opts.IsRestricted.Value() 111 112 cols = append(cols, "is_restricted") 113 } 114 if opts.IsAdmin.Has() { 115 if !opts.IsAdmin.Value() && user_model.IsLastAdminUser(ctx, u) { 116 return models.ErrDeleteLastAdminUser{UID: u.ID} 117 } 118 119 u.IsAdmin = opts.IsAdmin.Value() 120 121 cols = append(cols, "is_admin") 122 } 123 124 if opts.Visibility.Has() { 125 if !u.IsOrganization() && !setting.Service.AllowedUserVisibilityModesSlice.IsAllowedVisibility(opts.Visibility.Value()) { 126 return fmt.Errorf("visibility mode not allowed: %s", opts.Visibility.Value().String()) 127 } 128 u.Visibility = opts.Visibility.Value() 129 130 cols = append(cols, "visibility") 131 } 132 if opts.KeepActivityPrivate.Has() { 133 u.KeepActivityPrivate = opts.KeepActivityPrivate.Value() 134 135 cols = append(cols, "keep_activity_private") 136 } 137 138 if opts.AllowCreateOrganization.Has() { 139 u.AllowCreateOrganization = opts.AllowCreateOrganization.Value() 140 141 cols = append(cols, "allow_create_organization") 142 } 143 if opts.RepoAdminChangeTeamAccess.Has() { 144 u.RepoAdminChangeTeamAccess = opts.RepoAdminChangeTeamAccess.Value() 145 146 cols = append(cols, "repo_admin_change_team_access") 147 } 148 149 if opts.EmailNotificationsPreference.Has() { 150 u.EmailNotificationsPreference = opts.EmailNotificationsPreference.Value() 151 152 cols = append(cols, "email_notifications_preference") 153 } 154 155 if opts.SetLastLogin { 156 u.SetLastLogin() 157 158 cols = append(cols, "last_login_unix") 159 } 160 161 return user_model.UpdateUserCols(ctx, u, cols...) 162 } 163 164 type UpdateAuthOptions struct { 165 LoginSource optional.Option[int64] 166 LoginName optional.Option[string] 167 Password optional.Option[string] 168 MustChangePassword optional.Option[bool] 169 ProhibitLogin optional.Option[bool] 170 } 171 172 func UpdateAuth(ctx context.Context, u *user_model.User, opts *UpdateAuthOptions) error { 173 if opts.LoginSource.Has() { 174 source, err := auth_model.GetSourceByID(ctx, opts.LoginSource.Value()) 175 if err != nil { 176 return err 177 } 178 179 u.LoginType = source.Type 180 u.LoginSource = source.ID 181 } 182 if opts.LoginName.Has() { 183 u.LoginName = opts.LoginName.Value() 184 } 185 186 deleteAuthTokens := false 187 if opts.Password.Has() && (u.IsLocal() || u.IsOAuth2()) { 188 password := opts.Password.Value() 189 190 if len(password) < setting.MinPasswordLength { 191 return password_module.ErrMinLength 192 } 193 if !password_module.IsComplexEnough(password) { 194 return password_module.ErrComplexity 195 } 196 if err := password_module.IsPwned(ctx, password); err != nil { 197 return err 198 } 199 200 if err := u.SetPassword(password); err != nil { 201 return err 202 } 203 204 deleteAuthTokens = true 205 } 206 207 if opts.MustChangePassword.Has() { 208 u.MustChangePassword = opts.MustChangePassword.Value() 209 } 210 if opts.ProhibitLogin.Has() { 211 u.ProhibitLogin = opts.ProhibitLogin.Value() 212 } 213 214 if err := user_model.UpdateUserCols(ctx, u, "login_type", "login_source", "login_name", "passwd", "passwd_hash_algo", "salt", "must_change_password", "prohibit_login"); err != nil { 215 return err 216 } 217 218 if deleteAuthTokens { 219 return auth_model.DeleteAuthTokensByUserID(ctx, u.ID) 220 } 221 return nil 222 }