2022-03-29 09:29:02 +03:00
// Copyright 2022 The Gitea Authors. All rights reserved.
2022-11-27 21:20:29 +03:00
// SPDX-License-Identifier: MIT
2022-03-29 09:29:02 +03:00
package organization
import (
"context"
2022-05-20 13:20:51 +03:00
"fmt"
2022-03-29 09:29:02 +03:00
"code.gitea.io/gitea/models/db"
2023-04-07 18:21:02 +03:00
"code.gitea.io/gitea/models/perm"
2024-09-12 06:53:40 +03:00
"code.gitea.io/gitea/models/unit"
2022-03-29 09:29:02 +03:00
user_model "code.gitea.io/gitea/models/user"
2024-09-12 06:53:40 +03:00
"code.gitea.io/gitea/modules/container"
2022-03-29 09:29:02 +03:00
"code.gitea.io/gitea/modules/log"
"xorm.io/builder"
)
// ________ ____ ___
// \_____ \_______ ____ | | \______ ___________
// / | \_ __ \/ ___\| | / ___// __ \_ __ \
// / | \ | \/ /_/ > | /\___ \\ ___/| | \/
// \_______ /__| \___ /|______//____ >\___ >__|
// \/ /_____/ \/ \/
// OrgUser represents an organization-user relation.
type OrgUser struct {
ID int64 ` xorm:"pk autoincr" `
UID int64 ` xorm:"INDEX UNIQUE(s)" `
OrgID int64 ` xorm:"INDEX UNIQUE(s)" `
IsPublic bool ` xorm:"INDEX" `
}
func init ( ) {
db . RegisterModel ( new ( OrgUser ) )
}
// GetOrganizationCount returns count of membership of organization of the user.
func GetOrganizationCount ( ctx context . Context , u * user_model . User ) ( int64 , error ) {
return db . GetEngine ( ctx ) .
Where ( "uid=?" , u . ID ) .
Count ( new ( OrgUser ) )
}
// IsOrganizationOwner returns true if given user is in the owner team.
func IsOrganizationOwner ( ctx context . Context , orgID , uid int64 ) ( bool , error ) {
ownerTeam , err := GetOwnerTeam ( ctx , orgID )
if err != nil {
if IsErrTeamNotExist ( err ) {
log . Error ( "Organization does not have owner team: %d" , orgID )
return false , nil
}
return false , err
}
return IsTeamMember ( ctx , orgID , ownerTeam . ID , uid )
}
2023-04-07 18:21:02 +03:00
// IsOrganizationAdmin returns true if given user is in the owner team or an admin team.
func IsOrganizationAdmin ( ctx context . Context , orgID , uid int64 ) ( bool , error ) {
teams , err := GetUserOrgTeams ( ctx , orgID , uid )
if err != nil {
return false , err
}
for _ , t := range teams {
if t . AccessMode >= perm . AccessModeAdmin {
return true , nil
}
}
return false , nil
}
2022-03-29 09:29:02 +03:00
// IsOrganizationMember returns true if given user is member of organization.
func IsOrganizationMember ( ctx context . Context , orgID , uid int64 ) ( bool , error ) {
return db . GetEngine ( ctx ) .
Where ( "uid=?" , uid ) .
And ( "org_id=?" , orgID ) .
Table ( "org_user" ) .
Exist ( )
}
// IsPublicMembership returns true if the given user's membership of given org is public.
2023-10-03 13:30:41 +03:00
func IsPublicMembership ( ctx context . Context , orgID , uid int64 ) ( bool , error ) {
return db . GetEngine ( ctx ) .
2022-03-29 09:29:02 +03:00
Where ( "uid=?" , uid ) .
And ( "org_id=?" , orgID ) .
And ( "is_public=?" , true ) .
Table ( "org_user" ) .
Exist ( )
}
// CanCreateOrgRepo returns true if user can create repo in organization
2022-12-10 05:46:31 +03:00
func CanCreateOrgRepo ( ctx context . Context , orgID , uid int64 ) ( bool , error ) {
return db . GetEngine ( ctx ) .
2022-03-29 09:29:02 +03:00
Where ( builder . Eq { "team.can_create_org_repo" : true } ) .
Join ( "INNER" , "team_user" , "team_user.team_id = team.id" ) .
And ( "team_user.uid = ?" , uid ) .
And ( "team_user.org_id = ?" , orgID ) .
Exist ( new ( Team ) )
}
2022-05-20 13:20:51 +03:00
// IsUserOrgOwner returns true if user is in the owner team of given organization.
2023-10-03 13:30:41 +03:00
func IsUserOrgOwner ( ctx context . Context , users user_model . UserList , orgID int64 ) map [ int64 ] bool {
2022-05-20 13:20:51 +03:00
results := make ( map [ int64 ] bool , len ( users ) )
for _ , user := range users {
results [ user . ID ] = false // Set default to false
}
2023-10-03 13:30:41 +03:00
ownerMaps , err := loadOrganizationOwners ( ctx , users , orgID )
2022-05-20 13:20:51 +03:00
if err == nil {
for _ , owner := range ownerMaps {
results [ owner . UID ] = true
}
}
return results
}
2024-09-12 06:53:40 +03:00
// GetOrgAssignees returns all users that have write access and can be assigned to issues
// of the any repository in the organization.
func GetOrgAssignees ( ctx context . Context , orgID int64 ) ( _ [ ] * user_model . User , err error ) {
e := db . GetEngine ( ctx )
userIDs := make ( [ ] int64 , 0 , 10 )
if err = e . Table ( "access" ) .
Join ( "INNER" , "repository" , "`repository`.id = `access`.repo_id" ) .
Where ( "`repository`.owner_id = ? AND `access`.mode >= ?" , orgID , perm . AccessModeWrite ) .
Select ( "user_id" ) .
Find ( & userIDs ) ; err != nil {
return nil , err
}
additionalUserIDs := make ( [ ] int64 , 0 , 10 )
if err = e . Table ( "team_user" ) .
Join ( "INNER" , "team_repo" , "`team_repo`.team_id = `team_user`.team_id" ) .
Join ( "INNER" , "team_unit" , "`team_unit`.team_id = `team_user`.team_id" ) .
Join ( "INNER" , "repository" , "`repository`.id = `team_repo`.repo_id" ) .
Where ( "`repository`.owner_id = ? AND (`team_unit`.access_mode >= ? OR (`team_unit`.access_mode = ? AND `team_unit`.`type` = ?))" ,
orgID , perm . AccessModeWrite , perm . AccessModeRead , unit . TypePullRequests ) .
Distinct ( "`team_user`.uid" ) .
Select ( "`team_user`.uid" ) .
Find ( & additionalUserIDs ) ; err != nil {
return nil , err
}
uniqueUserIDs := make ( container . Set [ int64 ] )
uniqueUserIDs . AddMultiple ( userIDs ... )
uniqueUserIDs . AddMultiple ( additionalUserIDs ... )
users := make ( [ ] * user_model . User , 0 , len ( uniqueUserIDs ) )
if len ( userIDs ) > 0 {
if err = e . In ( "id" , uniqueUserIDs . Values ( ) ) .
Where ( builder . Eq { "`user`.is_active" : true } ) .
OrderBy ( user_model . GetOrderByName ( ) ) .
Find ( & users ) ; err != nil {
return nil , err
}
}
return users , nil
}
2022-05-20 13:20:51 +03:00
func loadOrganizationOwners ( ctx context . Context , users user_model . UserList , orgID int64 ) ( map [ int64 ] * TeamUser , error ) {
if len ( users ) == 0 {
return nil , nil
}
ownerTeam , err := GetOwnerTeam ( ctx , orgID )
if err != nil {
if IsErrTeamNotExist ( err ) {
log . Error ( "Organization does not have owner team: %d" , orgID )
return nil , nil
}
return nil , err
}
userIDs := users . GetUserIDs ( )
ownerMaps := make ( map [ int64 ] * TeamUser )
err = db . GetEngine ( ctx ) . In ( "uid" , userIDs ) .
And ( "org_id=?" , orgID ) .
And ( "team_id=?" , ownerTeam . ID ) .
Find ( & ownerMaps )
if err != nil {
2022-10-24 22:29:17 +03:00
return nil , fmt . Errorf ( "find team users: %w" , err )
2022-05-20 13:20:51 +03:00
}
return ownerMaps , nil
}