2014-04-10 14:20:58 -04:00
// Copyright 2014 The Gogs Authors. All rights reserved.
2019-01-23 17:30:19 -05:00
// Copyright 2019 The Gitea Authors. All rights reserved.
2014-04-10 14: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 04:51:28 -05:00
"context"
2014-04-10 14:20:58 -04:00
"fmt"
"time"
2021-11-17 07:34:35 -05:00
_ "image/jpeg" // Needed for jpeg support
2021-09-19 07:49:59 -04:00
"code.gitea.io/gitea/models/db"
2021-12-09 20:27:50 -05:00
repo_model "code.gitea.io/gitea/models/repo"
2021-11-09 14:57:58 -05:00
"code.gitea.io/gitea/models/unit"
2021-11-11 02:03:30 -05:00
user_model "code.gitea.io/gitea/models/user"
2016-11-10 11:24:48 -05:00
"code.gitea.io/gitea/modules/setting"
2019-02-18 11:00:27 -05:00
"code.gitea.io/gitea/modules/structs"
2019-06-23 11:22:43 -04:00
"xorm.io/builder"
2014-04-10 14:20:58 -04:00
)
2021-11-18 12:42:27 -05:00
// GetOrganizationCount returns count of membership of organization of the user.
2021-11-24 04:49:20 -05:00
func GetOrganizationCount ( ctx context . Context , u * user_model . User ) ( int64 , error ) {
2021-11-18 12:42:27 -05:00
return db . GetEngine ( ctx ) .
2016-11-10 10:16:32 -05:00
Where ( "uid=?" , u . ID ) .
Count ( new ( OrgUser ) )
2015-09-06 08:54:08 -04:00
}
2019-10-08 13:55:16 -04:00
// GetRepositoryIDs returns repositories IDs where user owned and has unittypes
2020-01-17 02:34:37 -05:00
// Caller shall check that units is not globally disabled
2021-11-24 04:49:20 -05:00
func GetRepositoryIDs ( u * user_model . User , units ... unit . Type ) ( [ ] int64 , error ) {
2019-10-08 13:55:16 -04:00
var ids [ ] int64
2021-09-23 11:45:36 -04:00
sess := db . GetEngine ( db . DefaultContext ) . Table ( "repository" ) . Cols ( "repository.id" )
2018-06-21 12:00:13 -04:00
if len ( units ) > 0 {
2019-10-08 13:55:16 -04:00
sess = sess . Join ( "INNER" , "repo_unit" , "repository.id = repo_unit.repo_id" )
sess = sess . In ( "repo_unit.type" , units )
2018-06-21 12:00:13 -04:00
}
2019-10-08 13:55:16 -04:00
return ids , sess . Where ( "owner_id = ?" , u . ID ) . Find ( & ids )
2017-02-16 19:58:19 -05:00
}
2021-01-12 23:19:17 -05:00
// GetActiveRepositoryIDs returns non-archived repositories IDs where user owned and has unittypes
2021-11-24 04:49:20 -05:00
// Caller shall check that units is not globally disabled
func GetActiveRepositoryIDs ( u * user_model . User , units ... unit . Type ) ( [ ] int64 , error ) {
var ids [ ] int64
2016-01-27 16:45:03 -05:00
2021-11-24 04:49:20 -05:00
sess := db . GetEngine ( db . DefaultContext ) . Table ( "repository" ) . Cols ( "repository.id" )
2018-09-06 20:40:58 -04:00
2021-11-24 04:49:20 -05:00
if len ( units ) > 0 {
sess = sess . Join ( "INNER" , "repo_unit" , "repository.id = repo_unit.repo_id" )
sess = sess . In ( "repo_unit.type" , units )
2021-01-24 10:23:05 -05:00
}
2021-11-24 04:49:20 -05:00
sess . Where ( builder . Eq { "is_archived" : false } )
2021-01-24 10:23:05 -05:00
2021-11-24 04:49:20 -05:00
return ids , sess . Where ( "owner_id = ?" , u . ID ) . GroupBy ( "repository.id" ) . Find ( & ids )
2014-04-10 14:20:58 -04:00
}
2021-11-24 04:49:20 -05:00
// GetOrgRepositoryIDs returns repositories IDs where user's team owned and has unittypes
// Caller shall check that units is not globally disabled
func GetOrgRepositoryIDs ( u * user_model . User , units ... unit . Type ) ( [ ] int64 , error ) {
var ids [ ] int64
2017-02-25 09:53:57 -05:00
2021-11-24 04:49:20 -05:00
if err := db . GetEngine ( db . DefaultContext ) . Table ( "repository" ) .
Cols ( "repository.id" ) .
Join ( "INNER" , "team_user" , "repository.owner_id = team_user.org_id" ) .
Join ( "INNER" , "team_repo" , "(? != ? and repository.is_private != ?) OR (team_user.team_id = team_repo.team_id AND repository.id = team_repo.repo_id)" , true , u . IsRestricted , true ) .
Where ( "team_user.uid = ?" , u . ID ) .
GroupBy ( "repository.id" ) . Find ( & ids ) ; err != nil {
return nil , err
2021-06-27 14:47:35 -04:00
}
2021-11-24 04:49:20 -05:00
if len ( units ) > 0 {
return FilterOutRepoIdsWithoutUnitAccess ( u , ids , units ... )
2020-11-14 11:53:43 -05:00
}
2021-06-27 14:47:35 -04:00
2021-11-24 04:49:20 -05:00
return ids , nil
2014-04-10 14:20:58 -04:00
}
2021-11-24 04:49:20 -05:00
// GetActiveOrgRepositoryIDs returns non-archived repositories IDs where user's team owned and has unittypes
// Caller shall check that units is not globally disabled
func GetActiveOrgRepositoryIDs ( u * user_model . User , units ... unit . Type ) ( [ ] int64 , error ) {
var ids [ ] int64
2017-02-25 09:53:57 -05:00
2021-11-24 04:49:20 -05:00
if err := db . GetEngine ( db . DefaultContext ) . Table ( "repository" ) .
Cols ( "repository.id" ) .
Join ( "INNER" , "team_user" , "repository.owner_id = team_user.org_id" ) .
Join ( "INNER" , "team_repo" , "(? != ? and repository.is_private != ?) OR (team_user.team_id = team_repo.team_id AND repository.id = team_repo.repo_id)" , true , u . IsRestricted , true ) .
Where ( "team_user.uid = ?" , u . ID ) .
Where ( builder . Eq { "is_archived" : false } ) .
GroupBy ( "repository.id" ) . Find ( & ids ) ; err != nil {
return nil , err
}
2017-09-25 00:59:27 -04:00
2021-11-24 04:49:20 -05:00
if len ( units ) > 0 {
return FilterOutRepoIdsWithoutUnitAccess ( u , ids , units ... )
2021-06-27 14:47:35 -04:00
}
2021-11-24 04:49:20 -05:00
return ids , nil
2017-08-12 10:18:44 -04:00
}
2021-11-24 04:49:20 -05:00
// GetAccessRepoIDs returns all repositories IDs where user's or user is a team member organizations
// Caller shall check that units is not globally disabled
func GetAccessRepoIDs ( u * user_model . User , units ... unit . Type ) ( [ ] int64 , error ) {
ids , err := GetRepositoryIDs ( u , units ... )
if err != nil {
return nil , err
}
ids2 , err := GetOrgRepositoryIDs ( u , units ... )
2021-11-21 10:41:00 -05:00
if err != nil {
2021-11-24 04:49:20 -05:00
return nil , err
2020-11-20 16:45:55 -05:00
}
2021-11-24 04:49:20 -05:00
return append ( ids , ids2 ... ) , nil
}
2021-11-21 10:41:00 -05:00
2021-11-24 04:49:20 -05:00
// GetActiveAccessRepoIDs returns all non-archived repositories IDs where user's or user is a team member organizations
// Caller shall check that units is not globally disabled
func GetActiveAccessRepoIDs ( u * user_model . User , units ... unit . Type ) ( [ ] int64 , error ) {
ids , err := GetActiveRepositoryIDs ( u , units ... )
if err != nil {
return nil , err
2017-02-25 09:53:57 -05:00
}
2021-11-24 04:49:20 -05:00
ids2 , err := GetActiveOrgRepositoryIDs ( u , units ... )
if err != nil {
return nil , err
2020-11-20 16:45:55 -05:00
}
2021-11-24 04:49:20 -05:00
return append ( ids , ids2 ... ) , nil
2015-08-29 13:13:24 -04:00
}
2015-09-06 08:54:08 -04:00
// deleteBeans deletes all given beans, beans should contain delete conditions.
2021-09-19 07:49:59 -04:00
func deleteBeans ( e db . Engine , beans ... interface { } ) ( err error ) {
2015-03-17 21:51:39 -04:00
for i := range beans {
if _ , err = e . Delete ( beans [ i ] ) ; err != nil {
return err
}
}
return nil
}
2021-11-18 12:42:27 -05:00
// DeleteUser deletes models associated to an user.
2021-11-24 04:49:20 -05:00
func DeleteUser ( ctx context . Context , u * user_model . User ) ( err error ) {
2021-11-18 00:58:42 -05:00
e := db . GetEngine ( ctx )
2014-06-27 03:37:01 -04:00
2015-08-17 05:05:37 -04:00
// ***** START: Watch *****
2017-05-20 04:48:22 -04:00
watchedRepoIDs := make ( [ ] int64 , 0 , 10 )
if err = e . Table ( "watch" ) . Cols ( "watch.repo_id" ) .
2019-11-10 04:22:19 -05:00
Where ( "watch.user_id = ?" , u . ID ) . And ( "watch.mode <>?" , RepoWatchModeDont ) . Find ( & watchedRepoIDs ) ; err != nil {
2015-03-17 21:51:39 -04:00
return fmt . Errorf ( "get all watches: %v" , err )
2014-04-10 14:20:58 -04:00
}
2021-12-09 20:27:50 -05:00
if _ , err = e . Decr ( "num_watches" ) . In ( "id" , watchedRepoIDs ) . NoAutoTime ( ) . Update ( new ( repo_model . Repository ) ) ; err != nil {
2017-05-20 04:48:22 -04:00
return fmt . Errorf ( "decrease repository num_watches: %v" , err )
2014-04-11 21:47:39 -04:00
}
2015-08-17 05:05:37 -04:00
// ***** END: Watch *****
2015-03-17 21:51:39 -04:00
2015-08-17 05:05:37 -04:00
// ***** START: Star *****
2017-05-20 04:48:22 -04: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 05:05:37 -04:00
return fmt . Errorf ( "get all stars: %v" , err )
2021-12-09 20:27:50 -05:00
} else if _ , err = e . Decr ( "num_stars" ) . In ( "id" , starredRepoIDs ) . NoAutoTime ( ) . Update ( new ( repo_model . Repository ) ) ; err != nil {
2017-05-20 04:48:22 -04:00
return fmt . Errorf ( "decrease repository num_stars: %v" , err )
2015-08-17 05:05:37 -04:00
}
// ***** END: Star *****
2015-03-17 21:51:39 -04:00
2015-08-17 05:05:37 -04:00
// ***** START: Follow *****
2017-05-20 04:48:22 -04: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 04:49:20 -05:00
} else if _ , err = e . Decr ( "num_followers" ) . In ( "id" , followeeIDs ) . Update ( new ( user_model . User ) ) ; err != nil {
2017-05-20 04:48:22 -04:00
return fmt . Errorf ( "decrease user num_followers: %v" , err )
2015-08-17 05:05:37 -04:00
}
2017-05-20 04:48:22 -04: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 04:49:20 -05:00
} else if _ , err = e . Decr ( "num_following" ) . In ( "id" , followerIDs ) . Update ( new ( user_model . User ) ) ; err != nil {
2017-05-20 04:48:22 -04:00
return fmt . Errorf ( "decrease user num_following: %v" , err )
2014-04-10 14:20:58 -04:00
}
2015-08-17 05:05:37 -04:00
// ***** END: Follow *****
2015-03-17 21:51:39 -04:00
2015-09-06 08:54:08 -04:00
if err = deleteBeans ( e ,
2016-07-23 13:08:22 -04:00
& AccessToken { UID : u . ID } ,
& Collaboration { UserID : u . ID } ,
& Access { UserID : u . ID } ,
& Watch { UserID : u . ID } ,
& Star { UID : u . ID } ,
2021-11-17 04:58:31 -05:00
& user_model . Follow { UserID : u . ID } ,
& user_model . Follow { FollowID : u . ID } ,
2016-07-23 13:08:22 -04:00
& Action { UserID : u . ID } ,
& IssueUser { UID : u . ID } ,
2021-11-11 02:03:30 -05:00
& user_model . EmailAddress { UID : u . ID } ,
2021-11-17 04:58:31 -05:00
& user_model . UserOpenID { UID : u . ID } ,
2017-12-03 18:14:26 -05:00
& Reaction { UserID : u . ID } ,
2018-12-18 11:26:26 -05:00
& TeamUser { UID : u . ID } ,
& Collaboration { UserID : u . ID } ,
& Stopwatch { UserID : u . ID } ,
2021-11-22 04:47:23 -05:00
& user_model . Setting { UserID : u . ID } ,
2015-03-17 21:51:39 -04:00
) ; err != nil {
2015-11-30 20:45:55 -05:00
return fmt . Errorf ( "deleteBeans: %v" , err )
2014-04-10 14:20:58 -04:00
}
2015-03-17 21:51:39 -04:00
2021-01-21 21:56:19 -05: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 {
if err = deleteComment ( e , comment ) ; err != nil {
return err
}
}
}
// Delete Reactions
if err = deleteReaction ( e , & ReactionOptions { Doer : u } ) ; err != nil {
return err
2021-01-17 15:48:38 -05:00
}
}
2015-08-17 05:05:37 -04:00
// ***** START: PublicKey *****
2018-12-18 11:26:26 -05:00
if _ , err = e . Delete ( & PublicKey { OwnerID : u . ID } ) ; err != nil {
2016-07-26 05:26:48 -04:00
return fmt . Errorf ( "deletePublicKeys: %v" , err )
2014-04-10 14:20:58 -04:00
}
2015-08-17 05:05:37 -04:00
// ***** END: PublicKey *****
2014-04-10 14:20:58 -04:00
2018-12-18 11:26:26 -05:00
// ***** START: GPGPublicKey *****
2021-09-24 07:32:56 -04:00
keys , err := listGPGKeys ( e , u . ID , db . ListOptions { } )
2021-02-04 04:16:21 -05:00
if err != nil {
return fmt . Errorf ( "ListGPGKeys: %v" , err )
}
// Delete GPGKeyImport(s).
for _ , key := range keys {
if _ , err = e . Delete ( & GPGKeyImport { KeyID : key . KeyID } ) ; err != nil {
return fmt . Errorf ( "deleteGPGKeyImports: %v" , err )
}
}
2018-12-18 11:26:26 -05:00
if _ , err = e . Delete ( & GPGKey { OwnerID : u . ID } ) ; err != nil {
return fmt . Errorf ( "deleteGPGKeys: %v" , err )
}
// ***** END: GPGPublicKey *****
2015-08-14 14:48:05 -04:00
// Clear assignee.
2018-05-09 12:29:04 -04:00
if err = clearAssigneeByUserID ( e , u . ID ) ; err != nil {
2015-08-17 05:05:37 -04:00
return fmt . Errorf ( "clear assignee: %v" , err )
2015-08-14 14:48:05 -04:00
}
2017-02-22 02:14:37 -05:00
// ***** START: ExternalLoginUser *****
2021-11-28 09:11:58 -05:00
if err = user_model . RemoveAllAccountLinks ( ctx , u ) ; err != nil {
2017-02-22 02:14:37 -05:00
return fmt . Errorf ( "ExternalLoginUser: %v" , err )
}
// ***** END: ExternalLoginUser *****
2021-11-24 04:49:20 -05:00
if _ , err = e . ID ( u . ID ) . Delete ( new ( user_model . User ) ) ; err != nil {
2015-08-17 05:05:37 -04:00
return fmt . Errorf ( "Delete: %v" , err )
2015-03-17 21:51:39 -04:00
}
2015-08-17 05:05:37 -04:00
return nil
2014-06-21 00:51:41 -04:00
}
2016-11-14 17:33:58 -05:00
// GetStarredRepos returns the repos starred by a particular user
2021-12-09 20:27:50 -05:00
func GetStarredRepos ( userID int64 , private bool , listOptions db . ListOptions ) ( [ ] * repo_model . Repository , error ) {
2021-09-23 11:45:36 -04:00
sess := db . GetEngine ( db . DefaultContext ) . Where ( "star.uid=?" , userID ) .
2016-11-14 17:33:58 -05:00
Join ( "LEFT" , "star" , "`repository`.id=`star`.repo_id" )
if ! private {
sess = sess . And ( "is_private=?" , false )
}
2020-01-24 14:00:29 -05:00
if listOptions . Page != 0 {
2021-09-24 07:32:56 -04:00
sess = db . SetSessionPagination ( sess , & listOptions )
2020-01-24 14:00:29 -05:00
2021-12-09 20:27:50 -05:00
repos := make ( [ ] * repo_model . Repository , 0 , listOptions . PageSize )
2020-01-24 14:00:29 -05:00
return repos , sess . Find ( & repos )
2016-11-14 17:33:58 -05:00
}
2020-01-24 14:00:29 -05:00
2021-12-09 20:27:50 -05:00
repos := make ( [ ] * repo_model . Repository , 0 , 10 )
2020-01-24 14:00:29 -05:00
return repos , sess . Find ( & repos )
2016-11-14 17:33:58 -05:00
}
2016-12-23 20:53:11 -05:00
// GetWatchedRepos returns the repos watched by a particular user
2021-12-09 20:27:50 -05:00
func GetWatchedRepos ( userID int64 , private bool , listOptions db . ListOptions ) ( [ ] * repo_model . Repository , int64 , error ) {
2021-09-23 11:45:36 -04:00
sess := db . GetEngine ( db . DefaultContext ) . Where ( "watch.user_id=?" , userID ) .
2019-11-10 04:22:19 -05:00
And ( "`watch`.mode<>?" , RepoWatchModeDont ) .
2016-12-23 20:53:11 -05:00
Join ( "LEFT" , "watch" , "`repository`.id=`watch`.repo_id" )
if ! private {
sess = sess . And ( "is_private=?" , false )
}
2020-01-24 14:00:29 -05:00
if listOptions . Page != 0 {
2021-09-24 07:32:56 -04:00
sess = db . SetSessionPagination ( sess , & listOptions )
2020-01-24 14:00:29 -05:00
2021-12-09 20:27:50 -05:00
repos := make ( [ ] * repo_model . Repository , 0 , listOptions . PageSize )
2021-08-12 08:43:08 -04:00
total , err := sess . FindAndCount ( & repos )
return repos , total , err
2016-12-23 20:53:11 -05:00
}
2020-01-24 14:00:29 -05:00
2021-12-09 20:27:50 -05:00
repos := make ( [ ] * repo_model . Repository , 0 , 10 )
2021-08-12 08:43:08 -04:00
total , err := sess . FindAndCount ( & repos )
return repos , total , err
2016-12-23 20:53:11 -05:00
}
2017-05-10 09:10:18 -04:00
2021-11-24 04:49:20 -05:00
// IsUserVisibleToViewer check if viewer is able to see user profile
func IsUserVisibleToViewer ( u * user_model . User , viewer * user_model . User ) bool {
return isUserVisibleToViewer ( db . GetEngine ( db . DefaultContext ) , u , viewer )
2020-10-14 09:07:51 -04:00
}
2021-11-17 04:58:31 -05:00
2021-11-24 04:49:20 -05:00
func isUserVisibleToViewer ( e db . Engine , u * user_model . User , viewer * user_model . User ) bool {
if viewer != nil && viewer . IsAdmin {
return true
2021-11-17 04:58:31 -05:00
}
2021-11-24 04:49:20 -05:00
switch u . Visibility {
case structs . VisibleTypePublic :
return true
case structs . VisibleTypeLimited :
if viewer == nil || viewer . IsRestricted {
return false
}
return true
case structs . VisibleTypePrivate :
if viewer == nil || viewer . IsRestricted {
return false
}
2021-11-17 04:58:31 -05:00
2021-11-24 04:49:20 -05:00
// If they follow - they see each over
follower := user_model . IsFollowing ( u . ID , viewer . ID )
if follower {
return true
}
2021-11-17 04:58:31 -05:00
2021-11-24 04:49:20 -05:00
// Now we need to check if they in some organization together
count , err := e . Table ( "team_user" ) .
Where (
builder . And (
builder . Eq { "uid" : viewer . ID } ,
builder . Or (
builder . Eq { "org_id" : u . ID } ,
builder . In ( "org_id" ,
builder . Select ( "org_id" ) .
From ( "team_user" , "t2" ) .
Where ( builder . Eq { "uid" : u . ID } ) ) ) ) ) .
Count ( new ( TeamUser ) )
if err != nil {
return false
}
2021-11-17 04:58:31 -05:00
2021-11-24 04:49:20 -05:00
if count < 0 {
// No common organization
return false
}
2021-11-18 00:58:42 -05:00
2021-11-24 04:49:20 -05:00
// they are in an organization together
return true
2021-11-18 00:58:42 -05:00
}
2021-11-24 04:49:20 -05:00
return false
2021-11-18 00:58:42 -05:00
}