2023-09-09 00:09:23 +03:00
// Copyright 2016 The Gogs Authors. All rights reserved.
// Copyright 2020 The Gitea Authors.
// SPDX-License-Identifier: MIT
package repository
import (
2023-09-16 17:39:12 +03:00
"context"
2024-11-28 00:12:26 +03:00
"fmt"
2023-09-16 17:39:12 +03:00
2023-09-09 00:09:23 +03:00
"code.gitea.io/gitea/models/db"
2024-11-28 00:12:26 +03:00
issues_model "code.gitea.io/gitea/models/issues"
2024-11-07 06:28:11 +03:00
"code.gitea.io/gitea/models/perm"
2023-09-09 00:09:23 +03:00
access_model "code.gitea.io/gitea/models/perm/access"
repo_model "code.gitea.io/gitea/models/repo"
2024-03-04 11:16:03 +03:00
user_model "code.gitea.io/gitea/models/user"
2024-11-07 06:28:11 +03:00
"xorm.io/builder"
2023-09-09 00:09:23 +03:00
)
2024-11-07 06:28:11 +03:00
func AddOrUpdateCollaborator ( ctx context . Context , repo * repo_model . Repository , u * user_model . User , mode perm . AccessMode ) error {
// only allow valid access modes, read, write and admin
if mode < perm . AccessModeRead || mode > perm . AccessModeAdmin {
return perm . ErrInvalidAccessMode
}
if err := repo . LoadOwner ( ctx ) ; err != nil {
return err
}
if user_model . IsUserBlockedBy ( ctx , u , repo . OwnerID ) || user_model . IsUserBlockedBy ( ctx , repo . Owner , u . ID ) {
return user_model . ErrBlockedUser
}
return db . WithTx ( ctx , func ( ctx context . Context ) error {
collaboration , has , err := db . Get [ repo_model . Collaboration ] ( ctx , builder . Eq {
"repo_id" : repo . ID ,
"user_id" : u . ID ,
} )
if err != nil {
return err
} else if has {
if collaboration . Mode == mode {
return nil
}
if _ , err = db . GetEngine ( ctx ) .
Where ( "repo_id=?" , repo . ID ) .
And ( "user_id=?" , u . ID ) .
Cols ( "mode" ) .
Update ( & repo_model . Collaboration {
Mode : mode ,
} ) ; err != nil {
return err
}
} else if err = db . Insert ( ctx , & repo_model . Collaboration {
RepoID : repo . ID ,
UserID : u . ID ,
Mode : mode ,
} ) ; err != nil {
return err
}
return access_model . RecalculateUserAccess ( ctx , repo , u . ID )
} )
}
2023-09-09 00:09:23 +03:00
// DeleteCollaboration removes collaboration relation between the user and repository.
2024-03-04 11:16:03 +03:00
func DeleteCollaboration ( ctx context . Context , repo * repo_model . Repository , collaborator * user_model . User ) ( err error ) {
2023-09-09 00:09:23 +03:00
collaboration := & repo_model . Collaboration {
RepoID : repo . ID ,
2024-03-04 11:16:03 +03:00
UserID : collaborator . ID ,
2023-09-09 00:09:23 +03:00
}
2023-09-16 17:39:12 +03:00
ctx , committer , err := db . TxContext ( ctx )
2023-09-09 00:09:23 +03:00
if err != nil {
return err
}
defer committer . Close ( )
2024-01-22 10:19:56 +03:00
if has , err := db . GetEngine ( ctx ) . Delete ( collaboration ) ; err != nil {
2023-09-09 00:09:23 +03:00
return err
2024-01-22 10:19:56 +03:00
} else if has == 0 {
return committer . Commit ( )
}
2024-03-04 11:16:03 +03:00
if err := repo . LoadOwner ( ctx ) ; err != nil {
return err
}
2024-01-22 10:19:56 +03:00
if err = access_model . RecalculateAccesses ( ctx , repo ) ; err != nil {
2023-09-09 00:09:23 +03:00
return err
}
2024-03-04 11:16:03 +03:00
if err = repo_model . WatchRepo ( ctx , collaborator , repo , false ) ; err != nil {
2023-09-09 00:09:23 +03:00
return err
}
2024-11-28 00:12:26 +03:00
if err = ReconsiderWatches ( ctx , repo , collaborator ) ; err != nil {
2023-09-09 00:09:23 +03:00
return err
}
// Unassign a user from any issue (s)he has been assigned to in the repository
2024-11-28 00:12:26 +03:00
if err := ReconsiderRepoIssuesAssignee ( ctx , repo , collaborator ) ; err != nil {
2023-09-09 00:09:23 +03:00
return err
}
return committer . Commit ( )
}
2024-11-28 00:12:26 +03:00
func ReconsiderRepoIssuesAssignee ( ctx context . Context , repo * repo_model . Repository , user * user_model . User ) error {
if canAssigned , err := access_model . CanBeAssigned ( ctx , user , repo , true ) ; err != nil || canAssigned {
return err
}
if _ , err := db . GetEngine ( ctx ) . Where ( builder . Eq { "assignee_id" : user . ID } ) .
In ( "issue_id" , builder . Select ( "id" ) . From ( "issue" ) . Where ( builder . Eq { "repo_id" : repo . ID } ) ) .
Delete ( & issues_model . IssueAssignees { } ) ; err != nil {
return fmt . Errorf ( "Could not delete assignee[%d] %w" , user . ID , err )
}
return nil
}
func ReconsiderWatches ( ctx context . Context , repo * repo_model . Repository , user * user_model . User ) error {
if has , err := access_model . HasAnyUnitAccess ( ctx , user . ID , repo ) ; err != nil || has {
return err
}
if err := repo_model . WatchRepo ( ctx , user , repo , false ) ; err != nil {
return err
}
// Remove all IssueWatches a user has subscribed to in the repository
return issues_model . RemoveIssueWatchersByRepoID ( ctx , user . ID , repo . ID )
}