diff options
Diffstat (limited to 'models/org.go')
-rw-r--r-- | models/org.go | 871 |
1 files changed, 816 insertions, 55 deletions
diff --git a/models/org.go b/models/org.go index 2625ed42..ce506705 100644 --- a/models/org.go +++ b/models/org.go @@ -6,14 +6,23 @@ package models import ( "errors" + "fmt" + "os" + "path" "strings" + "github.com/Unknwon/com" + "github.com/go-xorm/xorm" + "github.com/gogits/gogs/modules/base" ) var ( ErrOrgNotExist = errors.New("Organization does not exist") ErrTeamAlreadyExist = errors.New("Team already exist") + 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") ) // IsOrgOwner returns true if given user is in the owner team. @@ -26,14 +35,14 @@ func (org *User) IsOrgMember(uid int64) bool { return IsOrganizationMember(org.Id, uid) } +// GetTeam returns named team of organization. +func (org *User) GetTeam(name string) (*Team, error) { + return GetTeam(org.Id, name) +} + // GetOwnerTeam returns owner team of organization. func (org *User) GetOwnerTeam() (*Team, error) { - t := &Team{ - OrgId: org.Id, - Name: OWNER_TEAM, - } - _, err := x.Get(t) - return t, err + return org.GetTeam(OWNER_TEAM) } // GetTeams returns all teams that belong to organization. @@ -58,6 +67,16 @@ func (org *User) GetMembers() error { return nil } +// 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) +} + // CreateOrganization creates record of a new organization. func CreateOrganization(org, owner *User) (*User, error) { if !IsLegalName(org.Name) { @@ -97,9 +116,15 @@ func CreateOrganization(org, owner *User) (*User, error) { return nil, err } + if err = os.MkdirAll(UserPath(org.Name), os.ModePerm); err != nil { + sess.Rollback() + return nil, err + } + // Create default owner team. t := &Team{ OrgId: org.Id, + LowerName: strings.ToLower(OWNER_TEAM), Name: OWNER_TEAM, Authorize: ORG_ADMIN, NumMembers: 1, @@ -111,10 +136,10 @@ func CreateOrganization(org, owner *User) (*User, error) { // Add initial creator to organization and owner team. ou := &OrgUser{ - Uid: owner.Id, - OrgId: org.Id, - IsOwner: true, - NumTeam: 1, + Uid: owner.Id, + OrgId: org.Id, + IsOwner: true, + NumTeams: 1, } if _, err = sess.Insert(ou); err != nil { sess.Rollback() @@ -134,6 +159,19 @@ func CreateOrganization(org, owner *User) (*User, error) { return org, sess.Commit() } +// CountOrganizations returns number of organizations. +func CountOrganizations() int64 { + count, _ := x.Where("type=1").Count(new(User)) + return count +} + +// 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 +} + // TODO: need some kind of mechanism to record failure. // DeleteOrganization completely and permanently deletes everything of organization. func DeleteOrganization(org *User) (err error) { @@ -162,6 +200,176 @@ func DeleteOrganization(org *User) (err error) { return sess.Commit() } +// ________ ____ ___ +// \_____ \_______ ____ | | \______ ___________ +// / | \_ __ \/ ___\| | / ___// __ \_ __ \ +// / | \ | \/ /_/ > | /\___ \\ ___/| | \/ +// \_______ /__| \___ /|______//____ >\___ >__| +// \/ /_____/ \/ \/ + +// OrgUser represents an organization-user relation. +type OrgUser struct { + Id int64 + Uid int64 `xorm:"INDEX UNIQUE(s)"` + OrgId int64 `xorm:"INDEX UNIQUE(s)"` + IsPublic bool + IsOwner bool + NumTeams int +} + +// 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 +} + +// 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 +} + +// 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 +} + +// 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 +} + +// 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 + } + + ou := &OrgUser{ + Uid: uid, + OrgId: orgId, + } + + 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 + } + + u, err := GetUserById(uid) + if err != nil { + return err + } + org, err := GetUserById(orgId) + if err != nil { + return err + } + + // 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 + } + } + + 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 + } + + // 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 + } else if err = WatchRepo(u.Id, repo.Id, false); err != nil { + sess.Rollback() + return err + } + } + + // 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 + } + } + + return sess.Commit() +} + // ___________ // \__ ___/___ _____ _____ // | |_/ __ \\__ \ / \ @@ -177,6 +385,13 @@ const ( ORG_ADMIN ) +func AuthorizeToAccessType(auth AuthorizeType) AccessType { + if auth == ORG_READABLE { + return READABLE + } + return WRITABLE +} + const OWNER_TEAM = "Owners" // Team represents a organization team. @@ -187,10 +402,16 @@ type Team struct { Name string Description string Authorize AuthorizeType - RepoIds string `xorm:"TEXT"` - NumMembers int + RepoIds string `xorm:"TEXT"` + Repos []*Repository `xorm:"-"` + Members []*User `xorm:"-"` NumRepos int - Members []*User `xorm:"-"` + NumMembers int +} + +// IsOwnerTeam returns true if team is owner team. +func (t *Team) IsOwnerTeam() bool { + return t.Name == OWNER_TEAM } // IsTeamMember returns true if given user is a member of team. @@ -198,15 +419,193 @@ func (t *Team) IsMember(uid int64) bool { return IsTeamMember(t.OrgId, t.Id, uid) } -// GetMembers returns all members in given team of organization. +// 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 { + if len(str) == 0 { + continue + } + id := com.StrTo(str[1:]).MustInt64() + 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. func (t *Team) GetMembers() (err error) { t.Members, err = GetTeamMembers(t.OrgId, t.Id) return err } +// 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) +} + +// 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 { + auth, err := GetHighestAuthorize(t.OrgId, u.Id, t.Id, repo.Id) + if err != nil { + sess.Rollback() + return err + } + + access := &Access{ + UserName: u.LowerName, + RepoName: path.Join(repo.Owner.LowerName, repo.LowerName), + } + if auth == 0 { + access.Mode = mode + if _, err = sess.Insert(access); err != nil { + sess.Rollback() + return fmt.Errorf("fail to insert access: %v", err) + } + } else if auth < t.Authorize { + if err = addAccessWithAuthorize(sess, access, mode); err != nil { + sess.Rollback() + return err + } + } + if err = WatchRepo(u.Id, repo.Id, true); err != nil { + sess.Rollback() + return err + } + } + 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 { + auth, err := GetHighestAuthorize(t.OrgId, u.Id, t.Id, repo.Id) + 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) + } else if err = WatchRepo(u.Id, repo.Id, false); err != nil { + sess.Rollback() + return err + } + } else if auth < t.Authorize { + if err = addAccessWithAuthorize(sess, access, AuthorizeToAccessType(auth)); err != nil { + sess.Rollback() + return err + } + } + } + + return sess.Commit() +} + // 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 @@ -234,66 +633,198 @@ func NewTeam(t *Team) error { } // Update organization number of teams. - rawSql := "UPDATE `user` SET num_teams = num_teams + 1 WHERE id = ?" - if _, err = sess.Exec(rawSql, t.OrgId); err != nil { + 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 +} + +// GetHighestAuthorize returns highest repository authorize level for given user and team. +func GetHighestAuthorize(orgId, uid, teamId, repoId int64) (AuthorizeType, error) { + 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 + } + } + } + return auth, nil +} + // UpdateTeam updates information of team. -func UpdateTeam(t *Team) error { +func UpdateTeam(t *Team, authChanged bool) (err error) { + if !IsLegalName(t.Name) { + return ErrTeamNameIllegal + } + if len(t.Description) > 255 { t.Description = t.Description[:255] } + 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 + } + + // Update access. + mode := AuthorizeToAccessType(t.Authorize) + + 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 { + auth, err := GetHighestAuthorize(org.Id, u.Id, t.Id, repo.Id) + if err != nil { + sess.Rollback() + return err + } + if auth >= t.Authorize { + continue // Other team has higher or same authorize level. + } + } + + access := &Access{ + UserName: u.LowerName, + RepoName: path.Join(org.LowerName, repo.LowerName), + } + if err = addAccessWithAuthorize(sess, access, mode); err != nil { + sess.Rollback() + return err + } + } + } + } + t.LowerName = strings.ToLower(t.Name) - _, err := x.Id(t.Id).AllCols().Update(t) - return err + 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 + } -// OrgUser represents an organization-user relation. -type OrgUser struct { - Id int64 - Uid int64 `xorm:"INDEX"` - OrgId int64 `xorm:"INDEX"` - IsPublic bool - IsOwner bool - NumTeam int -} + // Get organization. + org, err := GetUserById(t.OrgId) + if err != nil { + return err + } -// 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 -} + sess := x.NewSession() + defer sess.Close() + if err = sess.Begin(); err != nil { + return err + } -// 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 -} + // Delete all accesses. + for _, repo := range t.Repos { + for _, u := range t.Members { + auth, err := GetHighestAuthorize(org.Id, u.Id, t.Id, repo.Id) + if err != nil { + sess.Rollback() + return err + } -// 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 -} + access := &Access{ + UserName: u.LowerName, + RepoName: path.Join(org.LowerName, repo.LowerName), + } + if auth == 0 { + if _, err = sess.Delete(access); err != nil { + sess.Rollback() + return fmt.Errorf("fail to delete access: %v", err) + } + } else if auth < t.Authorize { + // Downgrade authorize level. + if err = addAccessWithAuthorize(sess, access, AuthorizeToAccessType(auth)); err != nil { + sess.Rollback() + return err + } + } + } + } -// 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 + // 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() } // ___________ ____ ___ @@ -334,3 +865,233 @@ func GetTeamMembers(orgId, teamId int64) ([]*User, error) { } return us, nil } + +// 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 +} + +// AddTeamMember adds new member to given team of given organization. +func AddTeamMember(orgId, teamId, uid int64) error { + if IsTeamMember(orgId, teamId, uid) { + return nil + } + + if err := AddOrgUser(orgId, uid); err != nil { + return err + } + + // Get team and its repositories. + t, err := GetTeamById(teamId) + if err != nil { + return err + } + 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 + } + + 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 + } + + // Give access to team repositories. + mode := AuthorizeToAccessType(t.Authorize) + for _, repo := range t.Repos { + auth, err := GetHighestAuthorize(orgId, uid, teamId, repo.Id) + if err != nil { + sess.Rollback() + return err + } + + access := &Access{ + UserName: u.LowerName, + RepoName: path.Join(org.LowerName, repo.LowerName), + } + // Equal 0 means given access doesn't exist. + if auth == 0 { + access.Mode = mode + if _, err = sess.Insert(access); err != nil { + sess.Rollback() + return fmt.Errorf("fail to insert access: %v", err) + } + } else if auth < t.Authorize { + if err = addAccessWithAuthorize(sess, access, mode); err != nil { + 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 + } + + return sess.Commit() +} + +func removeTeamMemberWithSess(orgId, teamId, uid int64, sess *xorm.Session) error { + if !IsTeamMember(orgId, teamId, uid) { + return nil + } + + // Get team and its repositories. + t, err := GetTeamById(teamId) + if err != nil { + return err + } + + // Check if the user to delete is the last member in owner team. + if t.IsOwnerTeam() && t.NumMembers == 1 { + return ErrLastOrgOwner + } + + 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 + } + + tu := &TeamUser{ + Uid: uid, + OrgId: orgId, + TeamId: teamId, + } + + if _, err := sess.Delete(tu); err != nil { + sess.Rollback() + return err + } else if _, err = sess.Id(t.Id).AllCols().Update(t); err != nil { + sess.Rollback() + return err + } + + // Delete access to team repositories. + for _, repo := range t.Repos { + auth, err := GetHighestAuthorize(orgId, uid, teamId, repo.Id) + if err != nil { + sess.Rollback() + return err + } + + access := &Access{ + UserName: u.LowerName, + RepoName: path.Join(org.LowerName, repo.LowerName), + } + // Delete access if this is the last team user belongs to. + if auth == 0 { + if _, err = sess.Delete(access); err != nil { + sess.Rollback() + return fmt.Errorf("fail to delete access: %v", err) + } else if err = WatchRepo(u.Id, repo.Id, false); err != nil { + sess.Rollback() + return err + } + } else if auth < t.Authorize { + // Downgrade authorize level. + if err = addAccessWithAuthorize(sess, access, AuthorizeToAccessType(auth)); err != nil { + sess.Rollback() + return err + } + } + } + + // 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 + } + return nil +} + +// 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 + } + return sess.Commit() +} |