2018-06-21 16:00:13 +00:00
// Copyright 2018 The Gitea Authors. All rights reserved.
2016-03-25 22:04:02 +00:00
// Copyright 2016 The Gogs Authors. All rights reserved.
2022-11-27 18:20:29 +00:00
// SPDX-License-Identifier: MIT
2016-03-25 22:04:02 +00:00
package models
import (
2021-11-19 11:41:40 +00:00
"context"
2016-03-25 22:04:02 +00:00
"fmt"
"strings"
2017-12-21 07:43:26 +00:00
2021-09-19 11:49:59 +00:00
"code.gitea.io/gitea/models/db"
2022-06-12 15:51:54 +00:00
git_model "code.gitea.io/gitea/models/git"
2022-06-13 09:37:59 +00:00
issues_model "code.gitea.io/gitea/models/issues"
2022-03-29 06:29:02 +00:00
"code.gitea.io/gitea/models/organization"
2022-05-11 10:09:36 +00:00
access_model "code.gitea.io/gitea/models/perm/access"
2021-12-10 01:27:50 +00:00
repo_model "code.gitea.io/gitea/models/repo"
2021-11-24 09:49:20 +00:00
user_model "code.gitea.io/gitea/models/user"
2022-04-01 01:53:18 +00:00
"code.gitea.io/gitea/modules/log"
2019-01-27 09:25:21 +00:00
"code.gitea.io/gitea/modules/setting"
2022-03-22 01:09:45 +00:00
"code.gitea.io/gitea/modules/util"
2019-01-27 09:25:21 +00:00
2019-10-01 05:32:28 +00:00
"xorm.io/builder"
2016-03-25 22:04:02 +00:00
)
2022-08-25 02:31:57 +00:00
func AddRepository ( ctx context . Context , t * organization . Team , repo * repo_model . Repository ) ( err error ) {
2022-03-29 06:29:02 +00:00
if err = organization . AddTeamRepo ( ctx , t . OrgID , t . ID , repo . ID ) ; err != nil {
2016-03-25 22:04:02 +00:00
return err
}
2022-08-25 02:31:57 +00:00
if err = organization . IncrTeamRepoNum ( ctx , t . ID ) ; err != nil {
2022-10-24 19:29:17 +00:00
return fmt . Errorf ( "update team: %w" , err )
2016-03-25 22:04:02 +00:00
}
2017-12-31 03:08:08 +00:00
t . NumRepos ++
2022-05-11 10:09:36 +00:00
if err = access_model . RecalculateTeamAccesses ( ctx , repo , 0 ) ; err != nil {
2022-10-24 19:29:17 +00:00
return fmt . Errorf ( "recalculateAccesses: %w" , err )
2016-03-25 22:04:02 +00:00
}
2019-01-27 09:25:21 +00:00
// Make all team members watch this repo if enabled in global settings
if setting . Service . AutoWatchNewRepos {
2022-12-03 02:48:26 +00:00
if err = t . LoadMembers ( ctx ) ; err != nil {
2022-10-24 19:29:17 +00:00
return fmt . Errorf ( "getMembers: %w" , err )
2019-01-27 09:25:21 +00:00
}
for _ , u := range t . Members {
2022-05-20 14:08:52 +00:00
if err = repo_model . WatchRepo ( ctx , u . ID , repo . ID , true ) ; err != nil {
2022-10-24 19:29:17 +00:00
return fmt . Errorf ( "watchRepo: %w" , err )
2019-01-27 09:25:21 +00:00
}
2016-03-25 22:04:02 +00:00
}
}
2019-01-27 09:25:21 +00:00
2016-03-25 22:04:02 +00:00
return nil
}
2019-11-06 09:37:14 +00:00
// addAllRepositories adds all repositories to the team.
// If the team already has some repositories they will be left unchanged.
2022-03-29 06:29:02 +00:00
func addAllRepositories ( ctx context . Context , t * organization . Team ) error {
2022-08-25 02:31:57 +00:00
orgRepos , err := organization . GetOrgRepositories ( ctx , t . OrgID )
if err != nil {
2022-10-24 19:29:17 +00:00
return fmt . Errorf ( "get org repos: %w" , err )
2019-11-06 09:37:14 +00:00
}
for _ , repo := range orgRepos {
2022-05-11 10:09:36 +00:00
if ! organization . HasTeamRepo ( ctx , t . OrgID , t . ID , repo . ID ) {
2022-08-25 02:31:57 +00:00
if err := AddRepository ( ctx , t , repo ) ; err != nil {
2022-10-24 19:29:17 +00:00
return fmt . Errorf ( "AddRepository: %w" , err )
2019-11-06 09:37:14 +00:00
}
}
}
return nil
}
2019-11-09 00:39:37 +00:00
// AddAllRepositories adds all repositories to the team
2022-03-29 06:29:02 +00:00
func AddAllRepositories ( t * organization . Team ) ( err error ) {
2022-11-12 20:18:50 +00:00
ctx , committer , err := db . TxContext ( db . DefaultContext )
2021-11-21 15:41:00 +00:00
if err != nil {
2019-11-09 00:39:37 +00:00
return err
}
2021-11-21 15:41:00 +00:00
defer committer . Close ( )
2019-11-09 00:39:37 +00:00
2022-03-29 06:29:02 +00:00
if err = addAllRepositories ( ctx , t ) ; err != nil {
2019-11-09 00:39:37 +00:00
return err
}
2021-11-21 15:41:00 +00:00
return committer . Commit ( )
2019-11-09 00:39:37 +00:00
}
// RemoveAllRepositories removes all repositories from team and recalculates access
2022-03-29 06:29:02 +00:00
func RemoveAllRepositories ( t * organization . Team ) ( err error ) {
2019-11-09 00:39:37 +00:00
if t . IncludesAllRepositories {
return nil
}
2022-11-12 20:18:50 +00:00
ctx , committer , err := db . TxContext ( db . DefaultContext )
2021-11-21 15:41:00 +00:00
if err != nil {
2019-11-09 00:39:37 +00:00
return err
}
2021-11-21 15:41:00 +00:00
defer committer . Close ( )
2019-11-09 00:39:37 +00:00
2022-03-29 06:29:02 +00:00
if err = removeAllRepositories ( ctx , t ) ; err != nil {
2019-11-09 00:39:37 +00:00
return err
}
2021-11-21 15:41:00 +00:00
return committer . Commit ( )
2019-11-09 00:39:37 +00:00
}
// removeAllRepositories removes all repositories from team and recalculates access
// Note: Shall not be called if team includes all repositories
2022-03-29 06:29:02 +00:00
func removeAllRepositories ( ctx context . Context , t * organization . Team ) ( err error ) {
2021-12-10 01:27:50 +00:00
e := db . GetEngine ( ctx )
2019-11-09 00:39:37 +00:00
// Delete all accesses.
for _ , repo := range t . Repos {
2022-05-11 10:09:36 +00:00
if err := access_model . RecalculateTeamAccesses ( ctx , repo , t . ID ) ; err != nil {
2019-11-09 00:39:37 +00:00
return err
}
// Remove watches from all users and now unaccessible repos
for _ , user := range t . Members {
2022-05-11 10:09:36 +00:00
has , err := access_model . HasAccess ( ctx , user . ID , repo )
2019-11-09 00:39:37 +00:00
if err != nil {
return err
} else if has {
continue
}
2022-05-20 14:08:52 +00:00
if err = repo_model . WatchRepo ( ctx , user . ID , repo . ID , false ) ; err != nil {
2019-11-09 00:39:37 +00:00
return err
}
// Remove all IssueWatches a user has subscribed to in the repositories
2022-06-13 09:37:59 +00:00
if err = issues_model . RemoveIssueWatchersByRepoID ( ctx , user . ID , repo . ID ) ; err != nil {
2019-11-09 00:39:37 +00:00
return err
}
}
}
// Delete team-repo
if _ , err := e .
Where ( "team_id=?" , t . ID ) .
2022-03-29 06:29:02 +00:00
Delete ( new ( organization . TeamRepo ) ) ; err != nil {
2019-11-09 00:39:37 +00:00
return err
}
t . NumRepos = 0
if _ , err = e . ID ( t . ID ) . Cols ( "num_repos" ) . Update ( t ) ; err != nil {
return err
}
return nil
}
2022-05-11 10:09:36 +00:00
// HasRepository returns true if given repository belong to team.
func HasRepository ( t * organization . Team , repoID int64 ) bool {
return organization . HasTeamRepo ( db . DefaultContext , t . OrgID , t . ID , repoID )
2022-03-29 06:29:02 +00:00
}
2019-11-06 09:37:14 +00:00
// removeRepository removes a repository from a team and recalculates access
// Note: Repository shall not be removed from team if it includes all repositories (unless the repository is deleted)
2022-03-29 06:29:02 +00:00
func removeRepository ( ctx context . Context , t * organization . Team , repo * repo_model . Repository , recalculate bool ) ( err error ) {
2021-12-10 01:27:50 +00:00
e := db . GetEngine ( ctx )
2022-03-29 06:29:02 +00:00
if err = organization . RemoveTeamRepo ( ctx , t . ID , repo . ID ) ; err != nil {
2016-03-25 22:04:02 +00:00
return err
}
t . NumRepos --
2017-10-05 04:43:04 +00:00
if _ , err = e . ID ( t . ID ) . Cols ( "num_repos" ) . Update ( t ) ; err != nil {
2016-03-25 22:04:02 +00:00
return err
}
// Don't need to recalculate when delete a repository from organization.
if recalculate {
2022-05-11 10:09:36 +00:00
if err = access_model . RecalculateTeamAccesses ( ctx , repo , t . ID ) ; err != nil {
2016-03-25 22:04:02 +00:00
return err
}
}
2022-03-29 06:29:02 +00:00
teamUsers , err := organization . GetTeamUsersByTeamID ( ctx , t . ID )
2017-03-15 00:51:46 +00:00
if err != nil {
2022-10-24 19:29:17 +00:00
return fmt . Errorf ( "getTeamUsersByTeamID: %w" , err )
2016-03-25 22:04:02 +00:00
}
2017-03-21 00:55:00 +00:00
for _ , teamUser := range teamUsers {
2022-05-11 10:09:36 +00:00
has , err := access_model . HasAccess ( ctx , teamUser . UID , repo )
2016-03-25 22:04:02 +00:00
if err != nil {
return err
} else if has {
continue
}
2022-05-20 14:08:52 +00:00
if err = repo_model . WatchRepo ( ctx , teamUser . UID , repo . ID , false ) ; err != nil {
2016-03-25 22:04:02 +00:00
return err
}
2018-06-19 19:44:33 +00:00
// Remove all IssueWatches a user has subscribed to in the repositories
2022-06-13 09:37:59 +00:00
if err := issues_model . RemoveIssueWatchersByRepoID ( ctx , teamUser . UID , repo . ID ) ; err != nil {
2018-06-19 19:44:33 +00:00
return err
}
2016-03-25 22:04:02 +00:00
}
return nil
}
// RemoveRepository removes repository from team of organization.
2019-11-06 09:37:14 +00:00
// If the team shall include all repositories the request is ignored.
2022-03-29 06:29:02 +00:00
func RemoveRepository ( t * organization . Team , repoID int64 ) error {
if ! HasRepository ( t , repoID ) {
2016-03-25 22:04:02 +00:00
return nil
}
2019-11-06 09:37:14 +00:00
if t . IncludesAllRepositories {
return nil
}
2022-12-03 02:48:26 +00:00
repo , err := repo_model . GetRepositoryByID ( db . DefaultContext , repoID )
2016-03-25 22:04:02 +00:00
if err != nil {
return err
}
2022-11-12 20:18:50 +00:00
ctx , committer , err := db . TxContext ( db . DefaultContext )
2021-11-21 15:41:00 +00:00
if err != nil {
2016-03-25 22:04:02 +00:00
return err
}
2021-11-21 15:41:00 +00:00
defer committer . Close ( )
2016-03-25 22:04:02 +00:00
2022-03-29 06:29:02 +00:00
if err = removeRepository ( ctx , t , repo , true ) ; err != nil {
2016-03-25 22:04:02 +00:00
return err
}
2021-11-21 15:41:00 +00:00
return committer . Commit ( )
2016-03-25 22:04:02 +00:00
}
// NewTeam creates a record of new team.
// It's caller's responsibility to assign organization ID.
2022-03-29 06:29:02 +00:00
func NewTeam ( t * organization . Team ) ( err error ) {
2016-03-25 22:04:02 +00:00
if len ( t . Name ) == 0 {
2022-12-31 11:49:37 +00:00
return util . NewInvalidArgumentErrorf ( "empty team name" )
2016-03-25 22:04:02 +00:00
}
2022-03-29 06:29:02 +00:00
if err = organization . IsUsableTeamName ( t . Name ) ; err != nil {
2016-11-06 09:07:03 +00:00
return err
}
2021-11-24 09:49:20 +00:00
has , err := db . GetEngine ( db . DefaultContext ) . ID ( t . OrgID ) . Get ( new ( user_model . User ) )
2016-03-25 22:04:02 +00:00
if err != nil {
return err
2019-06-12 19:41:28 +00:00
}
if ! has {
2022-03-29 06:29:02 +00:00
return organization . ErrOrgNotExist { ID : t . OrgID }
2016-03-25 22:04:02 +00:00
}
t . LowerName = strings . ToLower ( t . Name )
2021-09-23 15:45:36 +00:00
has , err = db . GetEngine ( db . DefaultContext ) .
2016-11-10 15:16:32 +00:00
Where ( "org_id=?" , t . OrgID ) .
And ( "lower_name=?" , t . LowerName ) .
2022-03-29 06:29:02 +00:00
Get ( new ( organization . Team ) )
2016-03-25 22:04:02 +00:00
if err != nil {
return err
2019-06-12 19:41:28 +00:00
}
if has {
2022-03-29 06:29:02 +00:00
return organization . ErrTeamAlreadyExist { OrgID : t . OrgID , Name : t . LowerName }
2016-03-25 22:04:02 +00:00
}
2022-11-12 20:18:50 +00:00
ctx , committer , err := db . TxContext ( db . DefaultContext )
2021-11-21 15:41:00 +00:00
if err != nil {
2016-03-25 22:04:02 +00:00
return err
}
2021-11-21 15:41:00 +00:00
defer committer . Close ( )
2016-03-25 22:04:02 +00:00
2021-11-21 15:41:00 +00:00
if err = db . Insert ( ctx , t ) ; err != nil {
2016-03-25 22:04:02 +00:00
return err
}
2018-06-21 16:00:13 +00:00
// insert units for team
if len ( t . Units ) > 0 {
for _ , unit := range t . Units {
unit . TeamID = t . ID
}
2021-11-21 15:41:00 +00:00
if err = db . Insert ( ctx , & t . Units ) ; err != nil {
2018-06-21 16:00:13 +00:00
return err
}
}
2019-11-06 09:37:14 +00:00
// Add all repositories to the team if it has access to all of them.
if t . IncludesAllRepositories {
2022-03-29 06:29:02 +00:00
err = addAllRepositories ( ctx , t )
2019-11-06 09:37:14 +00:00
if err != nil {
2022-10-24 19:29:17 +00:00
return fmt . Errorf ( "addAllRepositories: %w" , err )
2019-11-06 09:37:14 +00:00
}
}
2016-03-25 22:04:02 +00:00
// Update organization number of teams.
2021-11-21 15:41:00 +00:00
if _ , err = db . Exec ( ctx , "UPDATE `user` SET num_teams=num_teams+1 WHERE id = ?" , t . OrgID ) ; err != nil {
2016-03-25 22:04:02 +00:00
return err
}
2021-11-21 15:41:00 +00:00
return committer . Commit ( )
2016-03-25 22:04:02 +00:00
}
// UpdateTeam updates information of team.
2022-03-29 06:29:02 +00:00
func UpdateTeam ( t * organization . Team , authChanged , includeAllChanged bool ) ( err error ) {
2016-03-25 22:04:02 +00:00
if len ( t . Name ) == 0 {
2022-12-31 11:49:37 +00:00
return util . NewInvalidArgumentErrorf ( "empty team name" )
2016-03-25 22:04:02 +00:00
}
if len ( t . Description ) > 255 {
t . Description = t . Description [ : 255 ]
}
2022-11-12 20:18:50 +00:00
ctx , committer , err := db . TxContext ( db . DefaultContext )
2021-11-21 15:41:00 +00:00
if err != nil {
2016-03-25 22:04:02 +00:00
return err
}
2021-11-21 15:41:00 +00:00
defer committer . Close ( )
sess := db . GetEngine ( ctx )
2016-03-25 22:04:02 +00:00
t . LowerName = strings . ToLower ( t . Name )
2017-01-27 16:11:41 +00:00
has , err := sess .
2016-11-10 15:16:32 +00:00
Where ( "org_id=?" , t . OrgID ) .
And ( "lower_name=?" , t . LowerName ) .
And ( "id!=?" , t . ID ) .
2022-03-29 06:29:02 +00:00
Get ( new ( organization . Team ) )
2016-03-25 22:04:02 +00:00
if err != nil {
return err
} else if has {
2022-03-29 06:29:02 +00:00
return organization . ErrTeamAlreadyExist { OrgID : t . OrgID , Name : t . LowerName }
2016-03-25 22:04:02 +00:00
}
2020-01-09 13:15:14 +00:00
if _ , err = sess . ID ( t . ID ) . Cols ( "name" , "lower_name" , "description" ,
"can_create_org_repo" , "authorize" , "includes_all_repositories" ) . Update ( t ) ; err != nil {
2022-10-24 19:29:17 +00:00
return fmt . Errorf ( "update: %w" , err )
2016-03-25 22:04:02 +00:00
}
2018-11-10 19:45:32 +00:00
// update units for team
if len ( t . Units ) > 0 {
for _ , unit := range t . Units {
unit . TeamID = t . ID
}
// Delete team-unit.
if _ , err := sess .
Where ( "team_id=?" , t . ID ) .
2022-03-29 06:29:02 +00:00
Delete ( new ( organization . TeamUnit ) ) ; err != nil {
2018-11-10 19:45:32 +00:00
return err
}
2022-01-05 03:37:00 +00:00
if _ , err = sess . Cols ( "org_id" , "team_id" , "type" , "access_mode" ) . Insert ( & t . Units ) ; err != nil {
2018-11-10 19:45:32 +00:00
return err
}
}
2016-03-25 22:04:02 +00:00
// Update access for team members if needed.
if authChanged {
2022-12-03 02:48:26 +00:00
if err = t . LoadRepositories ( ctx ) ; err != nil {
return fmt . Errorf ( "LoadRepositories: %w" , err )
2016-03-25 22:04:02 +00:00
}
for _ , repo := range t . Repos {
2022-05-11 10:09:36 +00:00
if err = access_model . RecalculateTeamAccesses ( ctx , repo , 0 ) ; err != nil {
2022-10-24 19:29:17 +00:00
return fmt . Errorf ( "recalculateTeamAccesses: %w" , err )
2016-03-25 22:04:02 +00:00
}
}
}
2019-11-06 09:37:14 +00:00
// Add all repositories to the team if it has access to all of them.
if includeAllChanged && t . IncludesAllRepositories {
2022-03-29 06:29:02 +00:00
err = addAllRepositories ( ctx , t )
2019-11-06 09:37:14 +00:00
if err != nil {
2022-10-24 19:29:17 +00:00
return fmt . Errorf ( "addAllRepositories: %w" , err )
2019-11-06 09:37:14 +00:00
}
}
2021-11-21 15:41:00 +00:00
return committer . Commit ( )
2016-03-25 22:04:02 +00:00
}
// DeleteTeam deletes given team.
// It's caller's responsibility to assign organization ID.
2022-03-29 06:29:02 +00:00
func DeleteTeam ( t * organization . Team ) error {
2022-11-12 20:18:50 +00:00
ctx , committer , err := db . TxContext ( db . DefaultContext )
2021-11-21 15:41:00 +00:00
if err != nil {
2016-03-25 22:04:02 +00:00
return err
}
2021-11-21 15:41:00 +00:00
defer committer . Close ( )
2016-03-25 22:04:02 +00:00
2022-12-03 02:48:26 +00:00
if err := t . LoadRepositories ( ctx ) ; err != nil {
2022-03-29 06:29:02 +00:00
return err
}
2022-12-03 02:48:26 +00:00
if err := t . LoadMembers ( ctx ) ; err != nil {
2018-06-19 19:44:33 +00:00
return err
}
2022-03-22 01:09:45 +00:00
// update branch protections
{
2022-06-12 15:51:54 +00:00
protections := make ( [ ] * git_model . ProtectedBranch , 0 , 10 )
2023-01-16 08:00:22 +00:00
err := db . GetEngine ( ctx ) . In ( "repo_id" ,
2022-03-22 01:09:45 +00:00
builder . Select ( "id" ) . From ( "repository" ) . Where ( builder . Eq { "owner_id" : t . OrgID } ) ) .
Find ( & protections )
if err != nil {
2022-10-24 19:29:17 +00:00
return fmt . Errorf ( "findProtectedBranches: %w" , err )
2022-03-22 01:09:45 +00:00
}
for _ , p := range protections {
2023-01-16 08:00:22 +00:00
if err := git_model . RemoveTeamIDFromProtectedBranch ( ctx , p , t . ID ) ; err != nil {
return err
2022-03-22 01:09:45 +00:00
}
}
}
if ! t . IncludesAllRepositories {
2022-03-29 06:29:02 +00:00
if err := removeAllRepositories ( ctx , t ) ; err != nil {
2022-03-22 01:09:45 +00:00
return err
}
2017-02-23 01:36:15 +00:00
}
2022-10-19 12:40:28 +00:00
if err := db . DeleteBeans ( ctx ,
& organization . Team { ID : t . ID } ,
& organization . TeamUser { OrgID : t . OrgID , TeamID : t . ID } ,
& organization . TeamUnit { TeamID : t . ID } ,
& organization . TeamInvite { TeamID : t . ID } ,
2023-04-19 23:50:00 +00:00
& issues_model . Review { Type : issues_model . ReviewTypeRequest , ReviewerTeamID : t . ID } , // batch delete the binding relationship between team and PR (request review from team)
2022-10-19 12:40:28 +00:00
) ; err != nil {
2018-06-21 16:00:13 +00:00
return err
}
2023-04-24 19:52:38 +00:00
for _ , tm := range t . Members {
if e rr := removeInvalidOrgUser ( ctx , tm . ID , t . OrgID ) ; err != nil {
return err
}
}
2016-03-25 22:04:02 +00:00
// Update organization number of teams.
2023-01-16 08:00:22 +00:00
if _ , err := db . Exec ( ctx , "UPDATE `user` SET num_teams=num_teams-1 WHERE id=?" , t . OrgID ) ; err != nil {
2016-03-25 22:04:02 +00:00
return err
}
2021-11-21 15:41:00 +00:00
return committer . Commit ( )
2016-03-25 22:04:02 +00:00
}
// AddTeamMember adds new membership of given team to given organization,
// the user will have membership to given organization automatically when needed.
2022-03-29 06:29:02 +00:00
func AddTeamMember ( team * organization . Team , userID int64 ) error {
isAlreadyMember , err := organization . IsTeamMember ( db . DefaultContext , team . OrgID , team . ID , userID )
2017-12-21 07:43:26 +00:00
if err != nil || isAlreadyMember {
return err
2016-03-25 22:04:02 +00:00
}
2022-03-29 06:29:02 +00:00
if err := organization . AddOrgUser ( team . OrgID , userID ) ; err != nil {
2016-03-25 22:04:02 +00:00
return err
}
2022-11-12 20:18:50 +00:00
ctx , committer , err := db . TxContext ( db . DefaultContext )
2021-11-21 15:41:00 +00:00
if err != nil {
2016-03-25 22:04:02 +00:00
return err
}
2021-11-21 15:41:00 +00:00
defer committer . Close ( )
2016-03-25 22:04:02 +00:00
2022-05-14 13:30:19 +00:00
// check in transaction
isAlreadyMember , err = organization . IsTeamMember ( ctx , team . OrgID , team . ID , userID )
if err != nil || isAlreadyMember {
return err
}
2021-11-21 15:41:00 +00:00
sess := db . GetEngine ( ctx )
2022-03-29 06:29:02 +00:00
if err := db . Insert ( ctx , & organization . TeamUser {
2016-11-28 08:33:08 +00:00
UID : userID ,
2017-02-24 06:25:09 +00:00
OrgID : team . OrgID ,
TeamID : team . ID ,
} ) ; err != nil {
2016-03-25 22:04:02 +00:00
return err
2022-03-29 06:29:02 +00:00
} else if _ , err := sess . Incr ( "num_members" ) . ID ( team . ID ) . Update ( new ( organization . Team ) ) ; err != nil {
2016-03-25 22:04:02 +00:00
return err
}
2017-12-31 03:08:08 +00:00
team . NumMembers ++
2016-03-25 22:04:02 +00:00
// Give access to team repositories.
2022-04-01 01:53:18 +00:00
// update exist access if mode become bigger
subQuery := builder . Select ( "repo_id" ) . From ( "team_repo" ) .
Where ( builder . Eq { "team_id" : team . ID } )
if _ , err := sess . Where ( "user_id=?" , userID ) .
In ( "repo_id" , subQuery ) .
And ( "mode < ?" , team . AccessMode ) .
SetExpr ( "mode" , team . AccessMode ) .
2022-05-11 10:09:36 +00:00
Update ( new ( access_model . Access ) ) ; err != nil {
2022-10-24 19:29:17 +00:00
return fmt . Errorf ( "update user accesses: %w" , err )
2022-04-01 01:53:18 +00:00
}
// for not exist access
var repoIDs [ ] int64
accessSubQuery := builder . Select ( "repo_id" ) . From ( "access" ) . Where ( builder . Eq { "user_id" : userID } )
if err := sess . SQL ( subQuery . And ( builder . NotIn ( "repo_id" , accessSubQuery ) ) ) . Find ( & repoIDs ) ; err != nil {
2022-10-24 19:29:17 +00:00
return fmt . Errorf ( "select id accesses: %w" , err )
2022-04-01 01:53:18 +00:00
}
2022-05-11 10:09:36 +00:00
accesses := make ( [ ] * access_model . Access , 0 , 100 )
2022-04-01 01:53:18 +00:00
for i , repoID := range repoIDs {
2022-05-11 10:09:36 +00:00
accesses = append ( accesses , & access_model . Access { RepoID : repoID , UserID : userID , Mode : team . AccessMode } )
2022-04-01 01:53:18 +00:00
if ( i % 100 == 0 || i == len ( repoIDs ) - 1 ) && len ( accesses ) > 0 {
if err = db . Insert ( ctx , accesses ) ; err != nil {
2022-10-24 19:29:17 +00:00
return fmt . Errorf ( "insert new user accesses: %w" , err )
2019-01-27 09:25:21 +00:00
}
2022-04-01 01:53:18 +00:00
accesses = accesses [ : 0 ]
2018-06-19 19:44:33 +00:00
}
2016-03-25 22:04:02 +00:00
}
2022-12-03 02:48:26 +00:00
if err := committer . Commit ( ) ; err != nil {
return err
}
committer . Close ( )
// this behaviour may spend much time so run it in a goroutine
// FIXME: Update watch repos batchly
2022-04-01 01:53:18 +00:00
if setting . Service . AutoWatchNewRepos {
// Get team and its repositories.
2022-12-03 02:48:26 +00:00
if err := team . LoadRepositories ( db . DefaultContext ) ; err != nil {
2022-04-01 01:53:18 +00:00
log . Error ( "getRepositories failed: %v" , err )
}
go func ( repos [ ] * repo_model . Repository ) {
for _ , repo := range repos {
2022-05-20 14:08:52 +00:00
if err = repo_model . WatchRepo ( db . DefaultContext , userID , repo . ID , true ) ; err != nil {
2022-04-01 01:53:18 +00:00
log . Error ( "watch repo failed: %v" , err )
}
}
} ( team . Repos )
}
2022-12-03 02:48:26 +00:00
return nil
2016-03-25 22:04:02 +00:00
}
2022-03-29 06:29:02 +00:00
func removeTeamMember ( ctx context . Context , team * organization . Team , userID int64 ) error {
2021-11-19 11:41:40 +00:00
e := db . GetEngine ( ctx )
2022-03-29 06:29:02 +00:00
isMember , err := organization . IsTeamMember ( ctx , team . OrgID , team . ID , userID )
2017-12-21 07:43:26 +00:00
if err != nil || ! isMember {
return err
2016-03-25 22:04:02 +00:00
}
// Check if the user to delete is the last member in owner team.
2017-02-24 06:25:09 +00:00
if team . IsOwnerTeam ( ) && team . NumMembers == 1 {
2022-03-29 06:29:02 +00:00
return organization . ErrLastOrgOwner { UID : userID }
2016-03-25 22:04:02 +00:00
}
2017-02-24 06:25:09 +00:00
team . NumMembers --
2016-03-25 22:04:02 +00:00
2022-12-03 02:48:26 +00:00
if err := team . LoadRepositories ( ctx ) ; err != nil {
2016-03-25 22:04:02 +00:00
return err
}
2022-03-29 06:29:02 +00:00
if _ , err := e . Delete ( & organization . TeamUser {
2016-11-28 08:33:08 +00:00
UID : userID ,
2017-02-24 06:25:09 +00:00
OrgID : team . OrgID ,
TeamID : team . ID ,
} ) ; err != nil {
2016-03-25 22:04:02 +00:00
return err
2016-11-10 15:16:32 +00:00
} else if _ , err = e .
2017-10-05 04:43:04 +00:00
ID ( team . ID ) .
2017-09-25 04:59:27 +00:00
Cols ( "num_members" ) .
2017-02-24 06:25:09 +00:00
Update ( team ) ; err != nil {
2016-03-25 22:04:02 +00:00
return err
}
// Delete access to team repositories.
2017-02-24 06:25:09 +00:00
for _ , repo := range team . Repos {
2022-05-11 10:09:36 +00:00
if err := access_model . RecalculateUserAccess ( ctx , repo , userID ) ; err != nil {
2016-03-25 22:04:02 +00:00
return err
}
2018-06-19 19:44:33 +00:00
// Remove watches from now unaccessible
2021-12-10 01:27:50 +00:00
if err := reconsiderWatches ( ctx , repo , userID ) ; err != nil {
2018-06-19 19:44:33 +00:00
return err
}
2020-04-07 21:52:01 +00:00
// Remove issue assignments from now unaccessible
2021-12-10 01:27:50 +00:00
if err := reconsiderRepoIssuesAssignee ( ctx , repo , userID ) ; err != nil {
2018-06-19 19:44:33 +00:00
return err
}
2016-03-25 22:04:02 +00:00
}
2023-04-24 19:52:38 +00:00
return removeInvalidOrgUser ( ctx , userID , team . OrgID )
}
func removeInvalidOrgUser ( ctx context . Context , userID , orgID int64 ) error {
2018-02-23 08:42:02 +00:00
// Check if the user is a member of any team in the organization.
2023-04-24 19:52:38 +00:00
if count , err := db . GetEngine ( ctx ) . Count ( & organization . TeamUser {
2018-02-23 08:42:02 +00:00
UID : userID ,
2023-04-24 19:52:38 +00:00
OrgID : orgID ,
2018-02-23 08:42:02 +00:00
} ) ; err != nil {
return err
} else if count == 0 {
2023-04-24 19:52:38 +00:00
return removeOrgUser ( ctx , orgID , userID )
2018-02-23 08:42:02 +00:00
}
2016-03-25 22:04:02 +00:00
return nil
}
// RemoveTeamMember removes member from given team of given organization.
2022-03-29 06:29:02 +00:00
func RemoveTeamMember ( team * organization . Team , userID int64 ) error {
2022-11-12 20:18:50 +00:00
ctx , committer , err := db . TxContext ( db . DefaultContext )
2021-11-19 11:41:40 +00:00
if err != nil {
2016-03-25 22:04:02 +00:00
return err
}
2021-11-19 11:41:40 +00:00
defer committer . Close ( )
if err := removeTeamMember ( ctx , team , userID ) ; err != nil {
2016-03-25 22:04:02 +00:00
return err
}
2021-11-19 11:41:40 +00:00
return committer . Commit ( )
2016-03-25 22:04:02 +00:00
}