@ -8,6 +8,12 @@ import (
"fmt"
"strings"
"time"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/util"
"github.com/Unknwon/com"
)
const (
@ -17,14 +23,43 @@ const (
// ProtectedBranch struct
type ProtectedBranch struct {
ID int64 ` xorm:"pk autoincr" `
RepoID int64 ` xorm:"UNIQUE(s)" `
BranchName string ` xorm:"UNIQUE(s)" `
CanPush bool
Created time . Time ` xorm:"-" `
CreatedUnix int64 ` xorm:"created" `
Updated time . Time ` xorm:"-" `
UpdatedUnix int64 ` xorm:"updated" `
ID int64 ` xorm:"pk autoincr" `
RepoID int64 ` xorm:"UNIQUE(s)" `
BranchName string ` xorm:"UNIQUE(s)" `
EnableWhitelist bool
WhitelistUserIDs [ ] int64 ` xorm:"JSON TEXT" `
WhitelistTeamIDs [ ] int64 ` xorm:"JSON TEXT" `
Created time . Time ` xorm:"-" `
CreatedUnix int64 ` xorm:"created" `
Updated time . Time ` xorm:"-" `
UpdatedUnix int64 ` xorm:"updated" `
}
// IsProtected returns if the branch is protected
func ( protectBranch * ProtectedBranch ) IsProtected ( ) bool {
return protectBranch . ID > 0
}
// CanUserPush returns if some user could push to this protected branch
func ( protectBranch * ProtectedBranch ) CanUserPush ( userID int64 ) bool {
if ! protectBranch . EnableWhitelist {
return false
}
if base . Int64sContains ( protectBranch . WhitelistUserIDs , userID ) {
return true
}
if len ( protectBranch . WhitelistTeamIDs ) == 0 {
return false
}
in , err := IsUserInTeams ( userID , protectBranch . WhitelistTeamIDs )
if err != nil {
log . Error ( 1 , "IsUserInTeams:" , err )
return false
}
return in
}
// GetProtectedBranchByRepoID getting protected branch by repo ID
@ -46,6 +81,73 @@ func GetProtectedBranchBy(repoID int64, BranchName string) (*ProtectedBranch, er
return rel , nil
}
// GetProtectedBranchByID getting protected branch by ID
func GetProtectedBranchByID ( id int64 ) ( * ProtectedBranch , error ) {
rel := & ProtectedBranch { ID : id }
has , err := x . Get ( rel )
if err != nil {
return nil , err
}
if ! has {
return nil , nil
}
return rel , nil
}
// UpdateProtectBranch saves branch protection options of repository.
// If ID is 0, it creates a new record. Otherwise, updates existing record.
// This function also performs check if whitelist user and team's IDs have been changed
// to avoid unnecessary whitelist delete and regenerate.
func UpdateProtectBranch ( repo * Repository , protectBranch * ProtectedBranch , whitelistUserIDs , whitelistTeamIDs [ ] int64 ) ( err error ) {
if err = repo . GetOwner ( ) ; err != nil {
return fmt . Errorf ( "GetOwner: %v" , err )
}
hasUsersChanged := ! util . IsSliceInt64Eq ( protectBranch . WhitelistUserIDs , whitelistUserIDs )
if hasUsersChanged {
protectBranch . WhitelistUserIDs = make ( [ ] int64 , 0 , len ( whitelistUserIDs ) )
for _ , userID := range whitelistUserIDs {
has , err := hasAccess ( x , userID , repo , AccessModeWrite )
if err != nil {
return fmt . Errorf ( "HasAccess [user_id: %d, repo_id: %d]: %v" , userID , protectBranch . RepoID , err )
} else if ! has {
continue // Drop invalid user ID
}
protectBranch . WhitelistUserIDs = append ( protectBranch . WhitelistUserIDs , userID )
}
}
// if the repo is in an orgniziation
hasTeamsChanged := ! util . IsSliceInt64Eq ( protectBranch . WhitelistTeamIDs , whitelistTeamIDs )
if hasTeamsChanged {
teams , err := GetTeamsWithAccessToRepo ( repo . OwnerID , repo . ID , AccessModeWrite )
if err != nil {
return fmt . Errorf ( "GetTeamsWithAccessToRepo [org_id: %d, repo_id: %d]: %v" , repo . OwnerID , repo . ID , err )
}
protectBranch . WhitelistTeamIDs = make ( [ ] int64 , 0 , len ( teams ) )
for i := range teams {
if teams [ i ] . HasWriteAccess ( ) && com . IsSliceContainsInt64 ( whitelistTeamIDs , teams [ i ] . ID ) {
protectBranch . WhitelistTeamIDs = append ( protectBranch . WhitelistTeamIDs , teams [ i ] . ID )
}
}
}
// Make sure protectBranch.ID is not 0 for whitelists
if protectBranch . ID == 0 {
if _ , err = x . Insert ( protectBranch ) ; err != nil {
return fmt . Errorf ( "Insert: %v" , err )
}
return nil
}
if _ , err = x . Id ( protectBranch . ID ) . AllCols ( ) . Update ( protectBranch ) ; err != nil {
return fmt . Errorf ( "Update: %v" , err )
}
return nil
}
// GetProtectedBranches get all protected branches
func ( repo * Repository ) GetProtectedBranches ( ) ( [ ] * ProtectedBranch , error ) {
protectedBranches := make ( [ ] * ProtectedBranch , 0 )
@ -53,7 +155,7 @@ func (repo *Repository) GetProtectedBranches() ([]*ProtectedBranch, error) {
}
// IsProtectedBranch checks if branch is protected
func ( repo * Repository ) IsProtectedBranch ( branchName string ) ( bool , error ) {
func ( repo * Repository ) IsProtectedBranch ( branchName string , doer * User ) ( bool , error ) {
protectedBranch := & ProtectedBranch {
RepoID : repo . ID ,
BranchName : branchName ,
@ -63,70 +165,12 @@ func (repo *Repository) IsProtectedBranch(branchName string) (bool, error) {
if err != nil {
return true , err
} else if has {
return true , nil
return ! protectedBranch . CanUserPush ( doer . ID ) , nil
}
return false , nil
}
// AddProtectedBranch add protection to branch
func ( repo * Repository ) AddProtectedBranch ( branchName string , canPush bool ) error {
protectedBranch := & ProtectedBranch {
RepoID : repo . ID ,
BranchName : branchName ,
}
has , err := x . Get ( protectedBranch )
if err != nil {
return err
} else if has {
return nil
}
sess := x . NewSession ( )
defer sess . Close ( )
if err = sess . Begin ( ) ; err != nil {
return err
}
protectedBranch . CanPush = canPush
if _ , err = sess . InsertOne ( protectedBranch ) ; err != nil {
return err
}
return sess . Commit ( )
}
// ChangeProtectedBranch access mode sets new access mode for the ProtectedBranch.
func ( repo * Repository ) ChangeProtectedBranch ( id int64 , canPush bool ) error {
ProtectedBranch := & ProtectedBranch {
RepoID : repo . ID ,
ID : id ,
}
has , err := x . Get ( ProtectedBranch )
if err != nil {
return fmt . Errorf ( "get ProtectedBranch: %v" , err )
} else if ! has {
return nil
}
if ProtectedBranch . CanPush == canPush {
return nil
}
ProtectedBranch . CanPush = canPush
sess := x . NewSession ( )
defer sess . Close ( )
if err = sess . Begin ( ) ; err != nil {
return err
}
if _ , err = sess . Id ( ProtectedBranch . ID ) . AllCols ( ) . Update ( ProtectedBranch ) ; err != nil {
return fmt . Errorf ( "update ProtectedBranch: %v" , err )
}
return sess . Commit ( )
}
// DeleteProtectedBranch removes ProtectedBranch relation between the user and repository.
func ( repo * Repository ) DeleteProtectedBranch ( id int64 ) ( err error ) {
protectedBranch := & ProtectedBranch {
@ -148,15 +192,3 @@ func (repo *Repository) DeleteProtectedBranch(id int64) (err error) {
return sess . Commit ( )
}
// newProtectedBranch insert one queue
func newProtectedBranch ( protectedBranch * ProtectedBranch ) error {
_ , err := x . InsertOne ( protectedBranch )
return err
}
// UpdateProtectedBranch update queue
func UpdateProtectedBranch ( protectedBranch * ProtectedBranch ) error {
_ , err := x . Update ( protectedBranch )
return err
}