aboutsummaryrefslogtreecommitdiffstats
path: root/services/user
diff options
context:
space:
mode:
Diffstat (limited to 'services/user')
-rw-r--r--services/user/update.go39
-rw-r--r--services/user/update_test.go12
-rw-r--r--services/user/user.go5
3 files changed, 43 insertions, 13 deletions
diff --git a/services/user/update.go b/services/user/update.go
index 4a39f4f783..d7354542bf 100644
--- a/services/user/update.go
+++ b/services/user/update.go
@@ -15,6 +15,26 @@ import (
"code.gitea.io/gitea/modules/structs"
)
+type UpdateOptionField[T any] struct {
+ FieldValue T
+ FromSync bool
+}
+
+func UpdateOptionFieldFromValue[T any](value T) optional.Option[UpdateOptionField[T]] {
+ return optional.Some(UpdateOptionField[T]{FieldValue: value})
+}
+
+func UpdateOptionFieldFromSync[T any](value T) optional.Option[UpdateOptionField[T]] {
+ return optional.Some(UpdateOptionField[T]{FieldValue: value, FromSync: true})
+}
+
+func UpdateOptionFieldFromPtr[T any](value *T) optional.Option[UpdateOptionField[T]] {
+ if value == nil {
+ return optional.None[UpdateOptionField[T]]()
+ }
+ return UpdateOptionFieldFromValue(*value)
+}
+
type UpdateOptions struct {
KeepEmailPrivate optional.Option[bool]
FullName optional.Option[string]
@@ -32,7 +52,7 @@ type UpdateOptions struct {
DiffViewStyle optional.Option[string]
AllowCreateOrganization optional.Option[bool]
IsActive optional.Option[bool]
- IsAdmin optional.Option[bool]
+ IsAdmin optional.Option[UpdateOptionField[bool]]
EmailNotificationsPreference optional.Option[string]
SetLastLogin bool
RepoAdminChangeTeamAccess optional.Option[bool]
@@ -111,13 +131,18 @@ func UpdateUser(ctx context.Context, u *user_model.User, opts *UpdateOptions) er
cols = append(cols, "is_restricted")
}
if opts.IsAdmin.Has() {
- if !opts.IsAdmin.Value() && user_model.IsLastAdminUser(ctx, u) {
- return user_model.ErrDeleteLastAdminUser{UID: u.ID}
+ if opts.IsAdmin.Value().FieldValue /* true */ {
+ u.IsAdmin = opts.IsAdmin.Value().FieldValue // set IsAdmin=true
+ cols = append(cols, "is_admin")
+ } else if !user_model.IsLastAdminUser(ctx, u) /* not the last admin */ {
+ u.IsAdmin = opts.IsAdmin.Value().FieldValue // it's safe to change it from false to true (not the last admin)
+ cols = append(cols, "is_admin")
+ } else /* IsAdmin=false but this is the last admin user */ { //nolint:gocritic // make it easier to read
+ if !opts.IsAdmin.Value().FromSync {
+ return user_model.ErrDeleteLastAdminUser{UID: u.ID}
+ }
+ // else: syncing from external-source, this user is the last admin, so skip the "IsAdmin=false" change
}
-
- u.IsAdmin = opts.IsAdmin.Value()
-
- cols = append(cols, "is_admin")
}
if opts.Visibility.Has() {
diff --git a/services/user/update_test.go b/services/user/update_test.go
index fc24a6c212..27513e8040 100644
--- a/services/user/update_test.go
+++ b/services/user/update_test.go
@@ -22,7 +22,11 @@ func TestUpdateUser(t *testing.T) {
admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
assert.Error(t, UpdateUser(db.DefaultContext, admin, &UpdateOptions{
- IsAdmin: optional.Some(false),
+ IsAdmin: UpdateOptionFieldFromValue(false),
+ }))
+
+ assert.NoError(t, UpdateUser(db.DefaultContext, admin, &UpdateOptions{
+ IsAdmin: UpdateOptionFieldFromSync(false),
}))
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 28})
@@ -38,7 +42,7 @@ func TestUpdateUser(t *testing.T) {
MaxRepoCreation: optional.Some(10),
IsRestricted: optional.Some(true),
IsActive: optional.Some(false),
- IsAdmin: optional.Some(true),
+ IsAdmin: UpdateOptionFieldFromValue(true),
Visibility: optional.Some(structs.VisibleTypePrivate),
KeepActivityPrivate: optional.Some(true),
Language: optional.Some("lang"),
@@ -60,7 +64,7 @@ func TestUpdateUser(t *testing.T) {
assert.Equal(t, opts.MaxRepoCreation.Value(), user.MaxRepoCreation)
assert.Equal(t, opts.IsRestricted.Value(), user.IsRestricted)
assert.Equal(t, opts.IsActive.Value(), user.IsActive)
- assert.Equal(t, opts.IsAdmin.Value(), user.IsAdmin)
+ assert.Equal(t, opts.IsAdmin.Value().FieldValue, user.IsAdmin)
assert.Equal(t, opts.Visibility.Value(), user.Visibility)
assert.Equal(t, opts.KeepActivityPrivate.Value(), user.KeepActivityPrivate)
assert.Equal(t, opts.Language.Value(), user.Language)
@@ -80,7 +84,7 @@ func TestUpdateUser(t *testing.T) {
assert.Equal(t, opts.MaxRepoCreation.Value(), user.MaxRepoCreation)
assert.Equal(t, opts.IsRestricted.Value(), user.IsRestricted)
assert.Equal(t, opts.IsActive.Value(), user.IsActive)
- assert.Equal(t, opts.IsAdmin.Value(), user.IsAdmin)
+ assert.Equal(t, opts.IsAdmin.Value().FieldValue, user.IsAdmin)
assert.Equal(t, opts.Visibility.Value(), user.Visibility)
assert.Equal(t, opts.KeepActivityPrivate.Value(), user.KeepActivityPrivate)
assert.Equal(t, opts.Language.Value(), user.Language)
diff --git a/services/user/user.go b/services/user/user.go
index 1aeebff142..c7252430de 100644
--- a/services/user/user.go
+++ b/services/user/user.go
@@ -20,6 +20,7 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
+ "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/agit"
asymkey_service "code.gitea.io/gitea/services/asymkey"
@@ -177,8 +178,8 @@ func DeleteUser(ctx context.Context, u *user_model.User, purge bool) error {
PageSize: repo_model.RepositoryListDefaultPageSize,
Page: 1,
},
- UserID: u.ID,
- IncludePrivate: true,
+ UserID: u.ID,
+ IncludeVisibility: structs.VisibleTypePrivate,
})
if err != nil {
return fmt.Errorf("unable to find org list for %s[%d]. Error: %w", u.Name, u.ID, err)