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"
2015-02-23 10:15:53 +03:00
"fmt"
2014-07-05 06:43:39 +04:00
"os"
2014-06-27 11:37:01 +04:00
"strings"
"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" )
2014-07-03 00:42:16 +04:00
)
2014-12-13 04:30:32 +03:00
// IsOwnedBy returns true if given user is in the owner team.
func ( org * User ) IsOwnedBy ( uid int64 ) bool {
2014-06-30 00:30:41 +04:00
return IsOrganizationOwner ( org . Id , uid )
}
// IsOrgMember returns true if given user is member of organization.
func ( org * User ) IsOrgMember ( uid int64 ) bool {
2015-02-24 08:27:22 +03:00
return org . IsOrganization ( ) && IsOrganizationMember ( org . Id , uid )
2014-06-30 00:30:41 +04:00
}
2015-02-13 08:58:46 +03:00
func ( org * User ) getTeam ( e Engine , name string ) ( * Team , error ) {
return getTeam ( e , org . Id , name )
}
2014-08-16 12:21:17 +04:00
// GetTeam returns named team of organization.
func ( org * User ) GetTeam ( name string ) ( * Team , error ) {
2015-02-13 08:58:46 +03:00
return org . getTeam ( x , name )
}
func ( org * User ) getOwnerTeam ( e Engine ) ( * Team , error ) {
return org . getTeam ( e , OWNER_TEAM )
2014-08-16 12:21:17 +04:00
}
2014-06-28 08:40:07 +04:00
// GetOwnerTeam returns owner team of organization.
func ( org * User ) GetOwnerTeam ( ) ( * Team , error ) {
2015-02-13 08:58:46 +03:00
return org . getOwnerTeam ( x )
}
func ( org * User ) getTeams ( e Engine ) error {
return e . Where ( "org_id=?" , org . Id ) . Find ( & org . Teams )
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 {
2015-02-13 08:58:46 +03:00
return org . getTeams ( x )
2014-06-28 23:43:25 +04:00
}
// 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 {
2015-08-08 17:43:14 +03:00
org . Members [ i ] , err = GetUserByID ( ou . Uid )
2014-06-28 23:43:25 +04:00
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 )
}
2015-03-01 05:44:09 +03:00
func ( org * User ) removeOrgRepo ( e Engine , repoID int64 ) error {
return removeOrgRepo ( e , org . Id , repoID )
}
// RemoveOrgRepo removes all team-repository relations of organization.
func ( org * User ) RemoveOrgRepo ( repoID int64 ) error {
return org . removeOrgRepo ( x , repoID )
}
2014-11-21 21:10:00 +03:00
// IsOrgEmailUsed returns true if the e-mail has been used in organization account.
func IsOrgEmailUsed ( email string ) ( bool , error ) {
if len ( email ) == 0 {
return false , nil
}
return x . Get ( & User {
Email : email ,
Type : ORGANIZATION ,
} )
}
2014-06-27 11:37:01 +04:00
// CreateOrganization creates record of a new organization.
2015-03-27 00:11:47 +03:00
func CreateOrganization ( org , owner * User ) ( err error ) {
if err = IsUsableName ( org . Name ) ; err != nil {
return err
2014-06-27 11:37:01 +04:00
}
2015-02-23 02:24:49 +03:00
isExist , err := IsUserExist ( 0 , org . Name )
2014-06-27 11:37:01 +04:00
if err != nil {
2015-03-27 00:11:47 +03:00
return err
2014-06-27 11:37:01 +04:00
} else if isExist {
2015-03-27 00:11:47 +03:00
return ErrUserAlreadyExist { org . Name }
2014-06-27 11:37:01 +04:00
}
2014-11-21 21:10:00 +03:00
isExist , err = IsOrgEmailUsed ( org . Email )
2014-06-27 11:37:01 +04:00
if err != nil {
2015-03-27 00:11:47 +03:00
return err
2014-06-27 11:37:01 +04:00
} else if isExist {
2015-03-27 00:11:47 +03:00
return ErrEmailAlreadyUsed { org . Email }
2014-06-27 11:37:01 +04:00
}
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 ( )
2015-02-23 10:15:53 +03:00
defer sessionRelease ( sess )
2014-06-27 11:37:01 +04:00
if err = sess . Begin ( ) ; err != nil {
2015-03-27 00:11:47 +03:00
return err
2014-06-27 11:37:01 +04:00
}
if _ , err = sess . Insert ( org ) ; err != nil {
2015-03-27 00:11:47 +03:00
return fmt . Errorf ( "insert organization: %v" , err )
2014-07-05 06:43:39 +04:00
}
2014-06-27 11:37:01 +04:00
// Create default owner team.
t := & Team {
2015-02-23 10:15:53 +03:00
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 ,
2015-02-09 14:36:33 +03:00
Authorize : ACCESS_MODE_OWNER ,
2014-06-27 11:37:01 +04:00
NumMembers : 1 ,
}
if _ , err = sess . Insert ( t ) ; err != nil {
2015-03-27 00:11:47 +03:00
return fmt . Errorf ( "insert owner team: %v" , err )
2014-06-27 11:37:01 +04:00
}
// Add initial creator to organization and owner team.
ou := & OrgUser {
2014-08-24 17:09:05 +04:00
Uid : owner . Id ,
2015-02-23 10:15:53 +03:00
OrgID : org . Id ,
2014-08-24 17:09:05 +04:00
IsOwner : true ,
NumTeams : 1 ,
2014-06-27 11:37:01 +04:00
}
if _ , err = sess . Insert ( ou ) ; err != nil {
2015-03-27 00:11:47 +03:00
return fmt . Errorf ( "insert org-user relation: %v" , err )
2014-06-27 11:37:01 +04:00
}
tu := & TeamUser {
Uid : owner . Id ,
2015-02-23 10:15:53 +03:00
OrgID : org . Id ,
TeamID : t . ID ,
2014-06-27 11:37:01 +04:00
}
if _ , err = sess . Insert ( tu ) ; err != nil {
2015-03-27 00:11:47 +03:00
return fmt . Errorf ( "insert team-user relation: %v" , err )
2015-02-23 10:15:53 +03:00
}
if err = os . MkdirAll ( UserPath ( org . Name ) , os . ModePerm ) ; err != nil {
2015-03-27 00:11:47 +03:00
return fmt . Errorf ( "create directory: %v" , err )
2014-06-27 11:37:01 +04:00
}
2015-03-27 00:11:47 +03:00
return sess . Commit ( )
2014-06-27 11:37:01 +04:00
}
2014-12-13 04:30:32 +03:00
// GetOrgByName returns organization by given name.
func GetOrgByName ( name string ) ( * User , error ) {
if len ( name ) == 0 {
return nil , ErrOrgNotExist
}
u := & User {
LowerName : strings . ToLower ( name ) ,
Type : ORGANIZATION ,
}
has , err := x . Get ( u )
if err != nil {
return nil , err
} else if ! has {
return nil , ErrOrgNotExist
}
return u , nil
}
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
}
2015-02-23 10:15:53 +03:00
if _ , err = sess . Delete ( & Team { OrgID : org . Id } ) ; err != nil {
2014-06-28 08:40:07 +04:00
sess . Rollback ( )
return err
}
2015-02-23 10:15:53 +03:00
if _ , err = sess . Delete ( & OrgUser { OrgID : org . Id } ) ; err != nil {
2014-06-28 08:40:07 +04:00
sess . Rollback ( )
return err
}
2015-02-23 10:15:53 +03:00
if _ , err = sess . Delete ( & TeamUser { OrgID : org . Id } ) ; err != nil {
2014-06-28 08:40:07 +04:00
sess . Rollback ( )
return err
}
return sess . Commit ( )
}
2014-06-25 08:44:48 +04:00
// ________ ____ ___
// \_____ \_______ ____ | | \______ ___________
// / | \_ __ \/ ___\| | / ___// __ \_ __ \
// / | \ | \/ /_/ > | /\___ \\ ___/| | \/
// \_______ /__| \___ /|______//____ >\___ >__|
// \/ /_____/ \/ \/
// OrgUser represents an organization-user relation.
type OrgUser struct {
2015-02-23 10:15:53 +03:00
ID int64 ` xorm:"pk autoincr" `
2014-08-15 14:29:41 +04:00
Uid int64 ` xorm:"INDEX UNIQUE(s)" `
2015-02-23 10:15:53 +03:00
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-12-07 04:22:48 +03:00
// IsPublicMembership returns true if given user public his/her membership.
2014-08-15 14:29:41 +04:00
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
2015-02-23 10:15:53 +03:00
_ , err = x . Id ( ou . ID ) . AllCols ( ) . Update ( ou )
2014-08-15 14:29:41 +04:00
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 ,
2015-02-23 10:15:53 +03:00
OrgID : orgId ,
2014-08-24 17:09:05 +04:00
}
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 {
2015-03-18 04:51:39 +03:00
return fmt . Errorf ( "get org-user: %v" , err )
2014-08-15 14:29:41 +04:00
} else if ! has {
return nil
}
2015-08-08 17:43:14 +03:00
u , err := GetUserByID ( uid )
2014-08-24 17:09:05 +04:00
if err != nil {
2015-03-18 04:51:39 +03:00
return fmt . Errorf ( "GetUserById: %v" , err )
2014-08-24 17:09:05 +04:00
}
2015-08-08 17:43:14 +03:00
org , err := GetUserByID ( orgId )
2014-08-24 17:09:05 +04:00
if err != nil {
2015-03-18 04:51:39 +03:00
return fmt . Errorf ( "get organization: %v" , err )
} else if err = org . GetRepositories ( ) ; err != nil {
return fmt . Errorf ( "GetRepositories: %v" , err )
2014-08-24 17:09:05 +04:00
}
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 {
2015-03-18 04:51:39 +03:00
return ErrLastOrgOwner { UID : uid }
2014-08-16 12:21:17 +04:00
}
}
2014-08-15 14:29:41 +04:00
sess := x . NewSession ( )
2015-03-18 04:51:39 +03:00
defer sessionRelease ( sess )
2014-08-15 14:29:41 +04:00
if err := sess . Begin ( ) ; err != nil {
return err
}
2015-02-23 10:15:53 +03:00
if _ , err := sess . Id ( ou . ID ) . Delete ( ou ) ; err != nil {
2014-08-15 14:29:41 +04:00
return err
2015-03-18 04:51:39 +03:00
} else if _ , err = sess . Exec ( "UPDATE `user` SET num_members=num_members-1 WHERE id=?" , orgId ) ; err != nil {
2014-08-15 14:29:41 +04:00
return err
}
2014-08-24 17:09:05 +04:00
// Delete all repository accesses.
2015-03-18 04:51:39 +03:00
access := & Access { UserID : u . Id }
2014-08-24 17:09:05 +04:00
for _ , repo := range org . Repos {
2015-08-08 17:43:14 +03:00
access . RepoID = repo . ID
2014-08-24 17:09:05 +04:00
if _ , err = sess . Delete ( access ) ; err != nil {
return err
2015-08-08 17:43:14 +03:00
} else if err = watchRepo ( sess , u . Id , repo . ID , false ) ; err != nil {
2014-08-27 12:39:36 +04:00
return err
2014-08-24 17:09:05 +04:00
}
}
// Delete member in his/her teams.
2015-03-18 04:51:39 +03:00
teams , err := getUserTeams ( sess , org . Id , u . Id )
2014-08-24 17:09:05 +04:00
if err != nil {
return err
}
2015-03-18 04:51:39 +03:00
for _ , t := range teams {
2015-02-23 10:15:53 +03:00
if err = removeTeamMember ( sess , org . Id , t . ID , u . Id ) ; err != nil {
2014-08-24 17:09:05 +04:00
return err
}
}
2014-08-15 14:29:41 +04:00
return sess . Commit ( )
}
2014-08-16 12:21:17 +04:00
// ___________
// \__ ___/___ _____ _____
// | |_/ __ \\__ \ / \
// | |\ ___/ / __ \| Y Y \
// |____| \___ >____ /__|_| /
// \/ \/ \/
const OWNER_TEAM = "Owners"
// Team represents a organization team.
type Team struct {
2015-02-23 10:15:53 +03:00
ID int64 ` xorm:"pk autoincr" `
OrgID int64 ` xorm:"INDEX" `
2014-08-16 12:21:17 +04:00
LowerName string
Name string
Description string
2015-02-05 16:29:08 +03:00
Authorize AccessMode
2014-08-16 12:58:32 +04:00
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 {
2015-02-23 10:15:53 +03:00
return IsTeamMember ( t . OrgID , t . ID , uid )
2014-08-16 12:21:17 +04:00
}
2015-02-23 10:15:53 +03:00
func ( t * Team ) getRepositories ( e Engine ) ( err error ) {
teamRepos := make ( [ ] * TeamRepo , 0 , t . NumRepos )
if err = x . Where ( "team_id=?" , t . ID ) . Find ( & teamRepos ) ; err != nil {
return fmt . Errorf ( "get team-repos: %v" , err )
}
t . Repos = make ( [ ] * Repository , 0 , len ( teamRepos ) )
for i := range teamRepos {
2015-08-08 17:43:14 +03:00
repo , err := getRepositoryByID ( e , teamRepos [ i ] . RepoID )
2014-08-16 12:58:32 +04:00
if err != nil {
2015-02-23 10:15:53 +03:00
return fmt . Errorf ( "getRepositoryById(%d): %v" , teamRepos [ i ] . RepoID , err )
2014-08-16 12:58:32 +04:00
}
t . Repos = append ( t . Repos , repo )
}
return nil
}
2015-02-13 08:58:46 +03:00
// GetRepositories returns all repositories in team of organization.
func ( t * Team ) GetRepositories ( ) error {
return t . getRepositories ( x )
}
func ( t * Team ) getMembers ( e Engine ) ( err error ) {
2015-02-23 10:15:53 +03:00
t . Members , err = getTeamMembers ( e , t . ID )
2015-02-13 08:58:46 +03:00
return err
}
2014-08-16 12:58:32 +04:00
// GetMembers returns all members in team of organization.
2014-08-16 12:21:17 +04:00
func ( t * Team ) GetMembers ( ) ( err error ) {
2015-02-13 08:58:46 +03:00
return t . getMembers ( x )
2014-08-16 12:21:17 +04:00
}
2014-08-16 12:58:32 +04:00
// AddMember adds new member to team of organization.
func ( t * Team ) AddMember ( uid int64 ) error {
2015-02-23 10:15:53 +03:00
return AddTeamMember ( t . OrgID , t . ID , uid )
2014-08-16 12:58:32 +04:00
}
// RemoveMember removes member from team of organization.
func ( t * Team ) RemoveMember ( uid int64 ) error {
2015-02-23 10:15:53 +03:00
return RemoveTeamMember ( t . OrgID , t . ID , uid )
2014-08-16 12:58:32 +04:00
}
2015-02-23 10:15:53 +03:00
func ( t * Team ) hasRepository ( e Engine , repoID int64 ) bool {
return hasTeamRepo ( e , t . OrgID , t . ID , repoID )
}
2014-08-26 14:11:15 +04:00
2015-02-23 10:15:53 +03:00
// HasRepository returns true if given repository belong to team.
func ( t * Team ) HasRepository ( repoID int64 ) bool {
return HasTeamRepo ( t . OrgID , t . ID , repoID )
}
2014-08-26 14:11:15 +04:00
2015-02-23 10:15:53 +03:00
func ( t * Team ) addRepository ( e Engine , repo * Repository ) ( err error ) {
2015-08-08 17:43:14 +03:00
if err = addTeamRepo ( e , t . OrgID , t . ID , repo . ID ) ; err != nil {
2014-08-26 14:11:15 +04:00
return err
}
t . NumRepos ++
2015-02-23 10:15:53 +03:00
if _ , err = e . Id ( t . ID ) . AllCols ( ) . Update ( t ) ; err != nil {
2015-02-24 08:27:22 +03:00
return fmt . Errorf ( "update team: %v" , err )
2014-08-26 14:11:15 +04:00
}
2015-03-01 05:44:09 +03:00
if err = repo . recalculateTeamAccesses ( e , 0 ) ; err != nil {
2015-02-24 08:27:22 +03:00
return fmt . Errorf ( "recalculateAccesses: %v" , err )
2015-02-05 16:29:08 +03:00
}
2014-08-26 14:11:15 +04:00
2015-02-23 10:15:53 +03:00
if err = t . getMembers ( e ) ; err != nil {
2015-02-24 08:27:22 +03:00
return fmt . Errorf ( "getMembers: %v" , err )
2015-02-23 10:15:53 +03:00
}
2014-08-26 14:11:15 +04:00
for _ , u := range t . Members {
2015-08-08 17:43:14 +03:00
if err = watchRepo ( e , u . Id , repo . ID , true ) ; err != nil {
2015-02-24 08:27:22 +03:00
return fmt . Errorf ( "watchRepo: %v" , err )
2014-08-27 12:39:36 +04:00
}
2014-08-26 14:11:15 +04:00
}
2015-02-23 10:15:53 +03:00
return nil
2015-02-05 16:29:08 +03:00
}
2015-02-23 10:15:53 +03:00
// AddRepository adds new repository to team of organization.
func ( t * Team ) AddRepository ( repo * Repository ) ( err error ) {
2015-08-08 17:43:14 +03:00
if repo . OwnerID != t . OrgID {
2015-02-23 10:15:53 +03:00
return errors . New ( "Repository does not belong to organization" )
2015-08-08 17:43:14 +03:00
} else if t . HasRepository ( repo . ID ) {
2014-08-26 14:11:15 +04:00
return nil
}
2015-02-23 10:15:53 +03:00
sess := x . NewSession ( )
defer sessionRelease ( sess )
if err = sess . Begin ( ) ; err != nil {
2014-08-26 14:11:15 +04:00
return err
}
2015-02-23 10:15:53 +03:00
if err = t . addRepository ( sess , repo ) ; err != nil {
2014-08-26 14:11:15 +04:00
return err
}
2015-02-23 10:15:53 +03:00
return sess . Commit ( )
}
2015-03-01 05:44:09 +03:00
func ( t * Team ) removeRepository ( e Engine , repo * Repository , recalculate bool ) ( err error ) {
2015-08-08 17:43:14 +03:00
if err = removeTeamRepo ( e , t . ID , repo . ID ) ; err != nil {
2014-08-26 14:11:15 +04:00
return err
}
t . NumRepos --
2015-02-23 10:15:53 +03:00
if _ , err = e . Id ( t . ID ) . AllCols ( ) . Update ( t ) ; err != nil {
2014-08-26 14:11:15 +04:00
return err
}
2015-03-01 05:44:09 +03:00
// Don't need to recalculate when delete a repository from organization.
if recalculate {
if err = repo . recalculateTeamAccesses ( e , t . ID ) ; err != nil {
return err
}
2015-02-05 16:29:08 +03:00
}
2015-02-23 10:15:53 +03:00
if err = t . getMembers ( e ) ; err != nil {
return fmt . Errorf ( "get team members: %v" , err )
}
2014-08-26 14:11:15 +04:00
for _ , u := range t . Members {
2015-02-23 10:15:53 +03:00
has , err := hasAccess ( e , u , repo , ACCESS_MODE_READ )
if err != nil {
2014-08-26 14:11:15 +04:00
return err
2015-02-23 10:15:53 +03:00
} else if has {
continue
2014-08-26 14:11:15 +04:00
}
2015-02-23 10:15:53 +03:00
2015-08-08 17:43:14 +03:00
if err = watchRepo ( e , u . Id , repo . ID , false ) ; err != nil {
2015-02-23 10:15:53 +03:00
return err
}
}
return nil
}
// RemoveRepository removes repository from team of organization.
func ( t * Team ) RemoveRepository ( repoID int64 ) error {
if ! t . HasRepository ( repoID ) {
return nil
}
2015-08-08 17:43:14 +03:00
repo , err := GetRepositoryByID ( repoID )
2015-02-23 10:15:53 +03:00
if err != nil {
return err
}
sess := x . NewSession ( )
defer sessionRelease ( sess )
if err = sess . Begin ( ) ; err != nil {
return err
}
2015-03-01 05:44:09 +03:00
if err = t . removeRepository ( sess , repo , true ) ; err != nil {
2015-02-23 10:15:53 +03:00
return err
2014-08-26 14:11:15 +04:00
}
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.
2015-03-27 00:11:47 +03:00
func NewTeam ( t * Team ) ( err error ) {
if err = IsUsableName ( t . Name ) ; err != nil {
return err
2014-08-16 12:21:17 +04:00
}
2015-02-23 10:15:53 +03:00
has , err := x . Id ( t . OrgID ) . Get ( new ( User ) )
2014-08-16 12:21:17 +04:00
if err != nil {
return err
} else if ! has {
return ErrOrgNotExist
}
t . LowerName = strings . ToLower ( t . Name )
2015-02-23 10:15:53 +03:00
has , err = x . Where ( "org_id=?" , t . OrgID ) . And ( "lower_name=?" , t . LowerName ) . Get ( new ( Team ) )
2014-08-16 12:21:17 +04:00
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.
2015-03-01 05:44:09 +03:00
if _ , err = sess . Exec ( "UPDATE `user` SET num_teams=num_teams+1 WHERE id = ?" , t . OrgID ) ; err != nil {
2014-08-16 12:21:17 +04:00
sess . Rollback ( )
return err
}
return sess . Commit ( )
}
2015-02-13 08:58:46 +03:00
func getTeam ( e Engine , orgId int64 , name string ) ( * Team , error ) {
2014-08-16 12:21:17 +04:00
t := & Team {
2015-02-23 10:15:53 +03:00
OrgID : orgId ,
2014-08-16 12:21:17 +04:00
LowerName : strings . ToLower ( name ) ,
}
2015-02-13 08:58:46 +03:00
has , err := e . Get ( t )
2014-08-16 12:21:17 +04:00
if err != nil {
return nil , err
} else if ! has {
return nil , ErrTeamNotExist
}
return t , nil
}
2015-02-13 08:58:46 +03:00
// GetTeam returns team by given team name and organization.
func GetTeam ( orgId int64 , name string ) ( * Team , error ) {
return getTeam ( x , orgId , name )
}
2015-02-11 07:44:16 +03:00
func getTeamById ( e Engine , teamId int64 ) ( * Team , error ) {
2014-08-16 12:21:17 +04:00
t := new ( Team )
2015-02-11 07:44:16 +03:00
has , err := e . Id ( teamId ) . Get ( t )
2014-08-16 12:21:17 +04:00
if err != nil {
return nil , err
} else if ! has {
return nil , ErrTeamNotExist
}
return t , nil
}
2015-02-11 07:44:16 +03:00
// GetTeamById returns team by given ID.
func GetTeamById ( teamId int64 ) ( * Team , error ) {
return getTeamById ( x , teamId )
}
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 ) {
2015-03-27 00:11:47 +03:00
if err = IsUsableName ( t . Name ) ; err != nil {
return err
2014-08-24 17:09:05 +04:00
}
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 ( )
2015-02-13 08:58:46 +03:00
defer sessionRelease ( sess )
2014-08-24 17:09:05 +04:00
if err = sess . Begin ( ) ; err != nil {
return err
}
2015-02-14 00:12:33 +03:00
t . LowerName = strings . ToLower ( t . Name )
2015-02-23 10:15:53 +03:00
if _ , err = sess . Id ( t . ID ) . AllCols ( ) . Update ( t ) ; err != nil {
2015-03-01 05:44:09 +03:00
return fmt . Errorf ( "update: %v" , err )
2015-02-14 00:12:33 +03:00
}
2014-08-24 17:09:05 +04:00
// Update access for team members if needed.
2015-02-05 16:29:08 +03:00
if authChanged {
2015-02-13 08:58:46 +03:00
if err = t . getRepositories ( sess ) ; err != nil {
2015-03-01 05:44:09 +03:00
return fmt . Errorf ( "getRepositories:%v" , err )
2014-08-24 17:09:05 +04:00
}
for _ , repo := range t . Repos {
2015-03-01 05:44:09 +03:00
if err = repo . recalculateTeamAccesses ( sess , 0 ) ; err != nil {
return fmt . Errorf ( "recalculateTeamAccesses: %v" , err )
2014-08-24 17:09:05 +04:00
}
}
}
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
}
// Get organization.
2015-08-08 17:43:14 +03:00
org , err := GetUserByID ( t . OrgID )
2014-08-24 17:09:05 +04:00
if err != nil {
return err
}
sess := x . NewSession ( )
2015-02-13 08:58:46 +03:00
defer sessionRelease ( sess )
2014-08-24 17:09:05 +04:00
if err = sess . Begin ( ) ; err != nil {
return err
}
// Delete all accesses.
for _ , repo := range t . Repos {
2015-03-01 05:44:09 +03:00
if err = repo . recalculateTeamAccesses ( sess , t . ID ) ; err != nil {
2015-02-05 16:29:08 +03:00
return err
2014-08-24 17:09:05 +04:00
}
}
// Delete team-user.
2015-02-23 10:15:53 +03:00
if _ , err = sess . Where ( "org_id=?" , org . Id ) . Where ( "team_id=?" , t . ID ) . Delete ( new ( TeamUser ) ) ; err != nil {
2014-08-24 17:09:05 +04:00
return err
}
// Delete team.
2015-02-23 10:15:53 +03:00
if _ , err = sess . Id ( t . ID ) . Delete ( new ( Team ) ) ; err != nil {
2014-08-24 17:09:05 +04:00
return err
}
// Update organization number of teams.
2015-02-23 10:15:53 +03:00
if _ , err = sess . Exec ( "UPDATE `user` SET num_teams=num_teams-1 WHERE id=?" , t . OrgID ) ; err != nil {
2014-08-24 17:09:05 +04:00
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 {
2015-02-23 10:15:53 +03:00
ID int64 ` xorm:"pk autoincr" `
OrgID int64 ` xorm:"INDEX" `
TeamID int64 ` xorm:"UNIQUE(s)" `
Uid int64 ` xorm:"UNIQUE(s)" `
2014-06-25 08:44:48 +04:00
}
2014-06-25 13:14:36 +04:00
2015-02-23 10:15:53 +03:00
func isTeamMember ( e Engine , orgID , teamID , uid int64 ) bool {
has , _ := e . Where ( "org_id=?" , orgID ) . And ( "team_id=?" , teamID ) . And ( "uid=?" , uid ) . Get ( new ( TeamUser ) )
2015-02-11 07:44:16 +03:00
return has
}
2014-06-30 00:30:41 +04:00
// IsTeamMember returns true if given user is a member of team.
2015-02-23 10:15:53 +03:00
func IsTeamMember ( orgID , teamID , uid int64 ) bool {
return isTeamMember ( x , orgID , teamID , uid )
2014-06-30 00:30:41 +04:00
}
2015-02-24 08:27:22 +03:00
func getTeamMembers ( e Engine , teamID int64 ) ( _ [ ] * User , err error ) {
teamUsers := make ( [ ] * TeamUser , 0 , 10 )
if err = e . Where ( "team_id=?" , teamID ) . Find ( & teamUsers ) ; err != nil {
return nil , fmt . Errorf ( "get team-users: %v" , err )
}
members := make ( [ ] * User , 0 , len ( teamUsers ) )
for i := range teamUsers {
member := new ( User )
if _ , err = e . Id ( teamUsers [ i ] . Uid ) . Get ( member ) ; err != nil {
return nil , fmt . Errorf ( "get user '%d': %v" , teamUsers [ i ] . Uid , err )
}
members = append ( members , member )
}
return members , nil
2014-06-25 13:14:36 +04:00
}
2014-08-16 12:21:17 +04:00
2015-02-13 08:58:46 +03:00
// GetTeamMembers returns all members in given team of organization.
func GetTeamMembers ( teamID int64 ) ( [ ] * User , error ) {
return getTeamMembers ( x , teamID )
}
2015-02-11 07:44:16 +03:00
func getUserTeams ( e Engine , orgId , uid int64 ) ( [ ] * Team , error ) {
2014-08-24 17:09:05 +04:00
tus := make ( [ ] * TeamUser , 0 , 5 )
2015-02-11 07:44:16 +03:00
if err := e . Where ( "uid=?" , uid ) . And ( "org_id=?" , orgId ) . Find ( & tus ) ; err != nil {
2014-08-24 17:09:05 +04:00
return nil , err
}
ts := make ( [ ] * Team , len ( tus ) )
for i , tu := range tus {
t := new ( Team )
2015-02-23 10:15:53 +03:00
has , err := e . Id ( tu . TeamID ) . Get ( t )
2014-08-24 17:09:05 +04:00
if err != nil {
return nil , err
} else if ! has {
return nil , ErrTeamNotExist
}
ts [ i ] = t
}
return ts , nil
}
2015-02-11 07:44:16 +03:00
// GetUserTeams returns all teams that user belongs to in given organization.
func GetUserTeams ( orgId , uid int64 ) ( [ ] * Team , error ) {
return getUserTeams ( x , orgId , uid )
}
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
}
2014-08-16 12:21:17 +04:00
sess := x . NewSession ( )
2015-02-13 08:58:46 +03:00
defer sessionRelease ( sess )
2014-08-16 12:21:17 +04:00
if err = sess . Begin ( ) ; err != nil {
return err
}
tu := & TeamUser {
Uid : uid ,
2015-02-23 10:15:53 +03:00
OrgID : orgId ,
TeamID : teamId ,
2014-08-16 12:21:17 +04:00
}
if _ , err = sess . Insert ( tu ) ; err != nil {
return err
2015-02-23 10:15:53 +03:00
} else if _ , err = sess . Id ( t . ID ) . Update ( t ) ; err != nil {
2014-08-16 12:21:17 +04:00
return err
}
2014-08-16 12:58:32 +04:00
// Give access to team repositories.
for _ , repo := range t . Repos {
2015-03-01 05:44:09 +03:00
if err = repo . recalculateTeamAccesses ( sess , 0 ) ; err != nil {
2014-08-16 12:58:32 +04:00
return err
}
2014-08-24 17:09:05 +04:00
}
// We make sure it exists before.
ou := new ( OrgUser )
2015-02-13 08:58:46 +03:00
if _ , err = sess . Where ( "uid=?" , uid ) . And ( "org_id=?" , orgId ) . Get ( ou ) ; err != nil {
2014-08-24 17:09:05 +04:00
return err
}
ou . NumTeams ++
if t . IsOwnerTeam ( ) {
ou . IsOwner = true
}
2015-02-23 10:15:53 +03:00
if _ , err = sess . Id ( ou . ID ) . AllCols ( ) . Update ( ou ) ; err != nil {
2014-08-24 17:09:05 +04:00
return err
2014-08-16 12:58:32 +04:00
}
2014-08-16 12:21:17 +04:00
return sess . Commit ( )
}
2015-02-11 07:44:16 +03:00
func removeTeamMember ( e Engine , orgId , teamId , uid int64 ) error {
if ! isTeamMember ( e , orgId , teamId , uid ) {
2014-08-16 12:21:17 +04:00
return nil
}
2014-08-16 12:58:32 +04:00
// Get team and its repositories.
2015-02-11 07:44:16 +03:00
t , err := getTeamById ( e , teamId )
2014-08-16 12:58:32 +04:00
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 {
2015-03-18 04:51:39 +03:00
return ErrLastOrgOwner { UID : uid }
2014-08-24 17:09:05 +04:00
}
2014-08-16 12:58:32 +04:00
t . NumMembers --
2015-02-13 08:58:46 +03:00
if err = t . getRepositories ( e ) ; err != nil {
2014-08-16 12:58:32 +04:00
return err
}
// Get organization.
2015-08-08 17:43:14 +03:00
org , err := getUserByID ( e , orgId )
2014-08-16 12:58:32 +04:00
if err != nil {
return err
}
2014-08-16 12:21:17 +04:00
tu := & TeamUser {
Uid : uid ,
2015-02-23 10:15:53 +03:00
OrgID : orgId ,
TeamID : teamId ,
2014-08-16 12:21:17 +04:00
}
2015-02-11 07:44:16 +03:00
if _ , err := e . Delete ( tu ) ; err != nil {
2014-08-16 12:21:17 +04:00
return err
2015-02-23 10:15:53 +03:00
} else if _ , err = e . Id ( t . ID ) . AllCols ( ) . Update ( t ) ; err != nil {
2014-08-16 12:21:17 +04:00
return err
}
2014-08-16 12:58:32 +04:00
// Delete access to team repositories.
for _ , repo := range t . Repos {
2015-03-01 05:44:09 +03:00
if err = repo . recalculateTeamAccesses ( e , 0 ) ; err != nil {
2014-08-16 12:58:32 +04:00
return err
}
2014-08-24 17:09:05 +04:00
}
// This must exist.
ou := new ( OrgUser )
2015-02-11 07:44:16 +03:00
_ , err = e . Where ( "uid=?" , uid ) . And ( "org_id=?" , org . Id ) . Get ( ou )
2014-08-24 17:09:05 +04:00
if err != nil {
return err
}
ou . NumTeams --
if t . IsOwnerTeam ( ) {
ou . IsOwner = false
}
2015-02-23 10:15:53 +03:00
if _ , err = e . Id ( ou . ID ) . AllCols ( ) . Update ( ou ) ; err != nil {
2014-08-24 17:09:05 +04:00
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 ( )
2015-02-23 10:15:53 +03:00
defer sessionRelease ( sess )
2014-08-24 17:09:05 +04:00
if err := sess . Begin ( ) ; err != nil {
return err
}
2015-02-11 07:44:16 +03:00
if err := removeTeamMember ( sess , orgId , teamId , uid ) ; err != nil {
2014-08-24 17:09:05 +04:00
return err
}
2014-08-16 12:21:17 +04:00
return sess . Commit ( )
}
2015-02-23 10:15:53 +03:00
// ___________ __________
// \__ ___/___ _____ _____\______ \ ____ ______ ____
// | |_/ __ \\__ \ / \| _// __ \\____ \ / _ \
// | |\ ___/ / __ \| Y Y \ | \ ___/| |_> > <_> )
// |____| \___ >____ /__|_| /____|_ /\___ > __/ \____/
// \/ \/ \/ \/ \/|__|
// TeamRepo represents an team-repository relation.
type TeamRepo struct {
ID int64 ` xorm:"pk autoincr" `
OrgID int64 ` xorm:"INDEX" `
TeamID int64 ` xorm:"UNIQUE(s)" `
RepoID int64 ` xorm:"UNIQUE(s)" `
}
func hasTeamRepo ( e Engine , orgID , teamID , repoID int64 ) bool {
has , _ := e . Where ( "org_id=?" , orgID ) . And ( "team_id=?" , teamID ) . And ( "repo_id=?" , repoID ) . Get ( new ( TeamRepo ) )
return has
}
// HasTeamRepo returns true if given repository belongs to team.
func HasTeamRepo ( orgID , teamID , repoID int64 ) bool {
return hasTeamRepo ( x , orgID , teamID , repoID )
}
func addTeamRepo ( e Engine , orgID , teamID , repoID int64 ) error {
_ , err := e . InsertOne ( & TeamRepo {
OrgID : orgID ,
TeamID : teamID ,
RepoID : repoID ,
} )
return err
}
// AddTeamRepo adds new repository relation to team.
func AddTeamRepo ( orgID , teamID , repoID int64 ) error {
return addTeamRepo ( x , orgID , teamID , repoID )
}
func removeTeamRepo ( e Engine , teamID , repoID int64 ) error {
_ , err := e . Delete ( & TeamRepo {
TeamID : teamID ,
RepoID : repoID ,
} )
return err
}
// RemoveTeamRepo deletes repository relation to team.
func RemoveTeamRepo ( teamID , repoID int64 ) error {
return removeTeamRepo ( x , teamID , repoID )
}
2015-03-01 05:44:09 +03:00
func removeOrgRepo ( e Engine , orgID , repoID int64 ) error {
_ , err := e . Delete ( & TeamRepo {
OrgID : orgID ,
RepoID : repoID ,
} )
return err
}
// RemoveOrgRepo removes all team-repository relations of given organization.
func RemoveOrgRepo ( orgID , repoID int64 ) error {
return removeOrgRepo ( x , orgID , repoID )
}