2014-04-10 22:20:58 +04:00
// Copyright 2014 The Gogs Authors. All rights reserved.
2019-01-24 01:30:19 +03:00
// Copyright 2019 The Gitea Authors. All rights reserved.
2014-04-10 22:20:58 +04:00
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package models
import (
2019-12-15 12:51:28 +03:00
"context"
2014-04-10 22:20:58 +04:00
"fmt"
"time"
2021-11-17 15:34:35 +03:00
_ "image/jpeg" // Needed for jpeg support
2021-12-10 11:14:24 +03:00
asymkey_model "code.gitea.io/gitea/models/asymkey"
2022-05-11 14:16:35 +03:00
auth_model "code.gitea.io/gitea/models/auth"
2021-09-19 14:49:59 +03:00
"code.gitea.io/gitea/models/db"
2022-03-31 12:20:39 +03:00
"code.gitea.io/gitea/models/issues"
2022-03-29 09:29:02 +03:00
"code.gitea.io/gitea/models/organization"
2022-05-11 13:09:36 +03:00
access_model "code.gitea.io/gitea/models/perm/access"
2022-05-08 16:46:34 +03:00
pull_model "code.gitea.io/gitea/models/pull"
2021-12-10 04:27:50 +03:00
repo_model "code.gitea.io/gitea/models/repo"
2021-11-11 10:03:30 +03:00
user_model "code.gitea.io/gitea/models/user"
2016-11-10 19:24:48 +03:00
"code.gitea.io/gitea/modules/setting"
2022-03-22 04:09:45 +03:00
"code.gitea.io/gitea/modules/util"
2014-04-10 22:20:58 +04:00
)
2021-11-18 20:42:27 +03:00
// DeleteUser deletes models associated to an user.
2021-11-24 12:49:20 +03:00
func DeleteUser ( ctx context . Context , u * user_model . User ) ( err error ) {
2021-11-18 08:58:42 +03:00
e := db . GetEngine ( ctx )
2014-06-27 11:37:01 +04:00
2015-08-17 12:05:37 +03:00
// ***** START: Watch *****
2017-05-20 11:48:22 +03:00
watchedRepoIDs := make ( [ ] int64 , 0 , 10 )
if err = e . Table ( "watch" ) . Cols ( "watch.repo_id" ) .
2021-12-12 18:48:20 +03:00
Where ( "watch.user_id = ?" , u . ID ) . And ( "watch.mode <>?" , repo_model . WatchModeDont ) . Find ( & watchedRepoIDs ) ; err != nil {
2015-03-18 04:51:39 +03:00
return fmt . Errorf ( "get all watches: %v" , err )
2014-04-10 22:20:58 +04:00
}
2021-12-10 04:27:50 +03:00
if _ , err = e . Decr ( "num_watches" ) . In ( "id" , watchedRepoIDs ) . NoAutoTime ( ) . Update ( new ( repo_model . Repository ) ) ; err != nil {
2017-05-20 11:48:22 +03:00
return fmt . Errorf ( "decrease repository num_watches: %v" , err )
2014-04-12 05:47:39 +04:00
}
2015-08-17 12:05:37 +03:00
// ***** END: Watch *****
2015-03-18 04:51:39 +03:00
2015-08-17 12:05:37 +03:00
// ***** START: Star *****
2017-05-20 11:48:22 +03:00
starredRepoIDs := make ( [ ] int64 , 0 , 10 )
if err = e . Table ( "star" ) . Cols ( "star.repo_id" ) .
Where ( "star.uid = ?" , u . ID ) . Find ( & starredRepoIDs ) ; err != nil {
2015-08-17 12:05:37 +03:00
return fmt . Errorf ( "get all stars: %v" , err )
2021-12-10 04:27:50 +03:00
} else if _ , err = e . Decr ( "num_stars" ) . In ( "id" , starredRepoIDs ) . NoAutoTime ( ) . Update ( new ( repo_model . Repository ) ) ; err != nil {
2017-05-20 11:48:22 +03:00
return fmt . Errorf ( "decrease repository num_stars: %v" , err )
2015-08-17 12:05:37 +03:00
}
// ***** END: Star *****
2015-03-18 04:51:39 +03:00
2015-08-17 12:05:37 +03:00
// ***** START: Follow *****
2017-05-20 11:48:22 +03:00
followeeIDs := make ( [ ] int64 , 0 , 10 )
if err = e . Table ( "follow" ) . Cols ( "follow.follow_id" ) .
Where ( "follow.user_id = ?" , u . ID ) . Find ( & followeeIDs ) ; err != nil {
return fmt . Errorf ( "get all followees: %v" , err )
2021-11-24 12:49:20 +03:00
} else if _ , err = e . Decr ( "num_followers" ) . In ( "id" , followeeIDs ) . Update ( new ( user_model . User ) ) ; err != nil {
2017-05-20 11:48:22 +03:00
return fmt . Errorf ( "decrease user num_followers: %v" , err )
2015-08-17 12:05:37 +03:00
}
2017-05-20 11:48:22 +03:00
followerIDs := make ( [ ] int64 , 0 , 10 )
if err = e . Table ( "follow" ) . Cols ( "follow.user_id" ) .
Where ( "follow.follow_id = ?" , u . ID ) . Find ( & followerIDs ) ; err != nil {
return fmt . Errorf ( "get all followers: %v" , err )
2021-11-24 12:49:20 +03:00
} else if _ , err = e . Decr ( "num_following" ) . In ( "id" , followerIDs ) . Update ( new ( user_model . User ) ) ; err != nil {
2017-05-20 11:48:22 +03:00
return fmt . Errorf ( "decrease user num_following: %v" , err )
2014-04-10 22:20:58 +04:00
}
2015-08-17 12:05:37 +03:00
// ***** END: Follow *****
2015-03-18 04:51:39 +03:00
2022-02-17 11:37:48 +03:00
if err = db . DeleteBeans ( ctx ,
2016-07-23 20:08:22 +03:00
& AccessToken { UID : u . ID } ,
2022-05-11 13:09:36 +03:00
& repo_model . Collaboration { UserID : u . ID } ,
& access_model . Access { UserID : u . ID } ,
2021-12-12 18:48:20 +03:00
& repo_model . Watch { UserID : u . ID } ,
& repo_model . Star { UID : u . ID } ,
2021-11-17 12:58:31 +03:00
& user_model . Follow { UserID : u . ID } ,
& user_model . Follow { FollowID : u . ID } ,
2016-07-23 20:08:22 +03:00
& Action { UserID : u . ID } ,
& IssueUser { UID : u . ID } ,
2021-11-11 10:03:30 +03:00
& user_model . EmailAddress { UID : u . ID } ,
2021-11-17 12:58:31 +03:00
& user_model . UserOpenID { UID : u . ID } ,
2022-03-31 12:20:39 +03:00
& issues . Reaction { UserID : u . ID } ,
2022-03-29 09:29:02 +03:00
& organization . TeamUser { UID : u . ID } ,
2018-12-18 19:26:26 +03:00
& Stopwatch { UserID : u . ID } ,
2021-11-22 12:47:23 +03:00
& user_model . Setting { UserID : u . ID } ,
2022-05-08 16:46:34 +03:00
& pull_model . AutoMerge { DoerID : u . ID } ,
& pull_model . ReviewState { UserID : u . ID } ,
2015-03-18 04:51:39 +03:00
) ; err != nil {
2015-12-01 04:45:55 +03:00
return fmt . Errorf ( "deleteBeans: %v" , err )
2014-04-10 22:20:58 +04:00
}
2015-03-18 04:51:39 +03:00
2022-05-11 14:16:35 +03:00
if err := auth_model . DeleteOAuth2RelictsByUserID ( ctx , u . ID ) ; err != nil {
return err
}
2021-01-22 05:56:19 +03:00
if setting . Service . UserDeleteWithCommentsMaxTime != 0 &&
u . CreatedUnix . AsTime ( ) . Add ( setting . Service . UserDeleteWithCommentsMaxTime ) . After ( time . Now ( ) ) {
// Delete Comments
const batchSize = 50
for start := 0 ; ; start += batchSize {
comments := make ( [ ] * Comment , 0 , batchSize )
if err = e . Where ( "type=? AND poster_id=?" , CommentTypeComment , u . ID ) . Limit ( batchSize , start ) . Find ( & comments ) ; err != nil {
return err
}
if len ( comments ) == 0 {
break
}
for _ , comment := range comments {
2022-03-31 12:20:39 +03:00
if err = deleteComment ( ctx , comment ) ; err != nil {
2021-01-22 05:56:19 +03:00
return err
}
}
}
// Delete Reactions
2022-03-31 12:20:39 +03:00
if err = issues . DeleteReaction ( ctx , & issues . ReactionOptions { DoerID : u . ID } ) ; err != nil {
2021-01-22 05:56:19 +03:00
return err
2021-01-17 23:48:38 +03:00
}
}
2022-03-22 04:09:45 +03:00
// ***** START: Branch Protections *****
{
const batchSize = 50
for start := 0 ; ; start += batchSize {
protections := make ( [ ] * ProtectedBranch , 0 , batchSize )
// @perf: We can't filter on DB side by u.ID, as those IDs are serialized as JSON strings.
// We could filter down with `WHERE repo_id IN (reposWithPushPermission(u))`,
// though that query will be quite complex and tricky to maintain (compare `getRepoAssignees()`).
// Also, as we didn't update branch protections when removing entries from `access` table,
// it's safer to iterate all protected branches.
if err = e . Limit ( batchSize , start ) . Find ( & protections ) ; err != nil {
return fmt . Errorf ( "findProtectedBranches: %v" , err )
}
if len ( protections ) == 0 {
break
}
for _ , p := range protections {
var matched1 , matched2 , matched3 bool
if len ( p . WhitelistUserIDs ) != 0 {
p . WhitelistUserIDs , matched1 = util . RemoveIDFromList (
p . WhitelistUserIDs , u . ID )
}
if len ( p . ApprovalsWhitelistUserIDs ) != 0 {
p . ApprovalsWhitelistUserIDs , matched2 = util . RemoveIDFromList (
p . ApprovalsWhitelistUserIDs , u . ID )
}
if len ( p . MergeWhitelistUserIDs ) != 0 {
p . MergeWhitelistUserIDs , matched3 = util . RemoveIDFromList (
p . MergeWhitelistUserIDs , u . ID )
}
if matched1 || matched2 || matched3 {
if _ , err = e . ID ( p . ID ) . Cols (
"whitelist_user_i_ds" ,
"merge_whitelist_user_i_ds" ,
"approvals_whitelist_user_i_ds" ,
) . Update ( p ) ; err != nil {
return fmt . Errorf ( "updateProtectedBranches: %v" , err )
}
}
}
}
}
// ***** END: Branch Protections *****
2015-08-17 12:05:37 +03:00
// ***** START: PublicKey *****
2022-05-20 17:08:52 +03:00
if _ , err = db . DeleteByBean ( ctx , & asymkey_model . PublicKey { OwnerID : u . ID } ) ; err != nil {
2016-07-26 12:26:48 +03:00
return fmt . Errorf ( "deletePublicKeys: %v" , err )
2014-04-10 22:20:58 +04:00
}
2015-08-17 12:05:37 +03:00
// ***** END: PublicKey *****
2014-04-10 22:20:58 +04:00
2018-12-18 19:26:26 +03:00
// ***** START: GPGPublicKey *****
2021-12-10 11:14:24 +03:00
keys , err := asymkey_model . ListGPGKeys ( ctx , u . ID , db . ListOptions { } )
2021-02-04 12:16:21 +03:00
if err != nil {
return fmt . Errorf ( "ListGPGKeys: %v" , err )
}
// Delete GPGKeyImport(s).
for _ , key := range keys {
2022-05-20 17:08:52 +03:00
if _ , err = db . DeleteByBean ( ctx , & asymkey_model . GPGKeyImport { KeyID : key . KeyID } ) ; err != nil {
2021-02-04 12:16:21 +03:00
return fmt . Errorf ( "deleteGPGKeyImports: %v" , err )
}
}
2022-05-20 17:08:52 +03:00
if _ , err = db . DeleteByBean ( ctx , & asymkey_model . GPGKey { OwnerID : u . ID } ) ; err != nil {
2018-12-18 19:26:26 +03:00
return fmt . Errorf ( "deleteGPGKeys: %v" , err )
}
// ***** END: GPGPublicKey *****
2015-08-14 21:48:05 +03:00
// Clear assignee.
2022-05-20 17:08:52 +03:00
if _ , err = db . DeleteByBean ( ctx , & IssueAssignees { AssigneeID : u . ID } ) ; err != nil {
2015-08-17 12:05:37 +03:00
return fmt . Errorf ( "clear assignee: %v" , err )
2015-08-14 21:48:05 +03:00
}
2017-02-22 10:14:37 +03:00
// ***** START: ExternalLoginUser *****
2021-11-28 17:11:58 +03:00
if err = user_model . RemoveAllAccountLinks ( ctx , u ) ; err != nil {
2017-02-22 10:14:37 +03:00
return fmt . Errorf ( "ExternalLoginUser: %v" , err )
}
// ***** END: ExternalLoginUser *****
2021-11-24 12:49:20 +03:00
if _ , err = e . ID ( u . ID ) . Delete ( new ( user_model . User ) ) ; err != nil {
2015-08-17 12:05:37 +03:00
return fmt . Errorf ( "Delete: %v" , err )
2015-03-18 04:51:39 +03:00
}
2015-08-17 12:05:37 +03:00
return nil
2014-06-21 08:51:41 +04:00
}