12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109 |
- // 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
- import (
- "errors"
- "fmt"
- "os"
- "strings"
- "github.com/Unknwon/com"
- "github.com/go-xorm/xorm"
- )
- var (
- ErrOrgNotExist = errors.New("Organization does not exist")
- ErrTeamNotExist = errors.New("Team does not exist")
- )
- // IsOwnedBy returns true if given user is in the owner team.
- func (org *User) IsOwnedBy(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 org.IsOrganization() && IsOrganizationMember(org.Id, uid)
- }
- func (org *User) getTeam(e Engine, name string) (*Team, error) {
- return getTeam(e, org.Id, name)
- }
- // GetTeam returns named team of organization.
- func (org *User) GetTeam(name string) (*Team, error) {
- return org.getTeam(x, name)
- }
- func (org *User) getOwnerTeam(e Engine) (*Team, error) {
- return org.getTeam(e, OWNER_TEAM)
- }
- // GetOwnerTeam returns owner team of organization.
- func (org *User) GetOwnerTeam() (*Team, error) {
- return org.getOwnerTeam(x)
- }
- func (org *User) getTeams(e Engine) error {
- return e.Where("org_id=?", org.Id).Find(&org.Teams)
- }
- // GetTeams returns all teams that belong to organization.
- func (org *User) GetTeams() error {
- return org.getTeams(x)
- }
- // 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
- }
- // 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)
- }
- 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)
- }
- // CreateOrganization creates record of a new organization.
- func CreateOrganization(org, owner *User) (err error) {
- if err = IsUsableName(org.Name); err != nil {
- return err
- }
- isExist, err := IsUserExist(0, org.Name)
- if err != nil {
- return err
- } else if isExist {
- return ErrUserAlreadyExist{org.Name}
- }
- org.LowerName = strings.ToLower(org.Name)
- org.FullName = org.Name
- org.Rands = GetUserSalt()
- org.Salt = GetUserSalt()
- org.UseCustomAvatar = true
- org.MaxRepoCreation = -1
- org.NumTeams = 1
- org.NumMembers = 1
- sess := x.NewSession()
- defer sessionRelease(sess)
- if err = sess.Begin(); err != nil {
- return err
- }
- if _, err = sess.Insert(org); err != nil {
- return fmt.Errorf("insert organization: %v", err)
- }
- org.GenerateRandomAvatar()
- // Add initial creator to organization and owner team.
- if _, err = sess.Insert(&OrgUser{
- Uid: owner.Id,
- OrgID: org.Id,
- IsOwner: true,
- NumTeams: 1,
- }); err != nil {
- return fmt.Errorf("insert org-user relation: %v", err)
- }
- // Create default owner team.
- t := &Team{
- OrgID: org.Id,
- LowerName: strings.ToLower(OWNER_TEAM),
- Name: OWNER_TEAM,
- Authorize: ACCESS_MODE_OWNER,
- NumMembers: 1,
- }
- if _, err = sess.Insert(t); err != nil {
- return fmt.Errorf("insert owner team: %v", err)
- }
- if _, err = sess.Insert(&TeamUser{
- Uid: owner.Id,
- OrgID: org.Id,
- TeamID: t.ID,
- }); err != nil {
- return fmt.Errorf("insert team-user relation: %v", err)
- }
- if err = os.MkdirAll(UserPath(org.Name), os.ModePerm); err != nil {
- return fmt.Errorf("create directory: %v", err)
- }
- return sess.Commit()
- }
- // 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
- }
- // CountOrganizations returns number of organizations.
- func CountOrganizations() int64 {
- count, _ := x.Where("type=1").Count(new(User))
- return count
- }
- // Organizations returns number of organizations in given page.
- func Organizations(page, pageSize int) ([]*User, error) {
- orgs := make([]*User, 0, pageSize)
- return orgs, x.Limit(pageSize, (page-1)*pageSize).Where("type=1").Asc("id").Find(&orgs)
- }
- // 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 sessionRelease(sess)
- if err = sess.Begin(); err != nil {
- return err
- }
- if err = deleteBeans(sess,
- &Team{OrgID: org.Id},
- &OrgUser{OrgID: org.Id},
- &TeamUser{OrgID: org.Id},
- ); err != nil {
- return fmt.Errorf("deleteBeans: %v", err)
- }
- if err = deleteUser(sess, org); err != nil {
- return fmt.Errorf("deleteUser: %v", err)
- }
- return sess.Commit()
- }
- // ________ ____ ___
- // \_____ \_______ ____ | | \______ ___________
- // / | \_ __ \/ ___\| | / ___// __ \_ __ \
- // / | \ | \/ /_/ > | /\___ \\ ___/| | \/
- // \_______ /__| \___ /|______//____ >\___ >__|
- // \/ /_____/ \/ \/
- // 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
- 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 true 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
- }
- func getPublicOrgsByUserID(sess *xorm.Session, userID int64) ([]*User, error) {
- orgs := make([]*User, 0, 10)
- return orgs, sess.Where("`org_user`.uid=?", userID).And("`org_user`.is_public=?", true).
- Join("INNER", "`org_user`", "`org_user`.org_id=`user`.id").Find(&orgs)
- }
- // GetPublicOrgsByUserID returns a list of organizations that the given user ID
- // has joined publicly.
- func GetPublicOrgsByUserID(userID int64) ([]*User, error) {
- sess := x.NewSession()
- return getPublicOrgsByUserID(sess, userID)
- }
- // GetPublicOrgsByUserID returns a list of organizations that the given user ID
- // has joined publicly, ordered descending by the given condition.
- func GetPublicOrgsByUserIDDesc(userID int64, desc string) ([]*User, error) {
- sess := x.NewSession()
- return getPublicOrgsByUserID(sess.Desc(desc), userID)
- }
- func getOwnedOrgsByUserID(sess *xorm.Session, userID int64) ([]*User, error) {
- orgs := make([]*User, 0, 10)
- return orgs, sess.Where("`org_user`.uid=?", userID).And("`org_user`.is_owner=?", true).
- Join("INNER", "`org_user`", "`org_user`.org_id=`user`.id").Find(&orgs)
- }
- // GetOwnedOrgsByUserID returns a list of organizations are owned by given user ID.
- func GetOwnedOrgsByUserID(userID int64) ([]*User, error) {
- sess := x.NewSession()
- return getOwnedOrgsByUserID(sess, userID)
- }
- // GetOwnedOrganizationsByUserIDDesc returns a list of organizations are owned by
- // given user ID, ordered descending by the given condition.
- func GetOwnedOrgsByUserIDDesc(userID int64, desc string) ([]*User, error) {
- sess := x.NewSession()
- return getOwnedOrgsByUserID(sess.Desc(desc), userID)
- }
- // GetOrgUsersByUserID returns all organization-user relations by user ID.
- func GetOrgUsersByUserID(uid int64, all bool) ([]*OrgUser, error) {
- ous := make([]*OrgUser, 0, 10)
- sess := x.Where("uid=?", uid)
- if !all {
- // Only show public organizations
- sess.And("is_public=?", true)
- }
- err := sess.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 fmt.Errorf("get org-user: %v", err)
- } else if !has {
- return nil
- }
- u, err := GetUserByID(uid)
- if err != nil {
- return fmt.Errorf("GetUserById: %v", err)
- }
- org, err := GetUserByID(orgId)
- if err != nil {
- return fmt.Errorf("get organization: %v", err)
- } else if err = org.GetRepositories(); err != nil {
- return fmt.Errorf("GetRepositories: %v", 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{UID: uid}
- }
- }
- sess := x.NewSession()
- defer sessionRelease(sess)
- if err := sess.Begin(); err != nil {
- return err
- }
- if _, err := sess.Id(ou.ID).Delete(ou); err != nil {
- return err
- } else if _, err = sess.Exec("UPDATE `user` SET num_members=num_members-1 WHERE id=?", orgId); err != nil {
- return err
- }
- // Delete all repository accesses.
- access := &Access{UserID: u.Id}
- for _, repo := range org.Repos {
- access.RepoID = repo.ID
- if _, err = sess.Delete(access); err != nil {
- return err
- } else if err = watchRepo(sess, u.Id, repo.ID, false); err != nil {
- return err
- }
- }
- // Delete member in his/her teams.
- teams, err := getUserTeams(sess, org.Id, u.Id)
- if err != nil {
- return err
- }
- for _, t := range teams {
- if err = removeTeamMember(sess, org.Id, t.ID, u.Id); err != nil {
- return err
- }
- }
- return sess.Commit()
- }
- // ___________
- // \__ ___/___ _____ _____
- // | |_/ __ \\__ \ / \
- // | |\ ___/ / __ \| Y Y \
- // |____| \___ >____ /__|_| /
- // \/ \/ \/
- const OWNER_TEAM = "Owners"
- // Team represents a organization team.
- type Team struct {
- ID int64 `xorm:"pk autoincr"`
- OrgID int64 `xorm:"INDEX"`
- LowerName string
- Name string
- Description string
- Authorize AccessMode
- Repos []*Repository `xorm:"-"`
- Members []*User `xorm:"-"`
- NumRepos int
- 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.
- func (t *Team) IsMember(uid int64) bool {
- return IsTeamMember(t.OrgID, t.ID, uid)
- }
- 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 {
- repo, err := getRepositoryByID(e, teamRepos[i].RepoID)
- if err != nil {
- return fmt.Errorf("getRepositoryById(%d): %v", teamRepos[i].RepoID, err)
- }
- t.Repos = append(t.Repos, repo)
- }
- return nil
- }
- // 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) {
- t.Members, err = getTeamMembers(e, t.ID)
- return err
- }
- // GetMembers returns all members in team of organization.
- func (t *Team) GetMembers() (err error) {
- return t.getMembers(x)
- }
- // 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)
- }
- func (t *Team) hasRepository(e Engine, repoID int64) bool {
- return hasTeamRepo(e, t.OrgID, t.ID, repoID)
- }
- // HasRepository returns true if given repository belong to team.
- func (t *Team) HasRepository(repoID int64) bool {
- return t.hasRepository(x, repoID)
- }
- func (t *Team) addRepository(e Engine, repo *Repository) (err error) {
- if err = addTeamRepo(e, t.OrgID, t.ID, repo.ID); err != nil {
- return err
- }
- t.NumRepos++
- if _, err = e.Id(t.ID).AllCols().Update(t); err != nil {
- return fmt.Errorf("update team: %v", err)
- }
- if err = repo.recalculateTeamAccesses(e, 0); err != nil {
- return fmt.Errorf("recalculateAccesses: %v", err)
- }
- if err = t.getMembers(e); err != nil {
- return fmt.Errorf("getMembers: %v", err)
- }
- for _, u := range t.Members {
- if err = watchRepo(e, u.Id, repo.ID, true); err != nil {
- return fmt.Errorf("watchRepo: %v", err)
- }
- }
- return nil
- }
- // AddRepository adds new repository to team of organization.
- func (t *Team) AddRepository(repo *Repository) (err error) {
- if repo.OwnerID != t.OrgID {
- return errors.New("Repository does not belong to organization")
- } else if t.HasRepository(repo.ID) {
- return nil
- }
- sess := x.NewSession()
- defer sessionRelease(sess)
- if err = sess.Begin(); err != nil {
- return err
- }
- if err = t.addRepository(sess, repo); err != nil {
- return err
- }
- return sess.Commit()
- }
- func (t *Team) removeRepository(e Engine, repo *Repository, recalculate bool) (err error) {
- if err = removeTeamRepo(e, t.ID, repo.ID); err != nil {
- return err
- }
- t.NumRepos--
- if _, err = e.Id(t.ID).AllCols().Update(t); err != nil {
- return err
- }
- // Don't need to recalculate when delete a repository from organization.
- if recalculate {
- if err = repo.recalculateTeamAccesses(e, t.ID); err != nil {
- return err
- }
- }
- if err = t.getMembers(e); err != nil {
- return fmt.Errorf("get team members: %v", err)
- }
- for _, u := range t.Members {
- has, err := hasAccess(e, u, repo, ACCESS_MODE_READ)
- if err != nil {
- return err
- } else if has {
- continue
- }
- if err = watchRepo(e, u.Id, repo.ID, false); err != nil {
- return err
- }
- }
- return nil
- }
- // RemoveRepository removes repository from team of organization.
- func (t *Team) RemoveRepository(repoID int64) error {
- if !t.HasRepository(repoID) {
- return nil
- }
- repo, err := GetRepositoryByID(repoID)
- if err != nil {
- return err
- }
- sess := x.NewSession()
- defer sessionRelease(sess)
- if err = sess.Begin(); err != nil {
- return err
- }
- if err = t.removeRepository(sess, repo, true); err != nil {
- 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 len(t.Name) == 0 {
- return errors.New("empty team name")
- }
- 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{t.OrgID, t.LowerName}
- }
- 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()
- }
- func getTeam(e Engine, orgId int64, name string) (*Team, error) {
- t := &Team{
- OrgID: orgId,
- LowerName: strings.ToLower(name),
- }
- has, err := e.Get(t)
- if err != nil {
- return nil, err
- } else if !has {
- return nil, ErrTeamNotExist
- }
- return t, nil
- }
- // GetTeam returns team by given team name and organization.
- func GetTeam(orgId int64, name string) (*Team, error) {
- return getTeam(x, orgId, name)
- }
- func getTeamById(e Engine, teamId int64) (*Team, error) {
- t := new(Team)
- has, err := e.Id(teamId).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) {
- return getTeamById(x, teamId)
- }
- // UpdateTeam updates information of team.
- func UpdateTeam(t *Team, authChanged bool) (err error) {
- if len(t.Name) == 0 {
- return errors.New("empty team name")
- }
- if len(t.Description) > 255 {
- t.Description = t.Description[:255]
- }
- sess := x.NewSession()
- defer sessionRelease(sess)
- if err = sess.Begin(); err != nil {
- return err
- }
- t.LowerName = strings.ToLower(t.Name)
- has, err := x.Where("org_id=?", t.OrgID).And("lower_name=?", t.LowerName).And("id!=?", t.ID).Get(new(Team))
- if err != nil {
- return err
- } else if has {
- return ErrTeamAlreadyExist{t.OrgID, t.LowerName}
- }
- if _, err = sess.Id(t.ID).AllCols().Update(t); err != nil {
- return fmt.Errorf("update: %v", err)
- }
- // Update access for team members if needed.
- if authChanged {
- if err = t.getRepositories(sess); err != nil {
- return fmt.Errorf("getRepositories:%v", err)
- }
- for _, repo := range t.Repos {
- if err = repo.recalculateTeamAccesses(sess, 0); err != nil {
- return fmt.Errorf("recalculateTeamAccesses: %v", 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
- }
- // Get organization.
- org, err := GetUserByID(t.OrgID)
- if err != nil {
- return err
- }
- sess := x.NewSession()
- defer sessionRelease(sess)
- if err = sess.Begin(); err != nil {
- return err
- }
- // Delete all accesses.
- for _, repo := range t.Repos {
- if err = repo.recalculateTeamAccesses(sess, t.ID); err != nil {
- return err
- }
- }
- // Delete team-user.
- if _, err = sess.Where("org_id=?", org.Id).Where("team_id=?", t.ID).Delete(new(TeamUser)); err != nil {
- return err
- }
- // Delete team.
- if _, err = sess.Id(t.ID).Delete(new(Team)); err != nil {
- 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 {
- return err
- }
- return sess.Commit()
- }
- // ___________ ____ ___
- // \__ ___/___ _____ _____ | | \______ ___________
- // | |_/ __ \\__ \ / \| | / ___// __ \_ __ \
- // | |\ ___/ / __ \| Y Y \ | /\___ \\ ___/| | \/
- // |____| \___ >____ /__|_| /______//____ >\___ >__|
- // \/ \/ \/ \/ \/
- // TeamUser represents an team-user relation.
- type TeamUser struct {
- ID int64 `xorm:"pk autoincr"`
- OrgID int64 `xorm:"INDEX"`
- TeamID int64 `xorm:"UNIQUE(s)"`
- Uid int64 `xorm:"UNIQUE(s)"`
- }
- 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))
- return has
- }
- // IsTeamMember returns true if given user is a member of team.
- func IsTeamMember(orgID, teamID, uid int64) bool {
- return isTeamMember(x, orgID, teamID, uid)
- }
- 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
- }
- // GetTeamMembers returns all members in given team of organization.
- func GetTeamMembers(teamID int64) ([]*User, error) {
- return getTeamMembers(x, teamID)
- }
- func getUserTeams(e Engine, orgId, uid int64) ([]*Team, error) {
- tus := make([]*TeamUser, 0, 5)
- if err := e.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 := e.Id(tu.TeamID).Get(t)
- if err != nil {
- return nil, err
- } else if !has {
- return nil, ErrTeamNotExist
- }
- ts[i] = t
- }
- return ts, nil
- }
- // GetUserTeams returns all teams that user belongs to in given organization.
- func GetUserTeams(orgId, uid int64) ([]*Team, error) {
- return getUserTeams(x, orgId, uid)
- }
- // 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
- }
- sess := x.NewSession()
- defer sessionRelease(sess)
- if err = sess.Begin(); err != nil {
- return err
- }
- tu := &TeamUser{
- Uid: uid,
- OrgID: orgId,
- TeamID: teamId,
- }
- if _, err = sess.Insert(tu); err != nil {
- return err
- } else if _, err = sess.Id(t.ID).Update(t); err != nil {
- return err
- }
- // Give access to team repositories.
- for _, repo := range t.Repos {
- if err = repo.recalculateTeamAccesses(sess, 0); err != nil {
- return err
- }
- }
- // We make sure it exists before.
- ou := new(OrgUser)
- if _, err = sess.Where("uid=?", uid).And("org_id=?", orgId).Get(ou); err != nil {
- return err
- }
- ou.NumTeams++
- if t.IsOwnerTeam() {
- ou.IsOwner = true
- }
- if _, err = sess.Id(ou.ID).AllCols().Update(ou); err != nil {
- return err
- }
- return sess.Commit()
- }
- func removeTeamMember(e Engine, orgId, teamId, uid int64) error {
- if !isTeamMember(e, orgId, teamId, uid) {
- return nil
- }
- // Get team and its repositories.
- t, err := getTeamById(e, 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{UID: uid}
- }
- t.NumMembers--
- if err = t.getRepositories(e); err != nil {
- return err
- }
- // Get organization.
- org, err := getUserByID(e, orgId)
- if err != nil {
- return err
- }
- tu := &TeamUser{
- Uid: uid,
- OrgID: orgId,
- TeamID: teamId,
- }
- if _, err := e.Delete(tu); err != nil {
- return err
- } else if _, err = e.Id(t.ID).AllCols().Update(t); err != nil {
- return err
- }
- // Delete access to team repositories.
- for _, repo := range t.Repos {
- if err = repo.recalculateTeamAccesses(e, 0); err != nil {
- return err
- }
- }
- // This must exist.
- ou := new(OrgUser)
- _, err = e.Where("uid=?", uid).And("org_id=?", org.Id).Get(ou)
- if err != nil {
- return err
- }
- ou.NumTeams--
- if t.IsOwnerTeam() {
- ou.IsOwner = false
- }
- if _, err = e.Id(ou.ID).AllCols().Update(ou); err != nil {
- return err
- }
- return nil
- }
- // RemoveTeamMember removes member from given team of given organization.
- func RemoveTeamMember(orgId, teamId, uid int64) error {
- sess := x.NewSession()
- defer sessionRelease(sess)
- if err := sess.Begin(); err != nil {
- return err
- }
- if err := removeTeamMember(sess, orgId, teamId, uid); err != nil {
- return err
- }
- return sess.Commit()
- }
- // ___________ __________
- // \__ ___/___ _____ _____\______ \ ____ ______ ____
- // | |_/ __ \\__ \ / \| _// __ \\____ \ / _ \
- // | |\ ___/ / __ \| 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)
- }
- 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)
- }
- // GetUserRepositories gets all repositories of an organization,
- // that the user with the given userID has access to.
- func (org *User) GetUserRepositories(userID int64) (err error) {
- teams := make([]*Team, 0, 10)
- if err = x.Cols("`team`.id").
- Where("`team_user`.org_id=?", org.Id).
- And("`team_user`.uid=?", userID).
- Join("INNER", "`team_user`", "`team_user`.team_id=`team`.id").
- Find(&teams); err != nil {
- return fmt.Errorf("GetUserRepositories: get teams: %v", err)
- }
- teamIDs := make([]string, len(teams))
- for i := range teams {
- teamIDs[i] = com.ToStr(teams[i].ID)
- }
- if len(teamIDs) == 0 {
- // user has no team but "IN ()" is invalid SQL
- teamIDs = append(teamIDs, "-1") // there is no repo with id=-1
- }
- // Due to a bug in xorm using IN() together with OR() is impossible.
- // As a workaround, we have to build the IN statement on our own, until this is fixed.
- // https://github.com/go-xorm/xorm/issues/342
- if err = x.Cols("`repository`.*").
- Join("INNER", "`team_repo`", "`team_repo`.repo_id=`repository`.id").
- Where("`repository`.owner_id=?", org.Id).
- And("`repository`.is_private=?", false).
- Or("`team_repo`.team_id=(?)", strings.Join(teamIDs, ",")).
- GroupBy("`repository`.id").
- Find(&org.Repos); err != nil {
- return fmt.Errorf("GetUserRepositories: get repositories: %v", err)
- }
- // FIXME: should I change this value inside method,
- // or only in location of caller where it's really needed?
- org.NumRepos = len(org.Repos)
- return nil
- }
- // GetTeams returns all teams that belong to organization,
- // and that the user has joined.
- func (org *User) GetUserTeams(userID int64) error {
- if err := x.Cols("`team`.*").
- Where("`team_user`.org_id=?", org.Id).
- And("`team_user`.uid=?", userID).
- Join("INNER", "`team_user`", "`team_user`.team_id=`team`.id").
- Find(&org.Teams); err != nil {
- return fmt.Errorf("GetUserTeams: %v", err)
- }
- // FIXME: should I change this value inside method,
- // or only in location of caller where it's really needed?
- org.NumTeams = len(org.Teams)
- return nil
- }
|