// FIXME: need some kind of mechanism to record failure. HINT: system notice func deleteUser(e *xorm.Session, 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(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 ***** watches := make([]*Watch, 0, 10) if err = e.Find(&watches, &Watch{UserID: u.Id}); err != nil { return fmt.Errorf("get all watches: %v", err) } for i := range watches { if _, err = e.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 ***** // ***** START: Star ***** stars := make([]*Star, 0, 10) if err = e.Find(&stars, &Star{UID: u.Id}); err != nil { return fmt.Errorf("get all stars: %v", err) } for i := range stars { if _, err = e.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 ***** // ***** START: Follow ***** followers := make([]*Follow, 0, 10) if err = e.Find(&followers, &Follow{UserID: u.Id}); err != nil { return fmt.Errorf("get all followers: %v", err) } for i := range followers { if _, err = e.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(e, &AccessToken{UID: u.Id}, &Collaboration{UserID: 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 fmt.Errorf("deleteBeans: %v", err) } // ***** START: PublicKey ***** keys := make([]*PublicKey, 0, 10) if err = e.Find(&keys, &PublicKey{OwnerID: u.Id}); err != nil { return fmt.Errorf("get all public keys: %v", err) } for _, key := range keys { if err = deletePublicKey(e, key.ID); err != nil { return fmt.Errorf("deletePublicKey: %v", err) } } // ***** END: PublicKey ***** // Clear assignee. if _, err = e.Exec("UPDATE `issue` SET assignee_id=0 WHERE assignee_id=?", u.Id); err != nil { return fmt.Errorf("clear assignee: %v", err) } if _, err = e.Id(u.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. RewriteAllPublicKeys() os.RemoveAll(UserPath(u.Name)) os.Remove(u.CustomAvatarPath()) return nil }