From 407385db7eae3ccdef235ac68273364bd704d0bd Mon Sep 17 00:00:00 2001 From: Unknwon Date: Mon, 17 Aug 2015 17:05:37 +0800 Subject: [PATCH] work on #1493 --- gogs.go | 2 +- models/repo.go | 8 +-- models/token.go | 4 +- models/user.go | 118 +++++++++++++++++++++++++------------ modules/auth/auth.go | 2 +- routers/api/v1/user_app.go | 2 +- routers/repo/http.go | 2 +- routers/user/setting.go | 2 +- templates/.VERSION | 2 +- 9 files changed, 91 insertions(+), 51 deletions(-) diff --git a/gogs.go b/gogs.go index d197e32da..d090b2225 100644 --- a/gogs.go +++ b/gogs.go @@ -17,7 +17,7 @@ import ( "github.com/gogits/gogs/modules/setting" ) -const APP_VER = "0.6.5.0815 Beta" +const APP_VER = "0.6.5.0817 Beta" func init() { runtime.GOMAXPROCS(runtime.NumCPU()) diff --git a/models/repo.go b/models/repo.go index 9aed7d7d3..fb787baea 100644 --- a/models/repo.go +++ b/models/repo.go @@ -1435,9 +1435,9 @@ func NotifyWatchers(act *Action) error { // \/ \/ type Star struct { - Id int64 - Uid int64 `xorm:"UNIQUE(s)"` - RepoId int64 `xorm:"UNIQUE(s)"` + ID int64 `xorm:"pk autoincr"` + UID int64 `xorm:"uid UNIQUE(s)"` + RepoID int64 `xorm:"UNIQUE(s)"` } // Star or unstar repository. @@ -1446,7 +1446,7 @@ func StarRepo(uid, repoId int64, star bool) (err error) { if IsStaring(uid, repoId) { return nil } - if _, err = x.Insert(&Star{Uid: uid, RepoId: repoId}); err != nil { + if _, err = x.Insert(&Star{UID: uid, RepoID: repoId}); err != nil { return err } else if _, err = x.Exec("UPDATE `repository` SET num_stars = num_stars + 1 WHERE id = ?", repoId); err != nil { return err diff --git a/models/token.go b/models/token.go index 909d05e07..d17182776 100644 --- a/models/token.go +++ b/models/token.go @@ -18,8 +18,8 @@ var ( // AccessToken represents a personal access token. type AccessToken struct { - Id int64 - Uid int64 + ID int64 `xorm:"pk autoincr"` + UID int64 `xorm:"uid INDEX"` Name string Sha1 string `xorm:"UNIQUE VARCHAR(40)"` Created time.Time `xorm:"CREATED"` diff --git a/models/user.go b/models/user.go index ca49a5b8f..8f93707da 100644 --- a/models/user.go +++ b/models/user.go @@ -515,8 +515,12 @@ func DeleteBeans(e Engine, beans ...interface{}) (err error) { } // FIXME: need some kind of mechanism to record failure. HINT: system notice -// DeleteUser completely and permanently deletes everything of user. +// DeleteUser completely and permanently deletes everything of a user, +// but issues/comments/pulls will be kept and shown as someone has been deleted. func DeleteUser(u *User) error { + // Note: A user owns any repository or belongs to any organization + // cannot perform delete operation. + // Check ownership of repository. count, err := GetRepositoryCount(u) if err != nil { @@ -533,80 +537,116 @@ func DeleteUser(u *User) error { return ErrUserHasOrgs{UID: u.Id} } - // Get watches before session. + sess := x.NewSession() + defer sessionRelease(sess) + if err = sess.Begin(); err != nil { + return err + } + + // ***** START: Watch ***** watches := make([]*Watch, 0, 10) - if err = x.Where("user_id=?", u.Id).Find(&watches); err != nil { + if err = x.Find(&watches, &Watch{UserID: u.Id}); err != nil { return fmt.Errorf("get all watches: %v", err) } - repoIDs := make([]int64, 0, len(watches)) for i := range watches { - repoIDs = append(repoIDs, watches[i].RepoID) + if _, err = sess.Exec("UPDATE `repository` SET num_watches=num_watches-1 WHERE id=?", watches[i].RepoID); err != nil { + return fmt.Errorf("decrease repository watch number[%d]: %v", watches[i].RepoID, err) + } } + // ***** END: Watch ***** - // FIXME: check issues, other repos' commits + // ***** START: Star ***** + stars := make([]*Star, 0, 10) + if err = x.Find(&stars, &Star{UID: u.Id}); err != nil { + return fmt.Errorf("get all stars: %v", err) + } + for i := range stars { + if _, err = sess.Exec("UPDATE `repository` SET num_stars=num_stars-1 WHERE id=?", stars[i].RepoID); err != nil { + return fmt.Errorf("decrease repository star number[%d]: %v", stars[i].RepoID, err) + } + } + // ***** END: Star ***** - sess := x.NewSession() - defer sessionRelease(sess) - if err = sess.Begin(); err != nil { - return err + // ***** START: Follow ***** + followers := make([]*Follow, 0, 10) + if err = x.Find(&followers, &Follow{UserID: u.Id}); err != nil { + return fmt.Errorf("get all followers: %v", err) + } + for i := range followers { + if _, err = sess.Exec("UPDATE `user` SET num_followers=num_followers-1 WHERE id=?", followers[i].UserID); err != nil { + return fmt.Errorf("decrease user follower number[%d]: %v", followers[i].UserID, err) + } } + // ***** END: Follow ***** if err = DeleteBeans(sess, - &Follow{FollowID: u.Id}, &Oauth2{Uid: u.Id}, - &Action{UserID: u.Id}, - &Access{UserID: u.Id}, + &AccessToken{UID: u.Id}, &Collaboration{UserID: u.Id}, - &EmailAddress{Uid: u.Id}, + &Access{UserID: u.Id}, &Watch{UserID: u.Id}, + &Star{UID: u.Id}, + &Follow{FollowID: u.Id}, + &Action{UserID: u.Id}, &IssueUser{UID: u.Id}, + &EmailAddress{Uid: u.Id}, ); err != nil { - return err + return fmt.Errorf("DeleteBeans: %v", err) } - // Decrease all watch numbers. - for i := range repoIDs { - if _, err = sess.Exec("UPDATE `repository` SET num_watches=num_watches-1 WHERE id=?", repoIDs[i]); err != nil { - return err - } - } - - // Delete all SSH keys. + // ***** START: PublicKey ***** keys := make([]*PublicKey, 0, 10) if err = sess.Find(&keys, &PublicKey{OwnerID: u.Id}); err != nil { - return err + return fmt.Errorf("get all public keys: %v", err) } for _, key := range keys { if err = deletePublicKey(sess, key); err != nil { - return err + return fmt.Errorf("deletePublicKey: %v", err) } } + // ***** END: PublicKey ***** // Clear assignee. if _, err = sess.Exec("UPDATE `issue` SET assignee_id=0 WHERE assignee_id=?", u.Id); err != nil { - return err + return fmt.Errorf("clear assignee: %v", err) } if _, err = sess.Delete(u); err != nil { - return err + return fmt.Errorf("Delete: %v", err) } - // Delete user data. - if err = os.RemoveAll(UserPath(u.Name)); err != nil { - return err + if err = sess.Commit(); err != nil { + return fmt.Errorf("Commit: %v", err) } - // Delete avatar. + + // FIXME: system notice + // Note: There are something just cannot be roll back, + // so just keep error logs of those operations. + + RewriteAllPublicKeys() + os.RemoveAll(UserPath(u.Name)) os.Remove(u.CustomAvatarPath()) - return sess.Commit() + return nil } // DeleteInactivateUsers deletes all inactivate users and email addresses. -func DeleteInactivateUsers() error { - _, err := x.Where("is_active=?", false).Delete(new(User)) - if err == nil { - _, err = x.Where("is_activated=?", false).Delete(new(EmailAddress)) +func DeleteInactivateUsers() (err error) { + users := make([]*User, 0, 10) + if err = x.Where("is_active=?", false).Find(&users); err != nil { + return fmt.Errorf("get all inactive users: %v", err) + } + for _, u := range users { + if err = DeleteUser(u); err != nil { + // Ignore users that were set inactive by admin. + if IsErrUserOwnRepos(err) || IsErrUserHasOrgs(err) { + continue + } + return err + } } + + _, err = x.Where("is_activated=?", false).Delete(new(EmailAddress)) return err } @@ -895,9 +935,9 @@ func SearchUserByName(opt SearchOption) (us []*User, err error) { // Follow is connection request for receiving user notification. type Follow struct { - Id int64 - UserID int64 `xorm:"unique(follow)"` - FollowID int64 `xorm:"unique(follow)"` + ID int64 `xorm:"pk autoincr"` + UserID int64 `xorm:"UNIQUE(follow)"` + FollowID int64 `xorm:"UNIQUE(follow)"` } // FollowUser marks someone be another's follower. diff --git a/modules/auth/auth.go b/modules/auth/auth.go index 92bcd7208..389808326 100644 --- a/modules/auth/auth.go +++ b/modules/auth/auth.go @@ -44,7 +44,7 @@ func SignedInId(req *http.Request, sess session.Store) int64 { } return 0 } - return t.Uid + return t.UID } } } diff --git a/routers/api/v1/user_app.go b/routers/api/v1/user_app.go index 31da8a3ee..5e5156aca 100644 --- a/routers/api/v1/user_app.go +++ b/routers/api/v1/user_app.go @@ -34,7 +34,7 @@ type CreateAccessTokenForm struct { // POST /users/:username/tokens func CreateAccessToken(ctx *middleware.Context, form CreateAccessTokenForm) { t := &models.AccessToken{ - Uid: ctx.User.Id, + UID: ctx.User.Id, Name: form.Name, } if err := models.NewAccessToken(t); err != nil { diff --git a/routers/repo/http.go b/routers/repo/http.go index 54ea91cad..abf6134f2 100644 --- a/routers/repo/http.go +++ b/routers/repo/http.go @@ -122,7 +122,7 @@ func Http(ctx *middleware.Context) { } return } - authUser, err = models.GetUserByID(token.Uid) + authUser, err = models.GetUserByID(token.UID) if err != nil { ctx.Handle(500, "GetUserById", err) return diff --git a/routers/user/setting.go b/routers/user/setting.go index de9af6556..428065249 100644 --- a/routers/user/setting.go +++ b/routers/user/setting.go @@ -420,7 +420,7 @@ func SettingsApplicationsPost(ctx *middleware.Context, form auth.NewAccessTokenF } t := &models.AccessToken{ - Uid: ctx.User.Id, + UID: ctx.User.Id, Name: form.Name, } if err := models.NewAccessToken(t); err != nil { diff --git a/templates/.VERSION b/templates/.VERSION index 2b9aa5b03..9962d7894 100644 --- a/templates/.VERSION +++ b/templates/.VERSION @@ -1 +1 @@ -0.6.5.0815 Beta \ No newline at end of file +0.6.5.0817 Beta \ No newline at end of file