| @@ -3,7 +3,7 @@ Gogs - Go Git Service [ |  | ||||
| ##### Current version: 0.9.15 | |||||
| ##### Current version: 0.9.16 | |||||
| | Web | UI | Preview | | | Web | UI | Preview | | ||||
| |:-------------:|:-------:|:-------:| | |:-------------:|:-------:|:-------:| | ||||
| @@ -17,7 +17,7 @@ import ( | |||||
| "github.com/gogits/gogs/modules/setting" | "github.com/gogits/gogs/modules/setting" | ||||
| ) | ) | ||||
| const APP_VER = "0.9.15.0323" | |||||
| const APP_VER = "0.9.16.0325" | |||||
| func init() { | func init() { | ||||
| runtime.GOMAXPROCS(runtime.NumCPU()) | runtime.GOMAXPROCS(runtime.NumCPU()) | ||||
| @@ -426,618 +426,6 @@ func RemoveOrgUser(orgId, uid int64) error { | |||||
| return sess.Commit() | 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 { | func removeOrgRepo(e Engine, orgID, repoID int64) error { | ||||
| _, err := e.Delete(&TeamRepo{ | _, err := e.Delete(&TeamRepo{ | ||||
| OrgID: orgID, | OrgID: orgID, | ||||
| @@ -0,0 +1,618 @@ | |||||
| // Copyright 2016 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" | |||||
| "strings" | |||||
| ) | |||||
| 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 membership of the team to the organization, | |||||
| // the user will have membership to the organization automatically when needed. | |||||
| 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 membership of given team to given organization, | |||||
| // the user will have membership to given organization automatically when needed. | |||||
| 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) | |||||
| } | |||||
| @@ -18,6 +18,7 @@ import ( | |||||
| type APIContext struct { | type APIContext struct { | ||||
| *Context | *Context | ||||
| Org *APIOrganization | |||||
| } | } | ||||
| // Error responses error message to client with given message. | // Error responses error message to client with given message. | ||||
| @@ -40,6 +41,7 @@ func (ctx *APIContext) Error(status int, title string, obj interface{}) { | |||||
| }) | }) | ||||
| } | } | ||||
| // SetLinkHeader sets pagination link header by given totol number and page size. | |||||
| func (ctx *APIContext) SetLinkHeader(total, pageSize int) { | func (ctx *APIContext) SetLinkHeader(total, pageSize int) { | ||||
| page := paginater.New(total, pageSize, ctx.QueryInt("page"), 0) | page := paginater.New(total, pageSize, ctx.QueryInt("page"), 0) | ||||
| links := make([]string, 0, 4) | links := make([]string, 0, 4) | ||||
| @@ -0,0 +1,14 @@ | |||||
| // Copyright 2016 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 context | |||||
| import ( | |||||
| "github.com/gogits/gogs/models" | |||||
| ) | |||||
| type APIOrganization struct { | |||||
| Organization *models.User | |||||
| Team *models.Team | |||||
| } | |||||
| @@ -14,13 +14,8 @@ import ( | |||||
| ) | ) | ||||
| func CreateTeam(ctx *context.APIContext, form api.CreateTeamOption) { | func CreateTeam(ctx *context.APIContext, form api.CreateTeamOption) { | ||||
| org := user.GetUserByParamsName(ctx, ":orgname") | |||||
| if ctx.Written() { | |||||
| return | |||||
| } | |||||
| team := &models.Team{ | team := &models.Team{ | ||||
| OrgID: org.Id, | |||||
| OrgID: ctx.Org.Organization.Id, | |||||
| Name: form.Name, | Name: form.Name, | ||||
| Description: form.Description, | Description: form.Description, | ||||
| Authorize: models.ParseAccessMode(form.Permission), | Authorize: models.ParseAccessMode(form.Permission), | ||||
| @@ -36,3 +31,30 @@ func CreateTeam(ctx *context.APIContext, form api.CreateTeamOption) { | |||||
| ctx.JSON(201, convert.ToTeam(team)) | ctx.JSON(201, convert.ToTeam(team)) | ||||
| } | } | ||||
| func AddTeamMember(ctx *context.APIContext) { | |||||
| u := user.GetUserByParams(ctx) | |||||
| if ctx.Written() { | |||||
| return | |||||
| } | |||||
| if err := ctx.Org.Team.AddMember(u.Id); err != nil { | |||||
| ctx.Error(500, "AddMember", err) | |||||
| return | |||||
| } | |||||
| ctx.Status(204) | |||||
| } | |||||
| func RemoveTeamMember(ctx *context.APIContext) { | |||||
| u := user.GetUserByParams(ctx) | |||||
| if ctx.Written() { | |||||
| return | |||||
| } | |||||
| if err := ctx.Org.Team.RemoveMember(u.Id); err != nil { | |||||
| ctx.Error(500, "RemoveMember", err) | |||||
| return | |||||
| } | |||||
| ctx.Status(204) | |||||
| } | |||||
| @@ -110,6 +110,42 @@ func ReqAdmin() macaron.Handler { | |||||
| } | } | ||||
| } | } | ||||
| func OrgAssignment(args ...bool) macaron.Handler { | |||||
| var ( | |||||
| assignTeam bool | |||||
| ) | |||||
| if len(args) > 0 { | |||||
| assignTeam = args[0] | |||||
| } | |||||
| return func(ctx *context.APIContext) { | |||||
| org, err := models.GetUserByName(ctx.Params(":orgname")) | |||||
| if err != nil { | |||||
| if models.IsErrUserNotExist(err) { | |||||
| ctx.Status(404) | |||||
| } else { | |||||
| ctx.Error(500, "GetUserByName", err) | |||||
| } | |||||
| return | |||||
| } | |||||
| ctx.Org = &context.APIOrganization{ | |||||
| Organization: org, | |||||
| } | |||||
| if assignTeam { | |||||
| ctx.Org.Team, err = models.GetTeamByID(ctx.ParamsInt64(":teamid")) | |||||
| if err != nil { | |||||
| if models.IsErrUserNotExist(err) { | |||||
| ctx.Status(404) | |||||
| } else { | |||||
| ctx.Error(500, "GetTeamById", err) | |||||
| } | |||||
| return | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| // RegisterRoutes registers all v1 APIs routes to web application. | // RegisterRoutes registers all v1 APIs routes to web application. | ||||
| // FIXME: custom form error response | // FIXME: custom form error response | ||||
| func RegisterRoutes(m *macaron.Macaron) { | func RegisterRoutes(m *macaron.Macaron) { | ||||
| @@ -208,7 +244,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| m.Group("/orgs/:orgname", func() { | m.Group("/orgs/:orgname", func() { | ||||
| m.Combo("").Get(org.Get).Patch(bind(api.EditOrgOption{}), org.Edit) | m.Combo("").Get(org.Get).Patch(bind(api.EditOrgOption{}), org.Edit) | ||||
| m.Combo("/teams").Get(org.ListTeams) | m.Combo("/teams").Get(org.ListTeams) | ||||
| }) | |||||
| }, OrgAssignment()) | |||||
| m.Any("/*", func(ctx *context.Context) { | m.Any("/*", func(ctx *context.Context) { | ||||
| ctx.Error(404) | ctx.Error(404) | ||||
| @@ -228,7 +264,13 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
| }) | }) | ||||
| m.Group("/orgs/:orgname", func() { | m.Group("/orgs/:orgname", func() { | ||||
| m.Combo("/teams").Post(bind(api.CreateTeamOption{}), admin.CreateTeam) | |||||
| m.Group("/teams", func() { | |||||
| m.Post("", OrgAssignment(), bind(api.CreateTeamOption{}), admin.CreateTeam) | |||||
| m.Group("/:teamid", func() { | |||||
| m.Combo("/memberships/:username").Put(admin.AddTeamMember).Delete(admin.RemoveTeamMember) | |||||
| }, OrgAssignment(true)) | |||||
| }) | |||||
| }) | }) | ||||
| }, ReqAdmin()) | }, ReqAdmin()) | ||||
| }, context.APIContexter()) | }, context.APIContexter()) | ||||
| @@ -42,20 +42,12 @@ func ListUserOrgs(ctx *context.APIContext) { | |||||
| // https://github.com/gogits/go-gogs-client/wiki/Organizations#get-an-organization | // https://github.com/gogits/go-gogs-client/wiki/Organizations#get-an-organization | ||||
| func Get(ctx *context.APIContext) { | func Get(ctx *context.APIContext) { | ||||
| org := user.GetUserByParamsName(ctx, ":orgname") | |||||
| if ctx.Written() { | |||||
| return | |||||
| } | |||||
| ctx.JSON(200, convert.ToOrganization(org)) | |||||
| ctx.JSON(200, convert.ToOrganization(ctx.Org.Organization)) | |||||
| } | } | ||||
| // https://github.com/gogits/go-gogs-client/wiki/Organizations#edit-an-organization | // https://github.com/gogits/go-gogs-client/wiki/Organizations#edit-an-organization | ||||
| func Edit(ctx *context.APIContext, form api.EditOrgOption) { | func Edit(ctx *context.APIContext, form api.EditOrgOption) { | ||||
| org := user.GetUserByParamsName(ctx, ":orgname") | |||||
| if ctx.Written() { | |||||
| return | |||||
| } | |||||
| org := ctx.Org.Organization | |||||
| if !org.IsOwnedBy(ctx.User.Id) { | if !org.IsOwnedBy(ctx.User.Id) { | ||||
| ctx.Status(403) | ctx.Status(403) | ||||
| return | return | ||||
| @@ -9,15 +9,10 @@ import ( | |||||
| "github.com/gogits/gogs/modules/context" | "github.com/gogits/gogs/modules/context" | ||||
| "github.com/gogits/gogs/routers/api/v1/convert" | "github.com/gogits/gogs/routers/api/v1/convert" | ||||
| "github.com/gogits/gogs/routers/api/v1/user" | |||||
| ) | ) | ||||
| func ListTeams(ctx *context.APIContext) { | func ListTeams(ctx *context.APIContext) { | ||||
| org := user.GetUserByParamsName(ctx, ":orgname") | |||||
| if ctx.Written() { | |||||
| return | |||||
| } | |||||
| org := ctx.Org.Organization | |||||
| if err := org.GetTeams(); err != nil { | if err := org.GetTeams(); err != nil { | ||||
| ctx.Error(500, "GetTeams", err) | ctx.Error(500, "GetTeams", err) | ||||
| return | return | ||||
| @@ -1 +1 @@ | |||||
| 0.9.15.0323 | |||||
| 0.9.16.0325 | |||||