This commit is contained in:
@@ -10,11 +10,11 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/avatar"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/storage"
|
||||
"gitea.dev/models/db"
|
||||
user_model "gitea.dev/models/user"
|
||||
"gitea.dev/modules/avatar"
|
||||
"gitea.dev/modules/log"
|
||||
"gitea.dev/modules/storage"
|
||||
)
|
||||
|
||||
// UploadAvatar saves custom avatar for user.
|
||||
|
||||
@@ -6,12 +6,12 @@ package user
|
||||
import (
|
||||
"context"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
org_model "code.gitea.io/gitea/models/organization"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
repo_service "code.gitea.io/gitea/services/repository"
|
||||
"gitea.dev/models/db"
|
||||
issues_model "gitea.dev/models/issues"
|
||||
org_model "gitea.dev/models/organization"
|
||||
repo_model "gitea.dev/models/repo"
|
||||
user_model "gitea.dev/models/user"
|
||||
repo_service "gitea.dev/services/repository"
|
||||
)
|
||||
|
||||
func CanBlockUser(ctx context.Context, doer, blocker, blockee *user_model.User) bool {
|
||||
|
||||
@@ -6,8 +6,8 @@ package user
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"gitea.dev/models/unittest"
|
||||
user_model "gitea.dev/models/user"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -8,26 +8,26 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
_ "image/jpeg" // Needed for jpeg support
|
||||
actions_model "gitea.dev/models/actions"
|
||||
activities_model "gitea.dev/models/activities"
|
||||
asymkey_model "gitea.dev/models/asymkey"
|
||||
auth_model "gitea.dev/models/auth"
|
||||
"gitea.dev/models/db"
|
||||
git_model "gitea.dev/models/git"
|
||||
issues_model "gitea.dev/models/issues"
|
||||
"gitea.dev/models/organization"
|
||||
access_model "gitea.dev/models/perm/access"
|
||||
pull_model "gitea.dev/models/pull"
|
||||
repo_model "gitea.dev/models/repo"
|
||||
user_model "gitea.dev/models/user"
|
||||
"gitea.dev/modules/setting"
|
||||
|
||||
actions_model "code.gitea.io/gitea/models/actions"
|
||||
activities_model "code.gitea.io/gitea/models/activities"
|
||||
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
||||
auth_model "code.gitea.io/gitea/models/auth"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
git_model "code.gitea.io/gitea/models/git"
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
"code.gitea.io/gitea/models/organization"
|
||||
access_model "code.gitea.io/gitea/models/perm/access"
|
||||
pull_model "code.gitea.io/gitea/models/pull"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
_ "image/jpeg" // Needed for jpeg support
|
||||
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
// deleteUser deletes models associated to an user.
|
||||
// deleteUser deletes models associated to a user.
|
||||
func deleteUser(ctx context.Context, u *user_model.User, purge bool) (err error) {
|
||||
e := db.GetEngine(ctx)
|
||||
|
||||
@@ -95,6 +95,11 @@ func deleteUser(ctx context.Context, u *user_model.User, purge bool) (err error)
|
||||
&user_model.Blocking{BlockerID: u.ID},
|
||||
&user_model.Blocking{BlockeeID: u.ID},
|
||||
&actions_model.ActionRunnerToken{OwnerID: u.ID},
|
||||
&actions_model.ActionScopedWorkflowSource{OwnerID: u.ID},
|
||||
&auth_model.TwoFactor{UID: u.ID},
|
||||
&auth_model.WebAuthnCredential{UserID: u.ID},
|
||||
&activities_model.Notification{UserID: u.ID},
|
||||
&issues_model.IssueWatch{UserID: u.ID},
|
||||
); err != nil {
|
||||
return fmt.Errorf("deleteBeans: %w", err)
|
||||
}
|
||||
|
||||
@@ -8,10 +8,10 @@ import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"gitea.dev/models/db"
|
||||
user_model "gitea.dev/models/user"
|
||||
"gitea.dev/modules/setting"
|
||||
"gitea.dev/modules/util"
|
||||
)
|
||||
|
||||
// ReplacePrimaryEmailAddress replaces the user's primary email address with the given email address.
|
||||
|
||||
@@ -6,8 +6,8 @@ package user
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"gitea.dev/models/unittest"
|
||||
user_model "gitea.dev/models/user"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -7,13 +7,13 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
auth_model "code.gitea.io/gitea/models/auth"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
password_module "code.gitea.io/gitea/modules/auth/password"
|
||||
"code.gitea.io/gitea/modules/optional"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
auth_model "gitea.dev/models/auth"
|
||||
"gitea.dev/models/db"
|
||||
user_model "gitea.dev/models/user"
|
||||
password_module "gitea.dev/modules/auth/password"
|
||||
"gitea.dev/modules/optional"
|
||||
"gitea.dev/modules/setting"
|
||||
"gitea.dev/modules/structs"
|
||||
)
|
||||
|
||||
type UpdateOptionField[T any] struct {
|
||||
@@ -147,7 +147,8 @@ func UpdateUser(ctx context.Context, u *user_model.User, opts *UpdateOptions) er
|
||||
}
|
||||
}
|
||||
|
||||
if opts.Visibility.Has() {
|
||||
// only validate and persist the visibility when it actually changes
|
||||
if opts.Visibility.Has() && opts.Visibility.Value() != u.Visibility {
|
||||
if !u.IsOrganization() && !setting.Service.AllowedUserVisibilityModesSlice.IsAllowedVisibility(opts.Visibility.Value()) {
|
||||
return fmt.Errorf("visibility mode not allowed: %s", opts.Visibility.Value().String())
|
||||
}
|
||||
|
||||
@@ -6,11 +6,13 @@ package user
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
password_module "code.gitea.io/gitea/modules/auth/password"
|
||||
"code.gitea.io/gitea/modules/optional"
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
"gitea.dev/models/unittest"
|
||||
user_model "gitea.dev/models/user"
|
||||
password_module "gitea.dev/modules/auth/password"
|
||||
"gitea.dev/modules/optional"
|
||||
"gitea.dev/modules/setting"
|
||||
"gitea.dev/modules/structs"
|
||||
"gitea.dev/modules/test"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -128,3 +130,33 @@ func TestUpdateAuth(t *testing.T) {
|
||||
Password: optional.Some("aaaa"),
|
||||
}), password_module.ErrMinLength)
|
||||
}
|
||||
|
||||
func TestUpdateUserVisibility(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
// user28's current visibility is public, e.g. an account created before public was disallowed
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 28})
|
||||
assert.Equal(t, structs.VisibleTypePublic, user.Visibility)
|
||||
|
||||
// public is no longer an allowed visibility mode, e.g. ALLOWED_USER_VISIBILITY_MODES = limited, private
|
||||
defer test.MockVariableValue(&setting.Service.AllowedUserVisibilityModesSlice, setting.AllowedVisibility{false, true, true})()
|
||||
|
||||
// re-submitting the unchanged (now-disallowed) visibility must not fail the whole update
|
||||
assert.NoError(t, UpdateUser(t.Context(), user, &UpdateOptions{
|
||||
FullName: optional.Some("Changed Name"),
|
||||
Visibility: optional.Some(structs.VisibleTypePublic),
|
||||
}))
|
||||
assert.Equal(t, "Changed Name", user.FullName)
|
||||
assert.Equal(t, structs.VisibleTypePublic, user.Visibility)
|
||||
|
||||
// changing to an allowed visibility still works
|
||||
assert.NoError(t, UpdateUser(t.Context(), user, &UpdateOptions{
|
||||
Visibility: optional.Some(structs.VisibleTypePrivate),
|
||||
}))
|
||||
assert.Equal(t, structs.VisibleTypePrivate, user.Visibility)
|
||||
|
||||
// genuinely changing to a disallowed visibility is still rejected
|
||||
assert.Error(t, UpdateUser(t.Context(), user, &UpdateOptions{
|
||||
Visibility: optional.Some(structs.VisibleTypePublic),
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -10,24 +10,24 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/organization"
|
||||
packages_model "code.gitea.io/gitea/models/packages"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
system_model "code.gitea.io/gitea/models/system"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/eventsource"
|
||||
"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"
|
||||
org_service "code.gitea.io/gitea/services/org"
|
||||
"code.gitea.io/gitea/services/packages"
|
||||
container_service "code.gitea.io/gitea/services/packages/container"
|
||||
repo_service "code.gitea.io/gitea/services/repository"
|
||||
"gitea.dev/models/db"
|
||||
"gitea.dev/models/organization"
|
||||
packages_model "gitea.dev/models/packages"
|
||||
repo_model "gitea.dev/models/repo"
|
||||
system_model "gitea.dev/models/system"
|
||||
user_model "gitea.dev/models/user"
|
||||
"gitea.dev/modules/eventsource"
|
||||
"gitea.dev/modules/log"
|
||||
"gitea.dev/modules/setting"
|
||||
"gitea.dev/modules/storage"
|
||||
"gitea.dev/modules/structs"
|
||||
"gitea.dev/modules/util"
|
||||
"gitea.dev/services/agit"
|
||||
asymkey_service "gitea.dev/services/asymkey"
|
||||
org_service "gitea.dev/services/org"
|
||||
"gitea.dev/services/packages"
|
||||
container_service "gitea.dev/services/packages/container"
|
||||
repo_service "gitea.dev/services/repository"
|
||||
)
|
||||
|
||||
// RenameUser renames a user
|
||||
@@ -108,7 +108,7 @@ func RenameUser(ctx context.Context, u *user_model.User, newUserName string, doe
|
||||
u.Name = oldUserName
|
||||
u.LowerName = strings.ToLower(oldUserName)
|
||||
if err2 := util.Rename(user_model.UserPath(newUserName), user_model.UserPath(oldUserName)); err2 != nil && !os.IsNotExist(err2) {
|
||||
log.Critical("Unable to rollback directory change during failed username change from: %s to: %s. DB Error: %v. Filesystem Error: %v", oldUserName, newUserName, err, err2)
|
||||
log.Error("Unable to rollback directory change during failed username change from: %s to: %s. DB Error: %v. Filesystem Error: %v", oldUserName, newUserName, err, err2)
|
||||
return fmt.Errorf("failed to rollback directory change during failed username change from: %s to: %s. DB Error: %w. Filesystem Error: %v", oldUserName, newUserName, err, err2)
|
||||
}
|
||||
return err
|
||||
|
||||
@@ -9,15 +9,17 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models/auth"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/organization"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
org_service "code.gitea.io/gitea/services/org"
|
||||
activities_model "gitea.dev/models/activities"
|
||||
"gitea.dev/models/auth"
|
||||
"gitea.dev/models/db"
|
||||
issues_model "gitea.dev/models/issues"
|
||||
"gitea.dev/models/organization"
|
||||
repo_model "gitea.dev/models/repo"
|
||||
"gitea.dev/models/unittest"
|
||||
user_model "gitea.dev/models/user"
|
||||
"gitea.dev/modules/setting"
|
||||
"gitea.dev/modules/timeutil"
|
||||
org_service "gitea.dev/services/org"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -61,6 +63,32 @@ func TestDeleteUser(t *testing.T) {
|
||||
|
||||
org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3})
|
||||
assert.Error(t, DeleteUser(t.Context(), org, false))
|
||||
|
||||
t.Run("CleanupOrphanedTables", func(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
// assert they exist before deletion
|
||||
unittest.AssertExistsAndLoadBean(t, &auth.TwoFactor{UID: 24})
|
||||
unittest.AssertExistsAndLoadBean(t, &auth.WebAuthnCredential{UserID: 32})
|
||||
unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{UserID: 2})
|
||||
unittest.AssertExistsAndLoadBean(t, &issues_model.IssueWatch{UserID: 2})
|
||||
|
||||
// delete users
|
||||
user24 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 24})
|
||||
assert.NoError(t, DeleteUser(t.Context(), user24, true))
|
||||
|
||||
user32 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 32})
|
||||
assert.NoError(t, DeleteUser(t.Context(), user32, true))
|
||||
|
||||
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
assert.NoError(t, DeleteUser(t.Context(), user2, true))
|
||||
|
||||
// assert they do not exist after deletion
|
||||
unittest.AssertNotExistsBean(t, &auth.TwoFactor{UID: 24})
|
||||
unittest.AssertNotExistsBean(t, &auth.WebAuthnCredential{UserID: 32})
|
||||
unittest.AssertNotExistsBean(t, &activities_model.Notification{UserID: 2})
|
||||
unittest.AssertNotExistsBean(t, &issues_model.IssueWatch{UserID: 2})
|
||||
})
|
||||
}
|
||||
|
||||
func TestDeleteUserUnlinkedAttachments(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user