diff options
Diffstat (limited to 'models')
-rw-r--r-- | models/admin/notice.go | 33 | ||||
-rw-r--r-- | models/admin/notice_test.go | 3 | ||||
-rw-r--r-- | models/consistency.go | 2 | ||||
-rw-r--r-- | models/org.go | 64 | ||||
-rw-r--r-- | models/org_test.go | 18 | ||||
-rw-r--r-- | models/repo.go | 20 | ||||
-rw-r--r-- | models/repo_test.go | 2 | ||||
-rw-r--r-- | models/user.go | 110 | ||||
-rw-r--r-- | models/user/email_address.go | 8 | ||||
-rw-r--r-- | models/user_test.go | 80 |
10 files changed, 54 insertions, 286 deletions
diff --git a/models/admin/notice.go b/models/admin/notice.go index c41e49ed8c..2d71b426dd 100644 --- a/models/admin/notice.go +++ b/models/admin/notice.go @@ -43,12 +43,7 @@ func (n *Notice) TrStr() string { } // CreateNotice creates new system notice. -func CreateNotice(tp NoticeType, desc string, args ...interface{}) error { - return CreateNoticeCtx(db.DefaultContext, tp, desc, args...) -} - -// CreateNoticeCtx creates new system notice. -func CreateNoticeCtx(ctx context.Context, tp NoticeType, desc string, args ...interface{}) error { +func CreateNotice(ctx context.Context, tp NoticeType, desc string, args ...interface{}) error { if len(args) > 0 { desc = fmt.Sprintf(desc, args...) } @@ -61,38 +56,28 @@ func CreateNoticeCtx(ctx context.Context, tp NoticeType, desc string, args ...in // CreateRepositoryNotice creates new system notice with type NoticeRepository. func CreateRepositoryNotice(desc string, args ...interface{}) error { - return CreateNoticeCtx(db.DefaultContext, NoticeRepository, desc, args...) + return CreateNotice(db.DefaultContext, NoticeRepository, desc, args...) } // RemoveAllWithNotice removes all directories in given path and // creates a system notice when error occurs. -func RemoveAllWithNotice(title, path string) { - RemoveAllWithNoticeCtx(db.DefaultContext, title, path) -} - -// RemoveStorageWithNotice removes a file from the storage and -// creates a system notice when error occurs. -func RemoveStorageWithNotice(bucket storage.ObjectStorage, title, path string) { - removeStorageWithNotice(db.DefaultContext, bucket, title, path) -} - -func removeStorageWithNotice(ctx context.Context, bucket storage.ObjectStorage, title, path string) { - if err := bucket.Delete(path); err != nil { +func RemoveAllWithNotice(ctx context.Context, title, path string) { + if err := util.RemoveAll(path); err != nil { desc := fmt.Sprintf("%s [%s]: %v", title, path, err) log.Warn(title+" [%s]: %v", path, err) - if err = CreateNoticeCtx(ctx, NoticeRepository, desc); err != nil { + if err = CreateNotice(ctx, NoticeRepository, desc); err != nil { log.Error("CreateRepositoryNotice: %v", err) } } } -// RemoveAllWithNoticeCtx removes all directories in given path and +// RemoveStorageWithNotice removes a file from the storage and // creates a system notice when error occurs. -func RemoveAllWithNoticeCtx(ctx context.Context, title, path string) { - if err := util.RemoveAll(path); err != nil { +func RemoveStorageWithNotice(ctx context.Context, bucket storage.ObjectStorage, title, path string) { + if err := bucket.Delete(path); err != nil { desc := fmt.Sprintf("%s [%s]: %v", title, path, err) log.Warn(title+" [%s]: %v", path, err) - if err = CreateNoticeCtx(ctx, NoticeRepository, desc); err != nil { + if err = CreateNotice(ctx, NoticeRepository, desc); err != nil { log.Error("CreateRepositoryNotice: %v", err) } } diff --git a/models/admin/notice_test.go b/models/admin/notice_test.go index 7272df4368..b4613db8e7 100644 --- a/models/admin/notice_test.go +++ b/models/admin/notice_test.go @@ -7,6 +7,7 @@ package admin import ( "testing" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unittest" "github.com/stretchr/testify/assert" @@ -28,7 +29,7 @@ func TestCreateNotice(t *testing.T) { Description: "test description", } unittest.AssertNotExistsBean(t, noticeBean) - assert.NoError(t, CreateNotice(noticeBean.Type, noticeBean.Description)) + assert.NoError(t, CreateNotice(db.DefaultContext, noticeBean.Type, noticeBean.Description)) unittest.AssertExistsAndLoadBean(t, noticeBean) } diff --git a/models/consistency.go b/models/consistency.go index 83cfbd0e49..ba669628b9 100644 --- a/models/consistency.go +++ b/models/consistency.go @@ -128,7 +128,7 @@ func DeleteOrphanedIssues() error { // Remove issue attachment files. for i := range attachmentPaths { - admin_model.RemoveAllWithNoticeCtx(db.DefaultContext, "Delete issue attachment", attachmentPaths[i]) + admin_model.RemoveAllWithNotice(db.DefaultContext, "Delete issue attachment", attachmentPaths[i]) } return nil } diff --git a/models/org.go b/models/org.go index 1840cae9fa..e0b4d27245 100644 --- a/models/org.go +++ b/models/org.go @@ -6,6 +6,7 @@ package models import ( + "context" "fmt" "strings" @@ -14,9 +15,7 @@ import ( user_model "code.gitea.io/gitea/models/user" "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" "xorm.io/builder" "xorm.io/xorm" @@ -254,68 +253,23 @@ func CountOrganizations() int64 { return count } -// DeleteOrganization completely and permanently deletes everything of organization. -func DeleteOrganization(org *User) (err error) { - if !org.IsOrganization() { - return fmt.Errorf("%s is a user not an organization", org.Name) - } - - sess := db.NewSession(db.DefaultContext) - defer sess.Close() - - if err = sess.Begin(); err != nil { - return err - } - - if err = deleteOrg(sess, org); err != nil { - if IsErrUserOwnRepos(err) { - return err - } else if err != nil { - return fmt.Errorf("deleteOrg: %v", err) - } - } - - return sess.Commit() -} - -func deleteOrg(e *xorm.Session, u *User) error { - // Check ownership of repository. - count, err := getRepositoryCount(e, u) - if err != nil { - return fmt.Errorf("GetRepositoryCount: %v", err) - } else if count > 0 { - return ErrUserOwnRepos{UID: u.ID} - } +// DeleteOrganization deletes models associated to an organization. +func DeleteOrganization(ctx context.Context, org *User) error { + e := db.GetEngine(ctx) if err := deleteBeans(e, - &Team{OrgID: u.ID}, - &OrgUser{OrgID: u.ID}, - &TeamUser{OrgID: u.ID}, - &TeamUnit{OrgID: u.ID}, + &Team{OrgID: org.ID}, + &OrgUser{OrgID: org.ID}, + &TeamUser{OrgID: org.ID}, + &TeamUnit{OrgID: org.ID}, ); err != nil { return fmt.Errorf("deleteBeans: %v", err) } - if _, err = e.ID(u.ID).Delete(new(User)); err != nil { + if _, err := e.ID(org.ID).Delete(new(User)); err != nil { return fmt.Errorf("Delete: %v", err) } - // FIXME: system notice - // Note: There are something just cannot be roll back, - // so just keep error logs of those operations. - path := UserPath(u.Name) - - if err := util.RemoveAll(path); err != nil { - return fmt.Errorf("Failed to RemoveAll %s: %v", path, err) - } - - if len(u.Avatar) > 0 { - avatarPath := u.CustomAvatarRelativePath() - if err := storage.Avatars.Delete(avatarPath); err != nil { - return fmt.Errorf("Failed to remove %s: %v", avatarPath, err) - } - } - return nil } diff --git a/models/org_test.go b/models/org_test.go index 2bc4d74fc3..8580702a06 100644 --- a/models/org_test.go +++ b/models/org_test.go @@ -261,24 +261,6 @@ func TestCountOrganizations(t *testing.T) { assert.Equal(t, expected, CountOrganizations()) } -func TestDeleteOrganization(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - org := unittest.AssertExistsAndLoadBean(t, &User{ID: 6}).(*User) - assert.NoError(t, DeleteOrganization(org)) - unittest.AssertNotExistsBean(t, &User{ID: 6}) - unittest.AssertNotExistsBean(t, &OrgUser{OrgID: 6}) - unittest.AssertNotExistsBean(t, &Team{OrgID: 6}) - - org = unittest.AssertExistsAndLoadBean(t, &User{ID: 3}).(*User) - err := DeleteOrganization(org) - assert.Error(t, err) - assert.True(t, IsErrUserOwnRepos(err)) - - user := unittest.AssertExistsAndLoadBean(t, &User{ID: 5}).(*User) - assert.Error(t, DeleteOrganization(user)) - unittest.CheckConsistencyFor(t, &User{}, &Team{}) -} - func TestIsOrganizationOwner(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) test := func(orgID, userID int64, expected bool) { diff --git a/models/repo.go b/models/repo.go index 57806a86f7..d62b3ec2b4 100644 --- a/models/repo.go +++ b/models/repo.go @@ -134,7 +134,7 @@ func NewRepoContext() { loadRepoConfig() unit.LoadUnitConfig() - admin_model.RemoveAllWithNotice("Clean up repository temporary data", filepath.Join(setting.AppDataPath, "tmp")) + admin_model.RemoveAllWithNotice(db.DefaultContext, "Clean up repository temporary data", filepath.Join(setting.AppDataPath, "tmp")) } // RepositoryStatus defines the status of repository @@ -1649,36 +1649,36 @@ func DeleteRepository(doer *User, uid, repoID int64) error { // Remove repository files. repoPath := repo.RepoPath() - admin_model.RemoveAllWithNotice("Delete repository files", repoPath) + admin_model.RemoveAllWithNotice(db.DefaultContext, "Delete repository files", repoPath) // Remove wiki files if repo.HasWiki() { - admin_model.RemoveAllWithNotice("Delete repository wiki", repo.WikiPath()) + admin_model.RemoveAllWithNotice(db.DefaultContext, "Delete repository wiki", repo.WikiPath()) } // Remove archives for i := range archivePaths { - admin_model.RemoveStorageWithNotice(storage.RepoArchives, "Delete repo archive file", archivePaths[i]) + admin_model.RemoveStorageWithNotice(db.DefaultContext, storage.RepoArchives, "Delete repo archive file", archivePaths[i]) } // Remove lfs objects for i := range lfsPaths { - admin_model.RemoveStorageWithNotice(storage.LFS, "Delete orphaned LFS file", lfsPaths[i]) + admin_model.RemoveStorageWithNotice(db.DefaultContext, storage.LFS, "Delete orphaned LFS file", lfsPaths[i]) } // Remove issue attachment files. for i := range attachmentPaths { - admin_model.RemoveStorageWithNotice(storage.Attachments, "Delete issue attachment", attachmentPaths[i]) + admin_model.RemoveStorageWithNotice(db.DefaultContext, storage.Attachments, "Delete issue attachment", attachmentPaths[i]) } // Remove release attachment files. for i := range releaseAttachments { - admin_model.RemoveStorageWithNotice(storage.Attachments, "Delete release attachment", releaseAttachments[i]) + admin_model.RemoveStorageWithNotice(db.DefaultContext, storage.Attachments, "Delete release attachment", releaseAttachments[i]) } // Remove attachment with no issue_id and release_id. for i := range newAttachmentPaths { - admin_model.RemoveStorageWithNotice(storage.Attachments, "Delete issue attachment", attachmentPaths[i]) + admin_model.RemoveStorageWithNotice(db.DefaultContext, storage.Attachments, "Delete issue attachment", attachmentPaths[i]) } if len(repo.Avatar) > 0 { @@ -1803,8 +1803,8 @@ func getPrivateRepositoryCount(e db.Engine, u *User) (int64, error) { } // GetRepositoryCount returns the total number of repositories of user. -func GetRepositoryCount(u *User) (int64, error) { - return getRepositoryCount(db.GetEngine(db.DefaultContext), u) +func GetRepositoryCount(ctx context.Context, u *User) (int64, error) { + return getRepositoryCount(db.GetEngine(ctx), u) } // GetPublicRepositoryCount returns the total number of public repositories of user. diff --git a/models/repo_test.go b/models/repo_test.go index 685570adc8..e6f4ea1c3f 100644 --- a/models/repo_test.go +++ b/models/repo_test.go @@ -71,7 +71,7 @@ func TestMetas(t *testing.T) { func TestGetRepositoryCount(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - count, err1 := GetRepositoryCount(&User{ID: int64(10)}) + count, err1 := GetRepositoryCount(db.DefaultContext, &User{ID: int64(10)}) privateCount, err2 := GetPrivateRepositoryCount(&User{ID: int64(10)}) publicCount, err3 := GetPublicRepositoryCount(&User{ID: int64(10)}) assert.NoError(t, err1) diff --git a/models/user.go b/models/user.go index cc6c5a5578..1bdb435793 100644 --- a/models/user.go +++ b/models/user.go @@ -22,7 +22,6 @@ import ( _ "image/jpeg" // Needed for jpeg support - admin_model "code.gitea.io/gitea/models/admin" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/login" "code.gitea.io/gitea/models/unit" @@ -32,7 +31,6 @@ import ( "code.gitea.io/gitea/modules/git" "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/timeutil" "code.gitea.io/gitea/modules/util" @@ -542,15 +540,16 @@ func (u *User) IsPublicMember(orgID int64) bool { return isMember } -func (u *User) getOrganizationCount(e db.Engine) (int64, error) { - return e. +// GetOrganizationCount returns count of membership of organization of the user. +func GetOrganizationCount(ctx context.Context, u *User) (int64, error) { + return db.GetEngine(ctx). Where("uid=?", u.ID). Count(new(OrgUser)) } // GetOrganizationCount returns count of membership of organization of user. func (u *User) GetOrganizationCount() (int64, error) { - return u.getOrganizationCount(db.GetEngine(db.DefaultContext)) + return GetOrganizationCount(db.DefaultContext, u) } // GetRepositories returns repositories that user owns, including private repositories. @@ -1149,26 +1148,9 @@ func deleteBeans(e db.Engine, beans ...interface{}) (err error) { return nil } -func deleteUser(ctx context.Context, u *User) error { +// DeleteUser deletes models associated to an user. +func DeleteUser(ctx context.Context, u *User) (err error) { e := db.GetEngine(ctx) - // Note: A user owns any repository or belongs to any organization - // cannot perform delete operation. - - // Check ownership of repository. - count, err := getRepositoryCount(e, u) - if err != nil { - return fmt.Errorf("GetRepositoryCount: %v", err) - } else if count > 0 { - return ErrUserOwnRepos{UID: u.ID} - } - - // Check membership of organization. - count, err = u.getOrganizationCount(e) - if err != nil { - return fmt.Errorf("GetOrganizationCount: %v", err) - } else if count > 0 { - return ErrUserHasOrgs{UID: u.ID} - } // ***** START: Watch ***** watchedRepoIDs := make([]int64, 0, 10) @@ -1301,85 +1283,21 @@ func deleteUser(ctx context.Context, u *User) error { return fmt.Errorf("Delete: %v", err) } - // Note: There are something just cannot be roll back, - // so just keep error logs of those operations. - path := UserPath(u.Name) - if err = util.RemoveAll(path); err != nil { - err = fmt.Errorf("Failed to RemoveAll %s: %v", path, err) - _ = admin_model.CreateNoticeCtx(ctx, admin_model.NoticeTask, fmt.Sprintf("delete user '%s': %v", u.Name, err)) - return err - } - - if len(u.Avatar) > 0 { - avatarPath := u.CustomAvatarRelativePath() - if err = storage.Avatars.Delete(avatarPath); err != nil { - err = fmt.Errorf("Failed to remove %s: %v", avatarPath, err) - _ = admin_model.CreateNoticeCtx(ctx, admin_model.NoticeTask, fmt.Sprintf("delete user '%s': %v", u.Name, err)) - return err - } - } - return nil } -// DeleteUser completely and permanently deletes everything of a user, -// but issues/comments/pulls will be kept and shown as someone has been deleted, -// unless the user is younger than USER_DELETE_WITH_COMMENTS_MAX_DAYS. -func DeleteUser(u *User) (err error) { - if u.IsOrganization() { - return fmt.Errorf("%s is an organization not a user", u.Name) - } - - ctx, committer, err := db.TxContext() - if err != nil { - return err - } - defer committer.Close() - - if err = deleteUser(ctx, u); err != nil { - // Note: don't wrapper error here. - return err - } - - return committer.Commit() -} +// GetInactiveUsers gets all inactive users +func GetInactiveUsers(ctx context.Context, olderThan time.Duration) ([]*User, error) { + var cond builder.Cond = builder.Eq{"is_active": false} -// DeleteInactiveUsers deletes all inactive users and email addresses. -func DeleteInactiveUsers(ctx context.Context, olderThan time.Duration) (err error) { - users := make([]*User, 0, 10) if olderThan > 0 { - if err = db.GetEngine(db.DefaultContext). - Where("is_active = ? and created_unix < ?", false, time.Now().Add(-olderThan).Unix()). - Find(&users); err != nil { - return fmt.Errorf("get all inactive users: %v", err) - } - } else { - if err = db.GetEngine(db.DefaultContext). - Where("is_active = ?", false). - Find(&users); err != nil { - return fmt.Errorf("get all inactive users: %v", err) - } - } - // FIXME: should only update authorized_keys file once after all deletions. - for _, u := range users { - select { - case <-ctx.Done(): - return db.ErrCancelledf("Before delete inactive user %s", u.Name) - default: - } - if err = DeleteUser(u); err != nil { - // Ignore users that were set inactive by admin. - if IsErrUserOwnRepos(err) || IsErrUserHasOrgs(err) { - continue - } - return err - } + cond = cond.And(builder.Lt{"created_unix": time.Now().Add(-olderThan).Unix()}) } - _, err = db.GetEngine(db.DefaultContext). - Where("is_activated = ?", false). - Delete(new(user_model.EmailAddress)) - return err + users := make([]*User, 0, 10) + return users, db.GetEngine(ctx). + Where(cond). + Find(&users) } // UserPath returns the path absolute path of user repositories. diff --git a/models/user/email_address.go b/models/user/email_address.go index 74fb71d454..98cd14a6a5 100644 --- a/models/user/email_address.go +++ b/models/user/email_address.go @@ -267,3 +267,11 @@ func DeleteEmailAddresses(emails []*EmailAddress) (err error) { return nil } + +// DeleteInactiveEmailAddresses deletes inactive email addresses +func DeleteInactiveEmailAddresses(ctx context.Context) error { + _, err := db.GetEngine(ctx). + Where("is_activated = ?", false). + Delete(new(EmailAddress)) + return err +} diff --git a/models/user_test.go b/models/user_test.go index 4e2e521767..2da5519d74 100644 --- a/models/user_test.go +++ b/models/user_test.go @@ -177,41 +177,6 @@ func TestSearchUsers(t *testing.T) { []int64{24}) } -func TestDeleteUser(t *testing.T) { - test := func(userID int64) { - assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &User{ID: userID}).(*User) - - ownedRepos := make([]*Repository, 0, 10) - assert.NoError(t, db.GetEngine(db.DefaultContext).Find(&ownedRepos, &Repository{OwnerID: userID})) - if len(ownedRepos) > 0 { - err := DeleteUser(user) - assert.Error(t, err) - assert.True(t, IsErrUserOwnRepos(err)) - return - } - - orgUsers := make([]*OrgUser, 0, 10) - assert.NoError(t, db.GetEngine(db.DefaultContext).Find(&orgUsers, &OrgUser{UID: userID})) - for _, orgUser := range orgUsers { - if err := RemoveOrgUser(orgUser.OrgID, orgUser.UID); err != nil { - assert.True(t, IsErrLastOrgOwner(err)) - return - } - } - assert.NoError(t, DeleteUser(user)) - unittest.AssertNotExistsBean(t, &User{ID: userID}) - unittest.CheckConsistencyFor(t, &User{}, &Repository{}) - } - test(2) - test(4) - test(8) - test(11) - - org := unittest.AssertExistsAndLoadBean(t, &User{ID: 3}).(*User) - assert.Error(t, DeleteUser(org)) -} - func TestEmailNotificationPreferences(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) @@ -333,21 +298,6 @@ func TestDisplayName(t *testing.T) { } } -func TestCreateUser(t *testing.T) { - user := &User{ - Name: "GiteaBot", - Email: "GiteaBot@gitea.io", - Passwd: ";p['////..-++']", - IsAdmin: false, - Theme: setting.UI.DefaultTheme, - MustChangePassword: false, - } - - assert.NoError(t, CreateUser(user)) - - assert.NoError(t, DeleteUser(user)) -} - func TestCreateUserInvalidEmail(t *testing.T) { user := &User{ Name: "GiteaBot", @@ -363,36 +313,6 @@ func TestCreateUserInvalidEmail(t *testing.T) { assert.True(t, user_model.IsErrEmailInvalid(err)) } -func TestCreateUser_Issue5882(t *testing.T) { - // Init settings - _ = setting.Admin - - passwd := ".//.;1;;//.,-=_" - - tt := []struct { - user *User - disableOrgCreation bool - }{ - {&User{Name: "GiteaBot", Email: "GiteaBot@gitea.io", Passwd: passwd, MustChangePassword: false}, false}, - {&User{Name: "GiteaBot2", Email: "GiteaBot2@gitea.io", Passwd: passwd, MustChangePassword: false}, true}, - } - - setting.Service.DefaultAllowCreateOrganization = true - - for _, v := range tt { - setting.Admin.DisableRegularOrgCreation = v.disableOrgCreation - - assert.NoError(t, CreateUser(v.user)) - - u, err := GetUserByEmail(v.user.Email) - assert.NoError(t, err) - - assert.Equal(t, !u.AllowCreateOrganization, v.disableOrgCreation) - - assert.NoError(t, DeleteUser(v.user)) - } -} - func TestGetUserIDsByNames(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) |