2014-06-25 08:44:48 +04:00
// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package models
2014-06-27 11:37:01 +04:00
import (
2014-07-03 00:42:16 +04:00
"errors"
2014-08-24 17:09:05 +04:00
"fmt"
2014-07-05 06:43:39 +04:00
"os"
2014-08-16 12:58:32 +04:00
"path"
2014-06-27 11:37:01 +04:00
"strings"
2014-08-16 12:58:32 +04:00
"github.com/Unknwon/com"
2014-08-24 17:09:05 +04:00
"github.com/go-xorm/xorm"
2014-08-16 12:58:32 +04:00
2014-06-27 11:37:01 +04:00
"github.com/gogits/gogs/modules/base"
)
2014-07-03 00:42:16 +04:00
var (
ErrOrgNotExist = errors . New ( "Organization does not exist" )
ErrTeamAlreadyExist = errors . New ( "Team already exist" )
2014-08-16 12:21:17 +04:00
ErrTeamNotExist = errors . New ( "Team does not exist" )
ErrTeamNameIllegal = errors . New ( "Team name contains illegal characters" )
ErrLastOrgOwner = errors . New ( "The user to remove is the last member in owner team" )
2014-07-03 00:42:16 +04:00
)
2014-06-30 00:30:41 +04:00
// IsOrgOwner returns true if given user is in the owner team.
func ( org * User ) IsOrgOwner ( uid int64 ) bool {
return IsOrganizationOwner ( org . Id , uid )
}
// IsOrgMember returns true if given user is member of organization.
func ( org * User ) IsOrgMember ( uid int64 ) bool {
return IsOrganizationMember ( org . Id , uid )
}
2014-08-16 12:21:17 +04:00
// GetTeam returns named team of organization.
func ( org * User ) GetTeam ( name string ) ( * Team , error ) {
return GetTeam ( org . Id , name )
}
2014-06-28 08:40:07 +04:00
// GetOwnerTeam returns owner team of organization.
func ( org * User ) GetOwnerTeam ( ) ( * Team , error ) {
2014-08-16 12:21:17 +04:00
return org . GetTeam ( OWNER_TEAM )
2014-06-28 08:40:07 +04:00
}
2014-06-28 23:43:25 +04:00
// GetTeams returns all teams that belong to organization.
func ( org * User ) GetTeams ( ) error {
return x . Where ( "org_id=?" , org . Id ) . Find ( & org . Teams )
}
// GetMembers returns all members of organization.
func ( org * User ) GetMembers ( ) error {
ous , err := GetOrgUsersByOrgId ( org . Id )
if err != nil {
return err
}
org . Members = make ( [ ] * User , len ( ous ) )
for i , ou := range ous {
org . Members [ i ] , err = GetUserById ( ou . Uid )
if err != nil {
return err
}
}
return nil
}
2014-08-15 14:29:41 +04:00
// AddMember adds new member to organization.
func ( org * User ) AddMember ( uid int64 ) error {
return AddOrgUser ( org . Id , uid )
}
// RemoveMember removes member from organization.
func ( org * User ) RemoveMember ( uid int64 ) error {
return RemoveOrgUser ( org . Id , uid )
}
2014-06-27 11:37:01 +04:00
// CreateOrganization creates record of a new organization.
func CreateOrganization ( org , owner * User ) ( * User , error ) {
if ! IsLegalName ( org . Name ) {
return nil , ErrUserNameIllegal
}
isExist , err := IsUserExist ( org . Name )
if err != nil {
return nil , err
} else if isExist {
return nil , ErrUserAlreadyExist
}
isExist , err = IsEmailUsed ( org . Email )
if err != nil {
return nil , err
} else if isExist {
return nil , ErrEmailAlreadyUsed
}
org . LowerName = strings . ToLower ( org . Name )
org . FullName = org . Name
org . Avatar = base . EncodeMd5 ( org . Email )
org . AvatarEmail = org . Email
// No password for organization.
org . NumTeams = 1
org . NumMembers = 1
sess := x . NewSession ( )
defer sess . Close ( )
if err = sess . Begin ( ) ; err != nil {
return nil , err
}
if _ , err = sess . Insert ( org ) ; err != nil {
sess . Rollback ( )
return nil , err
}
2014-07-05 06:43:39 +04:00
if err = os . MkdirAll ( UserPath ( org . Name ) , os . ModePerm ) ; err != nil {
sess . Rollback ( )
return nil , err
}
2014-06-27 11:37:01 +04:00
// Create default owner team.
t := & Team {
OrgId : org . Id ,
2014-08-11 07:11:18 +04:00
LowerName : strings . ToLower ( OWNER_TEAM ) ,
2014-06-27 11:37:01 +04:00
Name : OWNER_TEAM ,
Authorize : ORG_ADMIN ,
NumMembers : 1 ,
}
if _ , err = sess . Insert ( t ) ; err != nil {
sess . Rollback ( )
return nil , err
}
// Add initial creator to organization and owner team.
ou := & OrgUser {
2014-08-24 17:09:05 +04:00
Uid : owner . Id ,
OrgId : org . Id ,
IsOwner : true ,
NumTeams : 1 ,
2014-06-27 11:37:01 +04:00
}
if _ , err = sess . Insert ( ou ) ; err != nil {
sess . Rollback ( )
return nil , err
}
tu := & TeamUser {
Uid : owner . Id ,
OrgId : org . Id ,
TeamId : t . Id ,
}
if _ , err = sess . Insert ( tu ) ; err != nil {
sess . Rollback ( )
return nil , err
}
return org , sess . Commit ( )
}
2014-08-28 18:29:00 +04:00
// CountOrganizations returns number of organizations.
func CountOrganizations ( ) int64 {
count , _ := x . Where ( "type=1" ) . Count ( new ( User ) )
return count
}
2014-08-29 16:50:43 +04:00
// GetOrganizations returns given number of organizations with offset.
func GetOrganizations ( num , offset int ) ( [ ] * User , error ) {
orgs := make ( [ ] * User , 0 , num )
err := x . Limit ( num , offset ) . Where ( "type=1" ) . Asc ( "id" ) . Find ( & orgs )
return orgs , err
}
2014-06-28 08:40:07 +04:00
// TODO: need some kind of mechanism to record failure.
// DeleteOrganization completely and permanently deletes everything of organization.
func DeleteOrganization ( org * User ) ( err error ) {
if err := DeleteUser ( org ) ; err != nil {
return err
}
sess := x . NewSession ( )
defer sess . Close ( )
if err = sess . Begin ( ) ; err != nil {
return err
}
if _ , err = sess . Delete ( & Team { OrgId : org . Id } ) ; err != nil {
sess . Rollback ( )
return err
}
if _ , err = sess . Delete ( & OrgUser { OrgId : org . Id } ) ; err != nil {
sess . Rollback ( )
return err
}
if _ , err = sess . Delete ( & TeamUser { OrgId : org . Id } ) ; err != nil {
sess . Rollback ( )
return err
}
return sess . Commit ( )
}
2014-06-25 08:44:48 +04:00
// ________ ____ ___
// \_____ \_______ ____ | | \______ ___________
// / | \_ __ \/ ___\| | / ___// __ \_ __ \
// / | \ | \/ /_/ > | /\___ \\ ___/| | \/
// \_______ /__| \___ /|______//____ >\___ >__|
// \/ /_____/ \/ \/
// OrgUser represents an organization-user relation.
type OrgUser struct {
Id int64
2014-08-15 14:29:41 +04:00
Uid int64 ` xorm:"INDEX UNIQUE(s)" `
OrgId int64 ` xorm:"INDEX UNIQUE(s)" `
2014-06-25 08:44:48 +04:00
IsPublic bool
IsOwner bool
2014-08-24 17:09:05 +04:00
NumTeams int
2014-06-25 08:44:48 +04:00
}
2014-06-30 00:30:41 +04:00
// IsOrganizationOwner returns true if given user is in the owner team.
func IsOrganizationOwner ( orgId , uid int64 ) bool {
has , _ := x . Where ( "is_owner=?" , true ) . And ( "uid=?" , uid ) . And ( "org_id=?" , orgId ) . Get ( new ( OrgUser ) )
return has
}
// IsOrganizationMember returns true if given user is member of organization.
func IsOrganizationMember ( orgId , uid int64 ) bool {
has , _ := x . Where ( "uid=?" , uid ) . And ( "org_id=?" , orgId ) . Get ( new ( OrgUser ) )
return has
}
2014-08-15 14:29:41 +04:00
// IsPublicMembership returns ture if given user public his/her membership.
func IsPublicMembership ( orgId , uid int64 ) bool {
has , _ := x . Where ( "uid=?" , uid ) . And ( "org_id=?" , orgId ) . And ( "is_public=?" , true ) . Get ( new ( OrgUser ) )
return has
}
2014-06-25 08:44:48 +04:00
// GetOrgUsersByUserId returns all organization-user relations by user ID.
func GetOrgUsersByUserId ( uid int64 ) ( [ ] * OrgUser , error ) {
ous := make ( [ ] * OrgUser , 0 , 10 )
err := x . Where ( "uid=?" , uid ) . Find ( & ous )
return ous , err
}
2014-06-25 13:14:36 +04:00
// GetOrgUsersByOrgId returns all organization-user relations by organization ID.
func GetOrgUsersByOrgId ( orgId int64 ) ( [ ] * OrgUser , error ) {
ous := make ( [ ] * OrgUser , 0 , 10 )
err := x . Where ( "org_id=?" , orgId ) . Find ( & ous )
return ous , err
}
2014-08-15 14:29:41 +04:00
// ChangeOrgUserStatus changes public or private membership status.
func ChangeOrgUserStatus ( orgId , uid int64 , public bool ) error {
ou := new ( OrgUser )
has , err := x . Where ( "uid=?" , uid ) . And ( "org_id=?" , orgId ) . Get ( ou )
if err != nil {
return err
} else if ! has {
return nil
}
ou . IsPublic = public
_ , err = x . Id ( ou . Id ) . AllCols ( ) . Update ( ou )
return err
}
// AddOrgUser adds new user to given organization.
func AddOrgUser ( orgId , uid int64 ) error {
if IsOrganizationMember ( orgId , uid ) {
return nil
}
sess := x . NewSession ( )
defer sess . Close ( )
if err := sess . Begin ( ) ; err != nil {
return err
}
2014-08-24 17:09:05 +04:00
ou := & OrgUser {
Uid : uid ,
OrgId : orgId ,
}
2014-08-15 14:29:41 +04:00
if _ , err := sess . Insert ( ou ) ; err != nil {
sess . Rollback ( )
return err
} else if _ , err = sess . Exec ( "UPDATE `user` SET num_members = num_members + 1 WHERE id = ?" , orgId ) ; err != nil {
sess . Rollback ( )
return err
}
return sess . Commit ( )
}
// RemoveOrgUser removes user from given organization.
func RemoveOrgUser ( orgId , uid int64 ) error {
ou := new ( OrgUser )
has , err := x . Where ( "uid=?" , uid ) . And ( "org_id=?" , orgId ) . Get ( ou )
if err != nil {
return err
} else if ! has {
return nil
}
2014-08-24 17:09:05 +04:00
u , err := GetUserById ( uid )
if err != nil {
return err
}
org , err := GetUserById ( orgId )
if err != nil {
return err
}
2014-08-16 12:21:17 +04:00
// Check if the user to delete is the last member in owner team.
if IsOrganizationOwner ( orgId , uid ) {
t , err := org . GetOwnerTeam ( )
if err != nil {
return err
}
if t . NumMembers == 1 {
return ErrLastOrgOwner
}
}
2014-08-15 14:29:41 +04:00
sess := x . NewSession ( )
defer sess . Close ( )
if err := sess . Begin ( ) ; err != nil {
return err
}
if _ , err := sess . Id ( ou . Id ) . Delete ( ou ) ; err != nil {
sess . Rollback ( )
return err
} else if _ , err = sess . Exec ( "UPDATE `user` SET num_members = num_members - 1 WHERE id = ?" , orgId ) ; err != nil {
sess . Rollback ( )
return err
}
2014-08-24 17:09:05 +04:00
// Delete all repository accesses.
if err = org . GetRepositories ( ) ; err != nil {
sess . Rollback ( )
return err
}
access := & Access {
UserName : u . LowerName ,
}
for _ , repo := range org . Repos {
access . RepoName = path . Join ( org . LowerName , repo . LowerName )
if _ , err = sess . Delete ( access ) ; err != nil {
sess . Rollback ( )
return err
2014-08-27 12:39:36 +04:00
} else if err = WatchRepo ( u . Id , repo . Id , false ) ; err != nil {
sess . Rollback ( )
return err
2014-08-24 17:09:05 +04:00
}
}
// Delete member in his/her teams.
ts , err := GetUserTeams ( org . Id , u . Id )
if err != nil {
return err
}
for _ , t := range ts {
if err = removeTeamMemberWithSess ( org . Id , t . Id , u . Id , sess ) ; err != nil {
return err
}
}
2014-08-15 14:29:41 +04:00
return sess . Commit ( )
}
2014-08-16 12:21:17 +04:00
// ___________
// \__ ___/___ _____ _____
// | |_/ __ \\__ \ / \
// | |\ ___/ / __ \| Y Y \
// |____| \___ >____ /__|_| /
// \/ \/ \/
type AuthorizeType int
const (
ORG_READABLE AuthorizeType = iota + 1
ORG_WRITABLE
ORG_ADMIN
)
2014-08-26 14:11:15 +04:00
func AuthorizeToAccessType ( auth AuthorizeType ) AccessType {
if auth == ORG_READABLE {
return READABLE
}
return WRITABLE
}
2014-08-16 12:21:17 +04:00
const OWNER_TEAM = "Owners"
// Team represents a organization team.
type Team struct {
Id int64
OrgId int64 ` xorm:"INDEX" `
LowerName string
Name string
Description string
Authorize AuthorizeType
2014-08-16 12:58:32 +04:00
RepoIds string ` xorm:"TEXT" `
Repos [ ] * Repository ` xorm:"-" `
Members [ ] * User ` xorm:"-" `
2014-08-16 12:21:17 +04:00
NumRepos int
2014-08-16 12:58:32 +04:00
NumMembers int
2014-08-16 12:21:17 +04:00
}
2014-08-24 17:09:05 +04:00
// IsOwnerTeam returns true if team is owner team.
func ( t * Team ) IsOwnerTeam ( ) bool {
return t . Name == OWNER_TEAM
}
2014-08-16 12:21:17 +04:00
// IsTeamMember returns true if given user is a member of team.
func ( t * Team ) IsMember ( uid int64 ) bool {
return IsTeamMember ( t . OrgId , t . Id , uid )
}
2014-08-16 12:58:32 +04:00
// GetRepositories returns all repositories in team of organization.
func ( t * Team ) GetRepositories ( ) error {
idStrs := strings . Split ( t . RepoIds , "|" )
t . Repos = make ( [ ] * Repository , 0 , len ( idStrs ) )
for _ , str := range idStrs {
2014-08-24 17:09:05 +04:00
if len ( str ) == 0 {
continue
}
id := com . StrTo ( str [ 1 : ] ) . MustInt64 ( )
2014-08-16 12:58:32 +04:00
if id == 0 {
continue
}
repo , err := GetRepositoryById ( id )
if err != nil {
return err
}
t . Repos = append ( t . Repos , repo )
}
return nil
}
// GetMembers returns all members in team of organization.
2014-08-16 12:21:17 +04:00
func ( t * Team ) GetMembers ( ) ( err error ) {
t . Members , err = GetTeamMembers ( t . OrgId , t . Id )
return err
}
2014-08-16 12:58:32 +04:00
// AddMember adds new member to team of organization.
func ( t * Team ) AddMember ( uid int64 ) error {
return AddTeamMember ( t . OrgId , t . Id , uid )
}
// RemoveMember removes member from team of organization.
func ( t * Team ) RemoveMember ( uid int64 ) error {
return RemoveTeamMember ( t . OrgId , t . Id , uid )
}
2014-08-26 14:11:15 +04:00
// addAccessWithAuthorize inserts or updates access with given mode.
func addAccessWithAuthorize ( sess * xorm . Session , access * Access , mode AccessType ) error {
has , err := x . Get ( access )
if err != nil {
return fmt . Errorf ( "fail to get access: %v" , err )
}
access . Mode = mode
if has {
if _ , err = sess . Id ( access . Id ) . Update ( access ) ; err != nil {
return fmt . Errorf ( "fail to update access: %v" , err )
}
} else {
if _ , err = sess . Insert ( access ) ; err != nil {
return fmt . Errorf ( "fail to insert access: %v" , err )
}
}
return nil
}
// AddRepository adds new repository to team of organization.
func ( t * Team ) AddRepository ( repo * Repository ) ( err error ) {
idStr := "$" + com . ToStr ( repo . Id ) + "|"
if repo . OwnerId != t . OrgId {
return errors . New ( "Repository not belong to organization" )
} else if strings . Contains ( t . RepoIds , idStr ) {
return nil
}
if err = repo . GetOwner ( ) ; err != nil {
return err
} else if err = t . GetMembers ( ) ; err != nil {
return err
}
sess := x . NewSession ( )
defer sess . Close ( )
if err = sess . Begin ( ) ; err != nil {
return err
}
t . NumRepos ++
t . RepoIds += idStr
if _ , err = sess . Id ( t . Id ) . AllCols ( ) . Update ( t ) ; err != nil {
sess . Rollback ( )
return err
}
// Give access to team members.
mode := AuthorizeToAccessType ( t . Authorize )
for _ , u := range t . Members {
2014-09-13 05:36:26 +04:00
auth , err := GetHighestAuthorize ( t . OrgId , u . Id , repo . Id , t . Id )
2014-08-26 14:11:15 +04:00
if err != nil {
sess . Rollback ( )
return err
}
access := & Access {
UserName : u . LowerName ,
RepoName : path . Join ( repo . Owner . LowerName , repo . LowerName ) ,
}
2014-09-13 05:36:26 +04:00
if auth < t . Authorize {
2014-08-26 14:11:15 +04:00
if err = addAccessWithAuthorize ( sess , access , mode ) ; err != nil {
sess . Rollback ( )
return err
}
}
2014-08-27 12:39:36 +04:00
if err = WatchRepo ( u . Id , repo . Id , true ) ; err != nil {
sess . Rollback ( )
return err
}
2014-08-26 14:11:15 +04:00
}
return sess . Commit ( )
}
// RemoveRepository removes repository from team of organization.
func ( t * Team ) RemoveRepository ( repoId int64 ) error {
idStr := "$" + com . ToStr ( repoId ) + "|"
if ! strings . Contains ( t . RepoIds , idStr ) {
return nil
}
repo , err := GetRepositoryById ( repoId )
if err != nil {
return err
}
if err = repo . GetOwner ( ) ; err != nil {
return err
} else if err = t . GetMembers ( ) ; err != nil {
return err
}
sess := x . NewSession ( )
defer sess . Close ( )
if err = sess . Begin ( ) ; err != nil {
return err
}
t . NumRepos --
t . RepoIds = strings . Replace ( t . RepoIds , idStr , "" , 1 )
if _ , err = sess . Id ( t . Id ) . AllCols ( ) . Update ( t ) ; err != nil {
sess . Rollback ( )
return err
}
// Remove access to team members.
for _ , u := range t . Members {
2014-09-13 05:36:26 +04:00
auth , err := GetHighestAuthorize ( t . OrgId , u . Id , repo . Id , t . Id )
2014-08-26 14:11:15 +04:00
if err != nil {
sess . Rollback ( )
return err
}
access := & Access {
UserName : u . LowerName ,
RepoName : path . Join ( repo . Owner . LowerName , repo . LowerName ) ,
}
if auth == 0 {
if _ , err = sess . Delete ( access ) ; err != nil {
sess . Rollback ( )
return fmt . Errorf ( "fail to delete access: %v" , err )
2014-08-27 12:39:36 +04:00
} else if err = WatchRepo ( u . Id , repo . Id , false ) ; err != nil {
sess . Rollback ( )
return err
2014-08-26 14:11:15 +04:00
}
} else if auth < t . Authorize {
if err = addAccessWithAuthorize ( sess , access , AuthorizeToAccessType ( auth ) ) ; err != nil {
sess . Rollback ( )
return err
}
}
}
return sess . Commit ( )
}
2014-08-16 12:21:17 +04:00
// NewTeam creates a record of new team.
// It's caller's responsibility to assign organization ID.
func NewTeam ( t * Team ) error {
if ! IsLegalName ( t . Name ) {
return ErrTeamNameIllegal
}
has , err := x . Id ( t . OrgId ) . Get ( new ( User ) )
if err != nil {
return err
} else if ! has {
return ErrOrgNotExist
}
t . LowerName = strings . ToLower ( t . Name )
has , err = x . Where ( "org_id=?" , t . OrgId ) . And ( "lower_name=?" , t . LowerName ) . Get ( new ( Team ) )
if err != nil {
return err
} else if has {
return ErrTeamAlreadyExist
}
sess := x . NewSession ( )
defer sess . Close ( )
if err = sess . Begin ( ) ; err != nil {
return err
}
if _ , err = sess . Insert ( t ) ; err != nil {
sess . Rollback ( )
return err
}
// Update organization number of teams.
if _ , err = sess . Exec ( "UPDATE `user` SET num_teams = num_teams + 1 WHERE id = ?" , t . OrgId ) ; err != nil {
sess . Rollback ( )
return err
}
return sess . Commit ( )
}
// GetTeam returns team by given team name and organization.
func GetTeam ( orgId int64 , name string ) ( * Team , error ) {
t := & Team {
OrgId : orgId ,
LowerName : strings . ToLower ( name ) ,
}
has , err := x . Get ( t )
if err != nil {
return nil , err
} else if ! has {
return nil , ErrTeamNotExist
}
return t , nil
}
// GetTeamById returns team by given ID.
func GetTeamById ( teamId int64 ) ( * Team , error ) {
t := new ( Team )
has , err := x . Id ( teamId ) . Get ( t )
if err != nil {
return nil , err
} else if ! has {
return nil , ErrTeamNotExist
}
return t , nil
}
2014-08-24 17:09:05 +04:00
// GetHighestAuthorize returns highest repository authorize level for given user and team.
2014-09-13 05:36:26 +04:00
func GetHighestAuthorize ( orgId , uid , repoId , teamId int64 ) ( AuthorizeType , error ) {
2014-08-24 17:09:05 +04:00
ts , err := GetUserTeams ( orgId , uid )
if err != nil {
return 0 , err
}
var auth AuthorizeType = 0
for _ , t := range ts {
// Not current team and has given repository.
if t . Id != teamId && strings . Contains ( t . RepoIds , "$" + com . ToStr ( repoId ) + "|" ) {
// Fast return.
if t . Authorize == ORG_WRITABLE {
return ORG_WRITABLE , nil
}
if t . Authorize > auth {
auth = t . Authorize
}
}
}
2014-09-13 05:36:26 +04:00
2014-08-24 17:09:05 +04:00
return auth , nil
}
2014-08-16 12:21:17 +04:00
// UpdateTeam updates information of team.
2014-08-24 17:09:05 +04:00
func UpdateTeam ( t * Team , authChanged bool ) ( err error ) {
if ! IsLegalName ( t . Name ) {
return ErrTeamNameIllegal
}
2014-08-16 12:21:17 +04:00
if len ( t . Description ) > 255 {
t . Description = t . Description [ : 255 ]
}
2014-08-24 17:09:05 +04:00
sess := x . NewSession ( )
defer sess . Close ( )
if err = sess . Begin ( ) ; err != nil {
return err
}
// Update access for team members if needed.
if authChanged && ! t . IsOwnerTeam ( ) {
if err = t . GetRepositories ( ) ; err != nil {
return err
} else if err = t . GetMembers ( ) ; err != nil {
return err
}
// Get organization.
org , err := GetUserById ( t . OrgId )
if err != nil {
return err
}
2014-08-26 14:11:15 +04:00
// Update access.
mode := AuthorizeToAccessType ( t . Authorize )
2014-08-24 17:09:05 +04:00
for _ , repo := range t . Repos {
for _ , u := range t . Members {
// ORG_WRITABLE is the highest authorize level for now.
// Skip checking others if current team has this level.
if t . Authorize < ORG_WRITABLE {
2014-09-13 05:36:26 +04:00
auth , err := GetHighestAuthorize ( t . OrgId , u . Id , repo . Id , t . Id )
2014-08-24 17:09:05 +04:00
if err != nil {
sess . Rollback ( )
return err
}
if auth >= t . Authorize {
continue // Other team has higher or same authorize level.
}
}
2014-08-26 14:11:15 +04:00
access := & Access {
UserName : u . LowerName ,
RepoName : path . Join ( org . LowerName , repo . LowerName ) ,
}
if err = addAccessWithAuthorize ( sess , access , mode ) ; err != nil {
2014-08-24 17:09:05 +04:00
sess . Rollback ( )
return err
}
}
}
}
2014-08-16 12:21:17 +04:00
t . LowerName = strings . ToLower ( t . Name )
2014-08-24 17:09:05 +04:00
if _ , err = sess . Id ( t . Id ) . AllCols ( ) . Update ( t ) ; err != nil {
sess . Rollback ( )
return err
}
return sess . Commit ( )
}
// DeleteTeam deletes given team.
// It's caller's responsibility to assign organization ID.
func DeleteTeam ( t * Team ) error {
if err := t . GetRepositories ( ) ; err != nil {
return err
} else if err = t . GetMembers ( ) ; err != nil {
return err
}
// Get organization.
org , err := GetUserById ( t . OrgId )
if err != nil {
return err
}
sess := x . NewSession ( )
defer sess . Close ( )
if err = sess . Begin ( ) ; err != nil {
return err
}
// Delete all accesses.
for _ , repo := range t . Repos {
for _ , u := range t . Members {
2014-09-13 05:36:26 +04:00
auth , err := GetHighestAuthorize ( t . OrgId , u . Id , repo . Id , t . Id )
2014-08-24 17:09:05 +04:00
if err != nil {
sess . Rollback ( )
return err
}
2014-08-26 14:11:15 +04:00
access := & Access {
UserName : u . LowerName ,
RepoName : path . Join ( org . LowerName , repo . LowerName ) ,
}
2014-08-24 17:09:05 +04:00
if auth == 0 {
if _ , err = sess . Delete ( access ) ; err != nil {
sess . Rollback ( )
2014-08-26 14:11:15 +04:00
return fmt . Errorf ( "fail to delete access: %v" , err )
2014-08-24 17:09:05 +04:00
}
} else if auth < t . Authorize {
// Downgrade authorize level.
2014-08-26 14:11:15 +04:00
if err = addAccessWithAuthorize ( sess , access , AuthorizeToAccessType ( auth ) ) ; err != nil {
2014-08-24 17:09:05 +04:00
sess . Rollback ( )
return err
}
}
}
}
// Delete team-user.
if _ , err = sess . Where ( "org_id=?" , org . Id ) . Where ( "team_id=?" , t . Id ) . Delete ( new ( TeamUser ) ) ; err != nil {
sess . Rollback ( )
return err
}
// Delete team.
if _ , err = sess . Id ( t . Id ) . Delete ( new ( Team ) ) ; err != nil {
sess . Rollback ( )
return err
}
// Update organization number of teams.
if _ , err = sess . Exec ( "UPDATE `user` SET num_teams = num_teams - 1 WHERE id = ?" , t . OrgId ) ; err != nil {
sess . Rollback ( )
return err
}
return sess . Commit ( )
2014-08-16 12:21:17 +04:00
}
2014-06-25 08:44:48 +04:00
// ___________ ____ ___
// \__ ___/___ _____ _____ | | \______ ___________
// | |_/ __ \\__ \ / \| | / ___// __ \_ __ \
// | |\ ___/ / __ \| Y Y \ | /\___ \\ ___/| | \/
// |____| \___ >____ /__|_| /______//____ >\___ >__|
// \/ \/ \/ \/ \/
// TeamUser represents an team-user relation.
type TeamUser struct {
Id int64
Uid int64
OrgId int64 ` xorm:"INDEX" `
TeamId int64
}
2014-06-25 13:14:36 +04:00
2014-06-30 00:30:41 +04:00
// IsTeamMember returns true if given user is a member of team.
func IsTeamMember ( orgId , teamId , uid int64 ) bool {
has , _ := x . Where ( "uid=?" , uid ) . And ( "org_id=?" , orgId ) . And ( "team_id=?" , teamId ) . Get ( new ( TeamUser ) )
return has
}
2014-06-25 13:14:36 +04:00
// GetTeamMembers returns all members in given team of organization.
func GetTeamMembers ( orgId , teamId int64 ) ( [ ] * User , error ) {
2014-10-12 10:06:46 +04:00
us := make ( [ ] * User , 0 , 10 )
2014-10-12 10:39:00 +04:00
err := x . Sql ( "SELECT * FROM `user` JOIN `team_user` ON `team_user`.`team_id` = ? AND `team_user`.`uid` = `user`.`id`" , teamId ) . Find ( & us )
2014-10-11 09:24:36 +04:00
return us , err
2014-06-25 13:14:36 +04:00
}
2014-08-16 12:21:17 +04:00
2014-08-24 17:09:05 +04:00
// GetUserTeams returns all teams that user belongs to in given origanization.
func GetUserTeams ( orgId , uid int64 ) ( [ ] * Team , error ) {
tus := make ( [ ] * TeamUser , 0 , 5 )
if err := x . Where ( "uid=?" , uid ) . And ( "org_id=?" , orgId ) . Find ( & tus ) ; err != nil {
return nil , err
}
ts := make ( [ ] * Team , len ( tus ) )
for i , tu := range tus {
t := new ( Team )
has , err := x . Id ( tu . TeamId ) . Get ( t )
if err != nil {
return nil , err
} else if ! has {
return nil , ErrTeamNotExist
}
ts [ i ] = t
}
return ts , nil
}
2014-08-16 12:21:17 +04:00
// AddTeamMember adds new member to given team of given organization.
func AddTeamMember ( orgId , teamId , uid int64 ) error {
2014-08-24 17:09:05 +04:00
if IsTeamMember ( orgId , teamId , uid ) {
2014-08-16 12:21:17 +04:00
return nil
}
2014-08-24 17:09:05 +04:00
if err := AddOrgUser ( orgId , uid ) ; err != nil {
return err
}
2014-08-16 12:58:32 +04:00
// Get team and its repositories.
2014-08-16 12:21:17 +04:00
t , err := GetTeamById ( teamId )
if err != nil {
return err
}
t . NumMembers ++
2014-08-16 12:58:32 +04:00
if err = t . GetRepositories ( ) ; err != nil {
return err
}
// Get organization.
org , err := GetUserById ( orgId )
if err != nil {
return err
}
// Get user.
u , err := GetUserById ( uid )
if err != nil {
return err
}
2014-08-16 12:21:17 +04:00
sess := x . NewSession ( )
defer sess . Close ( )
if err = sess . Begin ( ) ; err != nil {
return err
}
tu := & TeamUser {
Uid : uid ,
OrgId : orgId ,
TeamId : teamId ,
}
if _ , err = sess . Insert ( tu ) ; err != nil {
sess . Rollback ( )
return err
} else if _ , err = sess . Id ( t . Id ) . Update ( t ) ; err != nil {
sess . Rollback ( )
return err
}
2014-08-16 12:58:32 +04:00
// Give access to team repositories.
2014-08-26 14:11:15 +04:00
mode := AuthorizeToAccessType ( t . Authorize )
2014-08-16 12:58:32 +04:00
for _ , repo := range t . Repos {
2014-09-13 05:36:26 +04:00
auth , err := GetHighestAuthorize ( t . OrgId , u . Id , repo . Id , teamId )
2014-08-24 17:09:05 +04:00
if err != nil {
2014-08-16 12:58:32 +04:00
sess . Rollback ( )
return err
}
2014-08-24 17:09:05 +04:00
2014-08-26 14:11:15 +04:00
access := & Access {
UserName : u . LowerName ,
RepoName : path . Join ( org . LowerName , repo . LowerName ) ,
}
2014-09-13 05:36:26 +04:00
if auth < t . Authorize {
2014-08-26 14:11:15 +04:00
if err = addAccessWithAuthorize ( sess , access , mode ) ; err != nil {
2014-08-24 17:09:05 +04:00
sess . Rollback ( )
return err
}
}
}
// We make sure it exists before.
ou := new ( OrgUser )
_ , err = sess . Where ( "uid=?" , uid ) . And ( "org_id=?" , orgId ) . Get ( ou )
if err != nil {
sess . Rollback ( )
return err
}
ou . NumTeams ++
if t . IsOwnerTeam ( ) {
ou . IsOwner = true
}
if _ , err = sess . Id ( ou . Id ) . AllCols ( ) . Update ( ou ) ; err != nil {
sess . Rollback ( )
return err
2014-08-16 12:58:32 +04:00
}
2014-08-16 12:21:17 +04:00
return sess . Commit ( )
}
2014-08-24 17:09:05 +04:00
func removeTeamMemberWithSess ( orgId , teamId , uid int64 , sess * xorm . Session ) error {
2014-08-16 12:21:17 +04:00
if ! IsTeamMember ( orgId , teamId , uid ) {
return nil
}
2014-08-16 12:58:32 +04:00
// Get team and its repositories.
t , err := GetTeamById ( teamId )
if err != nil {
return err
}
2014-08-24 17:09:05 +04:00
// Check if the user to delete is the last member in owner team.
if t . IsOwnerTeam ( ) && t . NumMembers == 1 {
return ErrLastOrgOwner
}
2014-08-16 12:58:32 +04:00
t . NumMembers --
if err = t . GetRepositories ( ) ; err != nil {
return err
}
// Get organization.
org , err := GetUserById ( orgId )
if err != nil {
return err
}
// Get user.
u , err := GetUserById ( uid )
if err != nil {
return err
}
2014-08-16 12:21:17 +04:00
tu := & TeamUser {
Uid : uid ,
OrgId : orgId ,
TeamId : teamId ,
}
if _ , err := sess . Delete ( tu ) ; err != nil {
sess . Rollback ( )
return err
2014-08-16 12:58:32 +04:00
} else if _ , err = sess . Id ( t . Id ) . AllCols ( ) . Update ( t ) ; err != nil {
2014-08-16 12:21:17 +04:00
sess . Rollback ( )
return err
}
2014-08-16 12:58:32 +04:00
// Delete access to team repositories.
for _ , repo := range t . Repos {
2014-09-13 05:36:26 +04:00
auth , err := GetHighestAuthorize ( t . OrgId , u . Id , repo . Id , teamId )
2014-08-24 17:09:05 +04:00
if err != nil {
2014-08-16 12:58:32 +04:00
sess . Rollback ( )
return err
}
2014-08-24 17:09:05 +04:00
2014-08-26 14:11:15 +04:00
access := & Access {
UserName : u . LowerName ,
RepoName : path . Join ( org . LowerName , repo . LowerName ) ,
}
2014-08-24 17:09:05 +04:00
// Delete access if this is the last team user belongs to.
if auth == 0 {
2014-08-26 14:11:15 +04:00
if _ , err = sess . Delete ( access ) ; err != nil {
sess . Rollback ( )
return fmt . Errorf ( "fail to delete access: %v" , err )
2014-08-27 12:39:36 +04:00
} else if err = WatchRepo ( u . Id , repo . Id , false ) ; err != nil {
sess . Rollback ( )
return err
2014-08-26 14:11:15 +04:00
}
2014-08-24 17:09:05 +04:00
} else if auth < t . Authorize {
// Downgrade authorize level.
2014-08-26 14:11:15 +04:00
if err = addAccessWithAuthorize ( sess , access , AuthorizeToAccessType ( auth ) ) ; err != nil {
sess . Rollback ( )
return err
2014-08-24 17:09:05 +04:00
}
}
}
// This must exist.
ou := new ( OrgUser )
_ , err = sess . Where ( "uid=?" , uid ) . And ( "org_id=?" , org . Id ) . Get ( ou )
if err != nil {
sess . Rollback ( )
return err
}
ou . NumTeams --
if t . IsOwnerTeam ( ) {
ou . IsOwner = false
}
if _ , err = sess . Id ( ou . Id ) . AllCols ( ) . Update ( ou ) ; err != nil {
sess . Rollback ( )
return err
2014-08-16 12:58:32 +04:00
}
2014-08-24 17:09:05 +04:00
return nil
}
2014-08-16 12:58:32 +04:00
2014-08-24 17:09:05 +04:00
// RemoveTeamMember removes member from given team of given organization.
func RemoveTeamMember ( orgId , teamId , uid int64 ) error {
sess := x . NewSession ( )
defer sess . Close ( )
if err := sess . Begin ( ) ; err != nil {
return err
}
if err := removeTeamMemberWithSess ( orgId , teamId , uid , sess ) ; err != nil {
return err
}
2014-08-16 12:21:17 +04:00
return sess . Commit ( )
}