mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-11-19 12:20:53 +00:00
Finish new edit team page, add member to team
This commit is contained in:
parent
e325c8499a
commit
21a1b8e5a3
|
@ -48,7 +48,7 @@ and it takes care of all the other things for you`,
|
||||||
Flags: []cli.Flag{},
|
Flags: []cli.Flag{},
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkVersion checks if binary matches the version of temolate files.
|
// checkVersion checks if binary matches the version of templates files.
|
||||||
func checkVersion() {
|
func checkVersion() {
|
||||||
data, err := ioutil.ReadFile(path.Join(setting.StaticRootPath, "templates/.VERSION"))
|
data, err := ioutil.ReadFile(path.Join(setting.StaticRootPath, "templates/.VERSION"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -235,7 +235,7 @@ func runWeb(*cli.Context) {
|
||||||
r.Get("/members/action/:action", org.MembersAction)
|
r.Get("/members/action/:action", org.MembersAction)
|
||||||
|
|
||||||
r.Get("/teams", org.Teams)
|
r.Get("/teams", org.Teams)
|
||||||
r.Get("/teams/:team", org.SingleTeam)
|
r.Get("/teams/:team", org.TeamMembers)
|
||||||
r.Get("/teams/:team/action/:action", org.TeamsAction)
|
r.Get("/teams/:team/action/:action", org.TeamsAction)
|
||||||
}, middleware.OrgAssignment(true, true))
|
}, middleware.OrgAssignment(true, true))
|
||||||
|
|
||||||
|
@ -243,6 +243,8 @@ func runWeb(*cli.Context) {
|
||||||
r.Get("/teams/new", org.NewTeam)
|
r.Get("/teams/new", org.NewTeam)
|
||||||
r.Post("/teams/new", bindIgnErr(auth.CreateTeamForm{}), org.NewTeamPost)
|
r.Post("/teams/new", bindIgnErr(auth.CreateTeamForm{}), org.NewTeamPost)
|
||||||
r.Get("/teams/:team/edit", org.EditTeam)
|
r.Get("/teams/:team/edit", org.EditTeam)
|
||||||
|
r.Post("/teams/:team/edit", bindIgnErr(auth.CreateTeamForm{}), org.EditTeamPost)
|
||||||
|
r.Post("/teams/:team/delete", org.DeleteTeam)
|
||||||
|
|
||||||
m.Group("/settings", func(r *macaron.Router) {
|
m.Group("/settings", func(r *macaron.Router) {
|
||||||
r.Get("", org.Settings)
|
r.Get("", org.Settings)
|
||||||
|
|
|
@ -283,6 +283,13 @@ teams.no_desc = This team has no description
|
||||||
teams.settings = Settings
|
teams.settings = Settings
|
||||||
teams.owners_permission_desc = Owners have full access to <strong>all repositories</strong> and have <strong>admin rights</strong> to the organization.
|
teams.owners_permission_desc = Owners have full access to <strong>all repositories</strong> and have <strong>admin rights</strong> to the organization.
|
||||||
teams.members = Team Members
|
teams.members = Team Members
|
||||||
|
teams.update_settings = Update Settings
|
||||||
|
teams.delete_team = Delete This Team
|
||||||
|
teams.add_team_member = Add Team Member
|
||||||
|
teams.delete_team_success = Given team has been successfully deleted.
|
||||||
|
teams.read_permission_desc = This team grants <strong>Read</strong> access: members can view and clone the team's repositories.
|
||||||
|
teams.write_permission_desc = This team grants <strong>Write</strong> access: members can read from and push to the team's repositories.
|
||||||
|
teams.admin_permission_desc = This team grants <strong>Admin</strong> access: members can read from, push to, and add collaborators to the team's repositories.
|
||||||
|
|
||||||
[action]
|
[action]
|
||||||
create_repo = created repository <a href="/%s">%s</a>
|
create_repo = created repository <a href="/%s">%s</a>
|
||||||
|
|
|
@ -283,6 +283,13 @@ teams.no_desc = 该团队暂无描述
|
||||||
teams.settings = 团队设置
|
teams.settings = 团队设置
|
||||||
teams.owners_permission_desc = 管理员团队对 <strong>所有仓库</strong> 具有操作权限,且对组织具有 <strong>管理员权限</strong>。
|
teams.owners_permission_desc = 管理员团队对 <strong>所有仓库</strong> 具有操作权限,且对组织具有 <strong>管理员权限</strong>。
|
||||||
teams.members = 团队成员
|
teams.members = 团队成员
|
||||||
|
teams.update_settings = 更新团队设置
|
||||||
|
teams.delete_team = 删除当前团队
|
||||||
|
teams.add_team_member = 添加团队成员
|
||||||
|
teams.delete_team_success = 指定团队已经被成功删除!
|
||||||
|
teams.read_permission_desc = 该团队拥有对所属仓库的 <strong>读取</strong> 权限,团队成员可以进行查看和克隆等只读操作。
|
||||||
|
teams.write_permission_desc = 该团队拥有对所属仓库的 <strong>读取</strong> 和 <strong>写入</strong> 的权限。
|
||||||
|
teams.admin_permission_desc = 该团队拥有一定的 <strong>管理</strong> 权限,团队成员可以读取、克隆、推送以及添加其它仓库协作者。
|
||||||
|
|
||||||
[action]
|
[action]
|
||||||
create_repo = 创建了仓库 <a href="/%s">%s</a>
|
create_repo = 创建了仓库 <a href="/%s">%s</a>
|
||||||
|
|
2
gogs.go
2
gogs.go
|
@ -17,7 +17,7 @@ import (
|
||||||
"github.com/gogits/gogs/modules/setting"
|
"github.com/gogits/gogs/modules/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
const APP_VER = "0.4.7.0823 Alpha"
|
const APP_VER = "0.4.7.0824 Alpha"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
runtime.GOMAXPROCS(runtime.NumCPU())
|
runtime.GOMAXPROCS(runtime.NumCPU())
|
||||||
|
|
376
models/org.go
376
models/org.go
|
@ -6,11 +6,13 @@ package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Unknwon/com"
|
"github.com/Unknwon/com"
|
||||||
|
"github.com/go-xorm/xorm"
|
||||||
|
|
||||||
"github.com/gogits/gogs/modules/base"
|
"github.com/gogits/gogs/modules/base"
|
||||||
)
|
)
|
||||||
|
@ -134,10 +136,10 @@ func CreateOrganization(org, owner *User) (*User, error) {
|
||||||
|
|
||||||
// Add initial creator to organization and owner team.
|
// Add initial creator to organization and owner team.
|
||||||
ou := &OrgUser{
|
ou := &OrgUser{
|
||||||
Uid: owner.Id,
|
Uid: owner.Id,
|
||||||
OrgId: org.Id,
|
OrgId: org.Id,
|
||||||
IsOwner: true,
|
IsOwner: true,
|
||||||
NumTeam: 1,
|
NumTeams: 1,
|
||||||
}
|
}
|
||||||
if _, err = sess.Insert(ou); err != nil {
|
if _, err = sess.Insert(ou); err != nil {
|
||||||
sess.Rollback()
|
sess.Rollback()
|
||||||
|
@ -199,7 +201,7 @@ type OrgUser struct {
|
||||||
OrgId int64 `xorm:"INDEX UNIQUE(s)"`
|
OrgId int64 `xorm:"INDEX UNIQUE(s)"`
|
||||||
IsPublic bool
|
IsPublic bool
|
||||||
IsOwner bool
|
IsOwner bool
|
||||||
NumTeam int
|
NumTeams int
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsOrganizationOwner returns true if given user is in the owner team.
|
// IsOrganizationOwner returns true if given user is in the owner team.
|
||||||
|
@ -255,17 +257,17 @@ func AddOrgUser(orgId, uid int64) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ou := &OrgUser{
|
|
||||||
Uid: uid,
|
|
||||||
OrgId: orgId,
|
|
||||||
}
|
|
||||||
|
|
||||||
sess := x.NewSession()
|
sess := x.NewSession()
|
||||||
defer sess.Close()
|
defer sess.Close()
|
||||||
if err := sess.Begin(); err != nil {
|
if err := sess.Begin(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ou := &OrgUser{
|
||||||
|
Uid: uid,
|
||||||
|
OrgId: orgId,
|
||||||
|
}
|
||||||
|
|
||||||
if _, err := sess.Insert(ou); err != nil {
|
if _, err := sess.Insert(ou); err != nil {
|
||||||
sess.Rollback()
|
sess.Rollback()
|
||||||
return err
|
return err
|
||||||
|
@ -288,12 +290,17 @@ func RemoveOrgUser(orgId, uid int64) error {
|
||||||
return nil
|
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.
|
// Check if the user to delete is the last member in owner team.
|
||||||
if IsOrganizationOwner(orgId, uid) {
|
if IsOrganizationOwner(orgId, uid) {
|
||||||
org, err := GetUserById(orgId)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
t, err := org.GetOwnerTeam()
|
t, err := org.GetOwnerTeam()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -317,6 +324,33 @@ func RemoveOrgUser(orgId, uid int64) error {
|
||||||
return err
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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()
|
return sess.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,6 +386,11 @@ type Team struct {
|
||||||
NumMembers 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.
|
// IsTeamMember returns true if given user is a member of team.
|
||||||
func (t *Team) IsMember(uid int64) bool {
|
func (t *Team) IsMember(uid int64) bool {
|
||||||
return IsTeamMember(t.OrgId, t.Id, uid)
|
return IsTeamMember(t.OrgId, t.Id, uid)
|
||||||
|
@ -362,7 +401,10 @@ func (t *Team) GetRepositories() error {
|
||||||
idStrs := strings.Split(t.RepoIds, "|")
|
idStrs := strings.Split(t.RepoIds, "|")
|
||||||
t.Repos = make([]*Repository, 0, len(idStrs))
|
t.Repos = make([]*Repository, 0, len(idStrs))
|
||||||
for _, str := range idStrs {
|
for _, str := range idStrs {
|
||||||
id := com.StrTo(str).MustInt64()
|
if len(str) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
id := com.StrTo(str[1:]).MustInt64()
|
||||||
if id == 0 {
|
if id == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -459,15 +501,177 @@ func GetTeamById(teamId int64) (*Team, error) {
|
||||||
return t, nil
|
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.
|
// 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 {
|
if len(t.Description) > 255 {
|
||||||
t.Description = 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
|
||||||
|
}
|
||||||
|
|
||||||
|
mode := READABLE
|
||||||
|
if t.Authorize > ORG_READABLE {
|
||||||
|
mode = WRITABLE
|
||||||
|
}
|
||||||
|
access := &Access{
|
||||||
|
Mode: mode,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, repo := range t.Repos {
|
||||||
|
access.RepoName = path.Join(org.LowerName, repo.LowerName)
|
||||||
|
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.UserName = u.LowerName
|
||||||
|
if _, err = sess.Update(access); err != nil {
|
||||||
|
sess.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
t.LowerName = strings.ToLower(t.Name)
|
t.LowerName = strings.ToLower(t.Name)
|
||||||
_, err := x.Id(t.Id).AllCols().Update(t)
|
if _, err = sess.Id(t.Id).AllCols().Update(t); err != nil {
|
||||||
return err
|
sess.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return sess.Commit()
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteTeam deletes given team.
|
||||||
|
// It's caller's responsibility to assign organization ID.
|
||||||
|
func DeleteTeam(t *Team) error {
|
||||||
|
if err := t.GetRepositories(); err != nil {
|
||||||
|
return err
|
||||||
|
} else if err = t.GetMembers(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get organization.
|
||||||
|
org, err := GetUserById(t.OrgId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sess := x.NewSession()
|
||||||
|
defer sess.Close()
|
||||||
|
if err = sess.Begin(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete all accesses.
|
||||||
|
mode := READABLE
|
||||||
|
if t.Authorize > ORG_READABLE {
|
||||||
|
mode = WRITABLE
|
||||||
|
}
|
||||||
|
access := new(Access)
|
||||||
|
|
||||||
|
for _, repo := range t.Repos {
|
||||||
|
access.RepoName = path.Join(org.LowerName, repo.LowerName)
|
||||||
|
for _, u := range t.Members {
|
||||||
|
access.UserName = u.LowerName
|
||||||
|
access.Mode = mode
|
||||||
|
auth, err := GetHighestAuthorize(org.Id, u.Id, t.Id, repo.Id)
|
||||||
|
if err != nil {
|
||||||
|
sess.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if auth == 0 {
|
||||||
|
if _, err = sess.Delete(access); err != nil {
|
||||||
|
sess.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if auth < t.Authorize {
|
||||||
|
// Downgrade authorize level.
|
||||||
|
mode := READABLE
|
||||||
|
if auth > ORG_READABLE {
|
||||||
|
mode = WRITABLE
|
||||||
|
}
|
||||||
|
access.Mode = mode
|
||||||
|
if _, err = sess.Update(access); err != nil {
|
||||||
|
sess.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete team-user.
|
||||||
|
if _, err = sess.Where("org_id=?", org.Id).Where("team_id=?", t.Id).Delete(new(TeamUser)); err != nil {
|
||||||
|
sess.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete team.
|
||||||
|
if _, err = sess.Id(t.Id).Delete(new(Team)); err != nil {
|
||||||
|
sess.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Update organization number of teams.
|
||||||
|
if _, err = sess.Exec("UPDATE `user` SET num_teams = num_teams - 1 WHERE id = ?", t.OrgId); err != nil {
|
||||||
|
sess.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return sess.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ___________ ____ ___
|
// ___________ ____ ___
|
||||||
|
@ -509,12 +713,37 @@ func GetTeamMembers(orgId, teamId int64) ([]*User, error) {
|
||||||
return us, nil
|
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.
|
// AddTeamMember adds new member to given team of given organization.
|
||||||
func AddTeamMember(orgId, teamId, uid int64) error {
|
func AddTeamMember(orgId, teamId, uid int64) error {
|
||||||
if !IsOrganizationMember(orgId, uid) || IsTeamMember(orgId, teamId, uid) {
|
if IsTeamMember(orgId, teamId, uid) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := AddOrgUser(orgId, uid); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Get team and its repositories.
|
// Get team and its repositories.
|
||||||
t, err := GetTeamById(teamId)
|
t, err := GetTeamById(teamId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -569,18 +798,49 @@ func AddTeamMember(orgId, teamId, uid int64) error {
|
||||||
|
|
||||||
// Give access to team repositories.
|
// Give access to team repositories.
|
||||||
for _, repo := range t.Repos {
|
for _, repo := range t.Repos {
|
||||||
access.RepoName = path.Join(org.LowerName, repo.LowerName)
|
auth, err := GetHighestAuthorize(orgId, uid, teamId, repo.Id)
|
||||||
if _, err = sess.Insert(access); err != nil {
|
if err != nil {
|
||||||
sess.Rollback()
|
sess.Rollback()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
access.Id = 0
|
||||||
|
access.RepoName = path.Join(org.LowerName, repo.LowerName)
|
||||||
|
// Equal 0 means given access doesn't exist.
|
||||||
|
if auth == 0 {
|
||||||
|
if _, err = sess.Insert(access); err != nil {
|
||||||
|
sess.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else if auth < t.Authorize {
|
||||||
|
if _, err = sess.Update(access); err != nil {
|
||||||
|
sess.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Println("kao")
|
||||||
|
|
||||||
|
// 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()
|
return sess.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveTeamMember removes member from given team of given organization.
|
func removeTeamMemberWithSess(orgId, teamId, uid int64, sess *xorm.Session) error {
|
||||||
func RemoveTeamMember(orgId, teamId, uid int64) error {
|
|
||||||
if !IsTeamMember(orgId, teamId, uid) {
|
if !IsTeamMember(orgId, teamId, uid) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -590,6 +850,12 @@ func RemoveTeamMember(orgId, teamId, uid int64) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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--
|
t.NumMembers--
|
||||||
|
|
||||||
if err = t.GetRepositories(); err != nil {
|
if err = t.GetRepositories(); err != nil {
|
||||||
|
@ -608,22 +874,12 @@ func RemoveTeamMember(orgId, teamId, uid int64) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sess := x.NewSession()
|
|
||||||
defer sess.Close()
|
|
||||||
if err := sess.Begin(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
tu := &TeamUser{
|
tu := &TeamUser{
|
||||||
Uid: uid,
|
Uid: uid,
|
||||||
OrgId: orgId,
|
OrgId: orgId,
|
||||||
TeamId: teamId,
|
TeamId: teamId,
|
||||||
}
|
}
|
||||||
|
|
||||||
access := &Access{
|
|
||||||
UserName: u.LowerName,
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := sess.Delete(tu); err != nil {
|
if _, err := sess.Delete(tu); err != nil {
|
||||||
sess.Rollback()
|
sess.Rollback()
|
||||||
return err
|
return err
|
||||||
|
@ -633,13 +889,63 @@ func RemoveTeamMember(orgId, teamId, uid int64) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete access to team repositories.
|
// Delete access to team repositories.
|
||||||
|
access := &Access{
|
||||||
|
UserName: u.LowerName,
|
||||||
|
}
|
||||||
|
|
||||||
for _, repo := range t.Repos {
|
for _, repo := range t.Repos {
|
||||||
access.RepoName = path.Join(org.LowerName, repo.LowerName)
|
auth, err := GetHighestAuthorize(orgId, uid, teamId, repo.Id)
|
||||||
if _, err = sess.Delete(access); err != nil {
|
if err != nil {
|
||||||
|
sess.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete access if this is the last team user belongs to.
|
||||||
|
if auth == 0 {
|
||||||
|
access.RepoName = path.Join(org.LowerName, repo.LowerName)
|
||||||
|
_, err = sess.Delete(access)
|
||||||
|
} else if auth < t.Authorize {
|
||||||
|
// Downgrade authorize level.
|
||||||
|
mode := READABLE
|
||||||
|
if auth > ORG_READABLE {
|
||||||
|
mode = WRITABLE
|
||||||
|
}
|
||||||
|
access.Mode = mode
|
||||||
|
_, err = sess.Update(access)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
sess.Rollback()
|
sess.Rollback()
|
||||||
return err
|
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()
|
return sess.Commit()
|
||||||
}
|
}
|
||||||
|
|
|
@ -525,6 +525,7 @@ func CreateRepository(u *User, name, desc, lang, license string, private, mirror
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, u := range us {
|
for _, u := range us {
|
||||||
|
access.Id = 0
|
||||||
access.UserName = u.LowerName
|
access.UserName = u.LowerName
|
||||||
if _, err = sess.Insert(access); err != nil {
|
if _, err = sess.Insert(access); err != nil {
|
||||||
sess.Rollback()
|
sess.Rollback()
|
||||||
|
@ -707,6 +708,10 @@ func TransferOwnership(u *User, newOwner string, repo *Repository) (err error) {
|
||||||
|
|
||||||
// ChangeRepositoryName changes all corresponding setting from old repository name to new one.
|
// ChangeRepositoryName changes all corresponding setting from old repository name to new one.
|
||||||
func ChangeRepositoryName(userName, oldRepoName, newRepoName string) (err error) {
|
func ChangeRepositoryName(userName, oldRepoName, newRepoName string) (err error) {
|
||||||
|
if !IsLegalName(newRepoName) {
|
||||||
|
return ErrRepoNameIllegal
|
||||||
|
}
|
||||||
|
|
||||||
// Update accesses.
|
// Update accesses.
|
||||||
accesses := make([]Access, 0, 10)
|
accesses := make([]Access, 0, 10)
|
||||||
if err = x.Find(&accesses, &Access{RepoName: strings.ToLower(userName + "/" + oldRepoName)}); err != nil {
|
if err = x.Find(&accesses, &Access{RepoName: strings.ToLower(userName + "/" + oldRepoName)}); err != nil {
|
||||||
|
|
|
@ -54,7 +54,8 @@ type User struct {
|
||||||
LoginSource int64 `xorm:"not null default 0"`
|
LoginSource int64 `xorm:"not null default 0"`
|
||||||
LoginName string
|
LoginName string
|
||||||
Type UserType
|
Type UserType
|
||||||
Orgs []*User `xorm:"-"`
|
Orgs []*User `xorm:"-"`
|
||||||
|
Repos []*Repository `xorm:"-"`
|
||||||
NumFollowers int
|
NumFollowers int
|
||||||
NumFollowings int
|
NumFollowings int
|
||||||
NumStars int
|
NumStars int
|
||||||
|
@ -143,6 +144,12 @@ func (u *User) GetOrganizationCount() (int64, error) {
|
||||||
return x.Where("uid=?", u.Id).Count(new(OrgUser))
|
return x.Where("uid=?", u.Id).Count(new(OrgUser))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRepositories returns all repositories that user owns, including private repositories.
|
||||||
|
func (u *User) GetRepositories() (err error) {
|
||||||
|
u.Repos, err = GetRepositories(u.Id, true)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// GetOrganizations returns all organizations that user belongs to.
|
// GetOrganizations returns all organizations that user belongs to.
|
||||||
func (u *User) GetOrganizations() error {
|
func (u *User) GetOrganizations() error {
|
||||||
ous, err := GetOrgUsersByUserId(u.Id)
|
ous, err := GetOrgUsersByUserId(u.Id)
|
||||||
|
|
|
@ -46,6 +46,7 @@ type Context struct {
|
||||||
IsBranch bool
|
IsBranch bool
|
||||||
IsTag bool
|
IsTag bool
|
||||||
IsCommit bool
|
IsCommit bool
|
||||||
|
IsAdmin bool // Current user is admin level.
|
||||||
HasAccess bool
|
HasAccess bool
|
||||||
Repository *models.Repository
|
Repository *models.Repository
|
||||||
Owner *models.User
|
Owner *models.User
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"github.com/Unknwon/macaron"
|
"github.com/Unknwon/macaron"
|
||||||
|
|
||||||
"github.com/gogits/gogs/models"
|
"github.com/gogits/gogs/models"
|
||||||
|
"github.com/gogits/gogs/modules/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
func OrgAssignment(redirect bool, args ...bool) macaron.Handler {
|
func OrgAssignment(redirect bool, args ...bool) macaron.Handler {
|
||||||
|
@ -35,6 +36,7 @@ func OrgAssignment(redirect bool, args ...bool) macaron.Handler {
|
||||||
if err == models.ErrUserNotExist {
|
if err == models.ErrUserNotExist {
|
||||||
ctx.Handle(404, "GetUserByName", err)
|
ctx.Handle(404, "GetUserByName", err)
|
||||||
} else if redirect {
|
} else if redirect {
|
||||||
|
log.Error(4, "GetUserByName", err)
|
||||||
ctx.Redirect("/")
|
ctx.Redirect("/")
|
||||||
} else {
|
} else {
|
||||||
ctx.Handle(500, "GetUserByName", err)
|
ctx.Handle(500, "GetUserByName", err)
|
||||||
|
@ -52,17 +54,14 @@ func OrgAssignment(redirect bool, args ...bool) macaron.Handler {
|
||||||
} else {
|
} else {
|
||||||
if org.IsOrgMember(ctx.User.Id) {
|
if org.IsOrgMember(ctx.User.Id) {
|
||||||
ctx.Org.IsMember = true
|
ctx.Org.IsMember = true
|
||||||
// TODO: ctx.Org.IsAdminTeam
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (requireMember && !ctx.Org.IsMember) ||
|
if (requireMember && !ctx.Org.IsMember) ||
|
||||||
(requireOwner && !ctx.Org.IsOwner) ||
|
(requireOwner && !ctx.Org.IsOwner) {
|
||||||
(requireAdminTeam && !ctx.Org.IsAdminTeam) {
|
|
||||||
ctx.Handle(404, "OrgAssignment", err)
|
ctx.Handle(404, "OrgAssignment", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.Data["IsAdminTeam"] = ctx.Org.IsAdminTeam
|
|
||||||
ctx.Data["IsOrganizationOwner"] = ctx.Org.IsOwner
|
ctx.Data["IsOrganizationOwner"] = ctx.Org.IsOwner
|
||||||
|
|
||||||
ctx.Org.OrgLink = "/org/" + org.Name
|
ctx.Org.OrgLink = "/org/" + org.Name
|
||||||
|
@ -76,6 +75,7 @@ func OrgAssignment(redirect bool, args ...bool) macaron.Handler {
|
||||||
if err == models.ErrTeamNotExist {
|
if err == models.ErrTeamNotExist {
|
||||||
ctx.Handle(404, "GetTeam", err)
|
ctx.Handle(404, "GetTeam", err)
|
||||||
} else if redirect {
|
} else if redirect {
|
||||||
|
log.Error(4, "GetTeam", err)
|
||||||
ctx.Redirect("/")
|
ctx.Redirect("/")
|
||||||
} else {
|
} else {
|
||||||
ctx.Handle(500, "GetTeam", err)
|
ctx.Handle(500, "GetTeam", err)
|
||||||
|
@ -83,6 +83,12 @@ func OrgAssignment(redirect bool, args ...bool) macaron.Handler {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.Data["Team"] = ctx.Org.Team
|
ctx.Data["Team"] = ctx.Org.Team
|
||||||
|
ctx.Org.IsAdminTeam = ctx.Org.Team.IsOwnerTeam() || ctx.Org.Team.Authorize == models.ORG_ADMIN
|
||||||
|
}
|
||||||
|
ctx.Data["IsAdminTeam"] = ctx.Org.IsAdminTeam
|
||||||
|
if requireAdminTeam && !ctx.Org.IsAdminTeam {
|
||||||
|
ctx.Handle(404, "OrgAssignment", err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,6 +59,7 @@ func RepoAssignment(redirect bool, args ...bool) macaron.Handler {
|
||||||
if err == models.ErrUserNotExist {
|
if err == models.ErrUserNotExist {
|
||||||
ctx.Handle(404, "GetUserByName", err)
|
ctx.Handle(404, "GetUserByName", err)
|
||||||
} else if redirect {
|
} else if redirect {
|
||||||
|
log.Error(4, "GetUserByName", err)
|
||||||
ctx.Redirect("/")
|
ctx.Redirect("/")
|
||||||
} else {
|
} else {
|
||||||
ctx.Handle(500, "GetUserByName", err)
|
ctx.Handle(500, "GetUserByName", err)
|
||||||
|
@ -84,7 +85,7 @@ func RepoAssignment(redirect bool, args ...bool) macaron.Handler {
|
||||||
ctx.Repo.IsTrueOwner = true
|
ctx.Repo.IsTrueOwner = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// get repository
|
// Get repository.
|
||||||
repo, err := models.GetRepositoryByName(u.Id, repoName)
|
repo, err := models.GetRepositoryByName(u.Id, repoName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == models.ErrRepoNotExist {
|
if err == models.ErrRepoNotExist {
|
||||||
|
@ -102,8 +103,22 @@ func RepoAssignment(redirect bool, args ...bool) macaron.Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the mirror repository owner(mirror repository doesn't have access).
|
// Check if the mirror repository owner(mirror repository doesn't have access).
|
||||||
if ctx.IsSigned && !ctx.Repo.IsOwner && repo.OwnerId == ctx.User.Id {
|
if ctx.IsSigned && !ctx.Repo.IsOwner {
|
||||||
ctx.Repo.IsOwner = true
|
if repo.OwnerId == ctx.User.Id {
|
||||||
|
ctx.Repo.IsOwner = true
|
||||||
|
}
|
||||||
|
// Check if current user has admin permission to repository.
|
||||||
|
if u.IsOrganization() {
|
||||||
|
auth, err := models.GetHighestAuthorize(u.Id, ctx.User.Id, 0, repo.Id)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Handle(500, "GetHighestAuthorize", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if auth == models.ORG_ADMIN {
|
||||||
|
ctx.Repo.IsOwner = true
|
||||||
|
ctx.Repo.IsAdmin = true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check access.
|
// Check access.
|
||||||
|
@ -281,7 +296,7 @@ func RepoAssignment(redirect bool, args ...bool) macaron.Handler {
|
||||||
|
|
||||||
func RequireTrueOwner() macaron.Handler {
|
func RequireTrueOwner() macaron.Handler {
|
||||||
return func(ctx *Context) {
|
return func(ctx *Context) {
|
||||||
if !ctx.Repo.IsTrueOwner {
|
if !ctx.Repo.IsTrueOwner && !ctx.Repo.IsAdmin {
|
||||||
if !ctx.IsSigned {
|
if !ctx.IsSigned {
|
||||||
ctx.SetCookie("redirect_to", "/"+url.QueryEscape(ctx.Req.RequestURI))
|
ctx.SetCookie("redirect_to", "/"+url.QueryEscape(ctx.Req.RequestURI))
|
||||||
ctx.Redirect("/user/login")
|
ctx.Redirect("/user/login")
|
||||||
|
|
|
@ -1298,27 +1298,33 @@ The register and sign-in page style
|
||||||
.repo-setting-zone {
|
.repo-setting-zone {
|
||||||
padding: 30px;
|
padding: 30px;
|
||||||
}
|
}
|
||||||
|
#team-members-list,
|
||||||
#repo-collab-list {
|
#repo-collab-list {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
padding: 10px 0 5px 0;
|
padding: 10px 0 5px 0;
|
||||||
}
|
}
|
||||||
|
#team-members-list li.collab,
|
||||||
#repo-collab-list li.collab {
|
#repo-collab-list li.collab {
|
||||||
clear: both;
|
clear: both;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
padding: 0 15px 0 15px;
|
padding: 0 15px 0 15px;
|
||||||
}
|
}
|
||||||
|
#team-members-list a.member,
|
||||||
#repo-collab-list a.member {
|
#repo-collab-list a.member {
|
||||||
color: #444;
|
color: #444;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
line-height: 50px;
|
line-height: 50px;
|
||||||
}
|
}
|
||||||
|
#team-members-list a.member:hover,
|
||||||
#repo-collab-list a.member:hover {
|
#repo-collab-list a.member:hover {
|
||||||
color: #4183C4;
|
color: #4183C4;
|
||||||
}
|
}
|
||||||
|
#team-members-list .avatar,
|
||||||
#repo-collab-list .avatar {
|
#repo-collab-list .avatar {
|
||||||
margin-right: 1em;
|
margin-right: 1em;
|
||||||
width: 40px;
|
width: 40px;
|
||||||
}
|
}
|
||||||
|
#team-members-list .remove-collab,
|
||||||
#repo-collab-list .remove-collab {
|
#repo-collab-list .remove-collab {
|
||||||
color: #DD4B39;
|
color: #DD4B39;
|
||||||
}
|
}
|
||||||
|
@ -1871,3 +1877,14 @@ textarea#issue-add-content {
|
||||||
#org-team-card .panel-footer {
|
#org-team-card .panel-footer {
|
||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
}
|
}
|
||||||
|
#team-members-list .panel-body .search {
|
||||||
|
padding: 4px 0 10px 10px;
|
||||||
|
border-bottom: 1px solid #dddddd;
|
||||||
|
}
|
||||||
|
#team-members-list li.collab {
|
||||||
|
padding-top: 10px !important;
|
||||||
|
border-bottom: 1px solid #dddddd;
|
||||||
|
}
|
||||||
|
#team-members-list li.collab:last-child {
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
|
@ -351,6 +351,41 @@ function initInvite() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function initOrgTeamCreate() {
|
||||||
|
// Delete team.
|
||||||
|
$('#org-team-delete').click(function (e) {
|
||||||
|
if (!confirm('This team is going to be deleted, do you want to continue?')) {
|
||||||
|
e.preventDefault();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
var $form = $('#team-create-form')
|
||||||
|
$form.attr('action', $form.data('delete-url'));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function initTeamMembersList() {
|
||||||
|
// Add team member.
|
||||||
|
var $ul = $('#org-team-members-list');
|
||||||
|
$('#org-team-members-add').on('keyup', function () {
|
||||||
|
var $this = $(this);
|
||||||
|
if (!$this.val()) {
|
||||||
|
$ul.toggleHide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Gogs.searchUsers($this.val(), $ul);
|
||||||
|
}).on('focus', function () {
|
||||||
|
if (!$(this).val()) {
|
||||||
|
$ul.toggleHide();
|
||||||
|
} else {
|
||||||
|
$ul.toggleShow();
|
||||||
|
}
|
||||||
|
}).next().next().find('ul').on("click", 'li', function () {
|
||||||
|
$('#org-team-members-add').val($(this).text());
|
||||||
|
$ul.toggleHide();
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
initCore();
|
initCore();
|
||||||
if ($('#user-profile-setting').length) {
|
if ($('#user-profile-setting').length) {
|
||||||
|
@ -368,6 +403,12 @@ $(document).ready(function () {
|
||||||
if ($('#invite-box').length) {
|
if ($('#invite-box').length) {
|
||||||
initInvite();
|
initInvite();
|
||||||
}
|
}
|
||||||
|
if ($('#team-create-form').length) {
|
||||||
|
initOrgTeamCreate();
|
||||||
|
}
|
||||||
|
if ($('#team-members-list').length) {
|
||||||
|
initTeamMembersList();
|
||||||
|
}
|
||||||
|
|
||||||
Tabs('#dashboard-sidebar-menu');
|
Tabs('#dashboard-sidebar-menu');
|
||||||
|
|
||||||
|
|
|
@ -197,3 +197,18 @@
|
||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#team-members-list {
|
||||||
|
.panel-body .search {
|
||||||
|
padding: 4px 0 10px 10px;
|
||||||
|
border-bottom: 1px solid #dddddd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#team-members-list {
|
||||||
|
li.collab {
|
||||||
|
padding-top: 10px !important;
|
||||||
|
border-bottom: 1px solid #dddddd;
|
||||||
|
&:last-child {
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -426,6 +426,7 @@ border-top-right-radius: .25em;
|
||||||
.repo-setting-zone {
|
.repo-setting-zone {
|
||||||
padding: 30px;
|
padding: 30px;
|
||||||
}
|
}
|
||||||
|
#team-members-list,
|
||||||
#repo-collab-list {
|
#repo-collab-list {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
padding: 10px 0 5px 0;
|
padding: 10px 0 5px 0;
|
||||||
|
|
|
@ -82,7 +82,12 @@ func MembersAction(ctx *middleware.Context) {
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.Redirect(ctx.Org.OrgLink + "/members")
|
|
||||||
|
if ctx.Params(":action") != "leave" {
|
||||||
|
ctx.Redirect(ctx.Org.OrgLink + "/members")
|
||||||
|
} else {
|
||||||
|
ctx.Redirect("/")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Invitation(ctx *middleware.Context) {
|
func Invitation(ctx *middleware.Context) {
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
package org
|
package org
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/Unknwon/com"
|
||||||
|
|
||||||
"github.com/gogits/gogs/models"
|
"github.com/gogits/gogs/models"
|
||||||
"github.com/gogits/gogs/modules/auth"
|
"github.com/gogits/gogs/modules/auth"
|
||||||
"github.com/gogits/gogs/modules/base"
|
"github.com/gogits/gogs/modules/base"
|
||||||
|
@ -39,23 +41,71 @@ func Teams(ctx *middleware.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TeamsAction(ctx *middleware.Context) {
|
func TeamsAction(ctx *middleware.Context) {
|
||||||
|
uid := com.StrTo(ctx.Query("uid")).MustInt64()
|
||||||
|
if uid == 0 {
|
||||||
|
ctx.Redirect(ctx.Org.OrgLink + "/teams")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
page := ctx.Query("page")
|
||||||
var err error
|
var err error
|
||||||
switch ctx.Params(":action") {
|
switch ctx.Params(":action") {
|
||||||
case "join":
|
case "join":
|
||||||
|
if !ctx.Org.IsOwner {
|
||||||
|
ctx.Error(404)
|
||||||
|
return
|
||||||
|
}
|
||||||
err = ctx.Org.Team.AddMember(ctx.User.Id)
|
err = ctx.Org.Team.AddMember(ctx.User.Id)
|
||||||
case "leave":
|
case "leave":
|
||||||
err = ctx.Org.Team.RemoveMember(ctx.User.Id)
|
err = ctx.Org.Team.RemoveMember(ctx.User.Id)
|
||||||
|
case "remove":
|
||||||
|
if !ctx.Org.IsOwner {
|
||||||
|
ctx.Error(404)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = ctx.Org.Team.RemoveMember(uid)
|
||||||
|
page = "team"
|
||||||
|
case "add":
|
||||||
|
if !ctx.Org.IsOwner {
|
||||||
|
ctx.Error(404)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
uname := ctx.Query("uname")
|
||||||
|
var u *models.User
|
||||||
|
u, err = models.GetUserByName(uname)
|
||||||
|
if err != nil {
|
||||||
|
if err == models.ErrUserNotExist {
|
||||||
|
ctx.Flash.Error(ctx.Tr("form.user_not_exist"))
|
||||||
|
ctx.Redirect(ctx.Org.OrgLink + "/teams/" + ctx.Org.Team.LowerName)
|
||||||
|
} else {
|
||||||
|
ctx.Handle(500, " GetUserByName", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ctx.Org.Team.AddMember(u.Id)
|
||||||
|
page = "team"
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(4, "Action(%s): %v", ctx.Params(":action"), err)
|
if err == models.ErrLastOrgOwner {
|
||||||
ctx.JSON(200, map[string]interface{}{
|
ctx.Flash.Error(ctx.Tr("form.last_org_owner"))
|
||||||
"ok": false,
|
} else {
|
||||||
"err": err.Error(),
|
log.Error(4, "Action(%s): %v", ctx.Params(":action"), err)
|
||||||
})
|
ctx.JSON(200, map[string]interface{}{
|
||||||
return
|
"ok": false,
|
||||||
|
"err": err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch page {
|
||||||
|
case "team":
|
||||||
|
ctx.Redirect(ctx.Org.OrgLink + "/teams/" + ctx.Org.Team.LowerName)
|
||||||
|
default:
|
||||||
|
ctx.Redirect(ctx.Org.OrgLink + "/teams")
|
||||||
}
|
}
|
||||||
ctx.Redirect(ctx.Org.OrgLink + "/teams")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTeam(ctx *middleware.Context) {
|
func NewTeam(ctx *middleware.Context) {
|
||||||
|
@ -116,13 +166,76 @@ func NewTeamPost(ctx *middleware.Context, form auth.CreateTeamForm) {
|
||||||
ctx.Redirect(ctx.Org.OrgLink + "/teams/" + t.LowerName)
|
ctx.Redirect(ctx.Org.OrgLink + "/teams/" + t.LowerName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func EditTeam(ctx *middleware.Context) {
|
func TeamMembers(ctx *middleware.Context) {
|
||||||
ctx.Data["Title"] = "Organization " + ctx.Params(":org") + " Edit Team"
|
|
||||||
ctx.HTML(200, "org/edit_team")
|
|
||||||
}
|
|
||||||
|
|
||||||
func SingleTeam(ctx *middleware.Context) {
|
|
||||||
ctx.Data["Title"] = ctx.Org.Team.Name
|
ctx.Data["Title"] = ctx.Org.Team.Name
|
||||||
ctx.Data["PageIsOrgTeams"] = true
|
ctx.Data["PageIsOrgTeams"] = true
|
||||||
|
if err := ctx.Org.Team.GetMembers(); err != nil {
|
||||||
|
ctx.Handle(500, "GetMembers", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
ctx.HTML(200, TEAM_MEMBERS)
|
ctx.HTML(200, TEAM_MEMBERS)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func EditTeam(ctx *middleware.Context) {
|
||||||
|
ctx.Data["Title"] = ctx.Org.Organization.FullName
|
||||||
|
ctx.Data["PageIsOrgTeams"] = true
|
||||||
|
ctx.Data["team_name"] = ctx.Org.Team.Name
|
||||||
|
ctx.Data["desc"] = ctx.Org.Team.Description
|
||||||
|
ctx.HTML(200, TEAM_NEW)
|
||||||
|
}
|
||||||
|
|
||||||
|
func EditTeamPost(ctx *middleware.Context, form auth.CreateTeamForm) {
|
||||||
|
t := ctx.Org.Team
|
||||||
|
ctx.Data["Title"] = ctx.Org.Organization.FullName
|
||||||
|
ctx.Data["PageIsOrgTeams"] = true
|
||||||
|
ctx.Data["team_name"] = t.Name
|
||||||
|
ctx.Data["desc"] = t.Description
|
||||||
|
|
||||||
|
if ctx.HasError() {
|
||||||
|
ctx.HTML(200, TEAM_NEW)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
isAuthChanged := false
|
||||||
|
if !t.IsOwnerTeam() {
|
||||||
|
// Validate permission level.
|
||||||
|
var auth models.AuthorizeType
|
||||||
|
switch form.Permission {
|
||||||
|
case "read":
|
||||||
|
auth = models.ORG_READABLE
|
||||||
|
case "write":
|
||||||
|
auth = models.ORG_WRITABLE
|
||||||
|
case "admin":
|
||||||
|
auth = models.ORG_ADMIN
|
||||||
|
default:
|
||||||
|
ctx.Error(401)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Name = form.TeamName
|
||||||
|
if t.Authorize != auth {
|
||||||
|
isAuthChanged = true
|
||||||
|
t.Authorize = auth
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.Description = form.Description
|
||||||
|
if err := models.UpdateTeam(t, isAuthChanged); err != nil {
|
||||||
|
if err == models.ErrTeamNameIllegal {
|
||||||
|
ctx.Data["Err_TeamName"] = true
|
||||||
|
ctx.RenderWithErr(ctx.Tr("form.illegal_team_name"), TEAM_NEW, &form)
|
||||||
|
} else {
|
||||||
|
ctx.Handle(500, "UpdateTeam", err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Redirect(ctx.Org.OrgLink + "/teams/" + t.LowerName)
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteTeam(ctx *middleware.Context) {
|
||||||
|
if err := models.DeleteTeam(ctx.Org.Team); err != nil {
|
||||||
|
ctx.Handle(500, "DeleteTeam", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Flash.Success(ctx.Tr("org.teams.delete_team_success"))
|
||||||
|
ctx.Redirect(ctx.Org.OrgLink + "/teams")
|
||||||
|
}
|
||||||
|
|
|
@ -56,7 +56,12 @@ func SettingsPost(ctx *middleware.Context, form auth.RepoSettingForm) {
|
||||||
ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), SETTINGS_OPTIONS, nil)
|
ctx.RenderWithErr(ctx.Tr("form.repo_name_been_taken"), SETTINGS_OPTIONS, nil)
|
||||||
return
|
return
|
||||||
} else if err = models.ChangeRepositoryName(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name, newRepoName); err != nil {
|
} else if err = models.ChangeRepositoryName(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name, newRepoName); err != nil {
|
||||||
ctx.Handle(500, "ChangeRepositoryName", err)
|
if err == models.ErrRepoNameIllegal {
|
||||||
|
ctx.Data["Err_RepoName"] = true
|
||||||
|
ctx.RenderWithErr(ctx.Tr("form.illegal_repo_name"), SETTINGS_OPTIONS, nil)
|
||||||
|
} else {
|
||||||
|
ctx.Handle(500, "ChangeRepositoryName", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Trace("Repository name changed: %s/%s -> %s", ctx.Repo.Owner.Name, ctx.Repo.Repository.Name, newRepoName)
|
log.Trace("Repository name changed: %s/%s -> %s", ctx.Repo.Owner.Name, ctx.Repo.Repository.Name, newRepoName)
|
||||||
|
@ -185,9 +190,24 @@ func SettingsCollaboration(ctx *middleware.Context) {
|
||||||
// Delete collaborator.
|
// Delete collaborator.
|
||||||
remove := strings.ToLower(ctx.Query("remove"))
|
remove := strings.ToLower(ctx.Query("remove"))
|
||||||
if len(remove) > 0 && remove != ctx.Repo.Owner.LowerName {
|
if len(remove) > 0 && remove != ctx.Repo.Owner.LowerName {
|
||||||
if err := models.DeleteAccess(&models.Access{UserName: remove, RepoName: repoLink}); err != nil {
|
needDelete := true
|
||||||
ctx.Handle(500, "DeleteAccess", err)
|
if ctx.User.IsOrganization() {
|
||||||
return
|
// Check if user belongs to a team that has access to this repository.
|
||||||
|
auth, err := models.GetHighestAuthorize(ctx.Repo.Owner.Id, ctx.User.Id, 0, ctx.Repo.Repository.Id)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Handle(500, "GetHighestAuthorize", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if auth > 0 {
|
||||||
|
needDelete = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if needDelete {
|
||||||
|
if err := models.DeleteAccess(&models.Access{UserName: remove, RepoName: repoLink}); err != nil {
|
||||||
|
ctx.Handle(500, "DeleteAccess", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ctx.Flash.Success(ctx.Tr("repo.settings.remove_collaborator_success"))
|
ctx.Flash.Success(ctx.Tr("repo.settings.remove_collaborator_success"))
|
||||||
ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
|
ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration")
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
0.4.7.0823 Alpha
|
0.4.7.0824 Alpha
|
|
@ -18,6 +18,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
{{$isMember := .Org.IsOrgMember $.SignedUser.Id}}
|
||||||
<div id="org-home-repo-list" class="left grid-2-3">
|
<div id="org-home-repo-list" class="left grid-2-3">
|
||||||
<div class="clear">
|
<div class="clear">
|
||||||
{{if .IsOrganizationOwner}}
|
{{if .IsOrganizationOwner}}
|
||||||
|
@ -26,6 +27,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div id="org-repo-list">
|
<div id="org-repo-list">
|
||||||
{{range .Repos}}
|
{{range .Repos}}
|
||||||
|
{{if or $isMember (not .IsPrivate)}}
|
||||||
<div class="org-repo-item">
|
<div class="org-repo-item">
|
||||||
<ul class="org-repo-status right">
|
<ul class="org-repo-status right">
|
||||||
<li><i class="octicon octicon-star"></i> {{.NumStars}}</li>
|
<li><i class="octicon octicon-star"></i> {{.NumStars}}</li>
|
||||||
|
@ -35,6 +37,7 @@
|
||||||
<p class="org-repo-description">{{.Description}}</p>
|
<p class="org-repo-description">{{.Description}}</p>
|
||||||
<p class="org-repo-updated">{{$.i18n.Tr "org.repo_updated"}} {{TimeSince .Updated $.i18n.Lang}}</p>
|
<p class="org-repo-updated">{{$.i18n.Tr "org.repo_updated"}} {{TimeSince .Updated $.i18n.Lang}}</p>
|
||||||
</div>
|
</div>
|
||||||
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -42,12 +45,16 @@
|
||||||
<div class="org-sidebar">
|
<div class="org-sidebar">
|
||||||
<div class="panel panel-radius">
|
<div class="panel panel-radius">
|
||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
|
{{if $isMember}}
|
||||||
<a class="text-grey right" href="/org/{{.Org.LowerName}}/members"><strong>{{.Org.NumMembers}}</strong><span class="octicon octicon-chevron-right"></span></a>
|
<a class="text-grey right" href="/org/{{.Org.LowerName}}/members"><strong>{{.Org.NumMembers}}</strong><span class="octicon octicon-chevron-right"></span></a>
|
||||||
|
{{end}}
|
||||||
<strong>{{.i18n.Tr "org.people"}}</strong>
|
<strong>{{.i18n.Tr "org.people"}}</strong>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-body member-avatar-group">
|
<div class="panel-body member-avatar-group">
|
||||||
{{range .Members}}
|
{{range .Members}}
|
||||||
<a href="/{{.Name}}" title="{{.Name}}"><img src="{{.AvatarLink}}"></a>
|
{{if or $isMember (.IsPublicMember $.Org.Id)}}
|
||||||
|
<a href="/{{.Name}}" title="{{.Name}}"><img src="{{.AvatarLink}}"></a>
|
||||||
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{if .IsOrganizationOwner}}
|
{{if .IsOrganizationOwner}}
|
||||||
|
@ -56,6 +63,7 @@
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
{{if $isMember}}
|
||||||
<br>
|
<br>
|
||||||
<div class="panel panel-radius">
|
<div class="panel panel-radius">
|
||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
|
@ -76,9 +84,9 @@
|
||||||
<div class="panel-footer">
|
<div class="panel-footer">
|
||||||
<a class="btn btn-medium btn-blue btn-link btn-radius" href="/org/{{$.Org.LowerName}}/teams/new">{{.i18n.Tr "org.create_new_team"}}</a>
|
<a class="btn btn-medium btn-blue btn-link btn-radius" href="/org/{{$.Org.LowerName}}/teams/new">{{.i18n.Tr "org.create_new_team"}}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
{{template "ng/base/alert" .}}
|
{{template "ng/base/alert" .}}
|
||||||
</div>
|
</div>
|
||||||
<div class="org-toolbar clear">
|
<div class="org-toolbar clear">
|
||||||
{{if .IsAdminTeam}}
|
{{if .IsOrganizationOwner}}
|
||||||
<a class="btn btn-green btn-large btn-link btn-radius right" href="{{.OrgLink}}/invitations/new"><i class="octicon octicon-repo-create"></i> {{.i18n.Tr "org.invite_someone"}}</a>
|
<a class="btn btn-green btn-large btn-link btn-radius right" href="{{.OrgLink}}/invitations/new"><i class="octicon octicon-repo-create"></i> {{.i18n.Tr "org.invite_someone"}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
{{template "ng/base/header" .}}
|
{{template "ng/base/header" .}}
|
||||||
{{template "org/base/header" .}}
|
{{template "org/base/header" .}}
|
||||||
<div id="setting-wrapper" class="main-wrapper">
|
<div id="setting-wrapper" class="main-wrapper">
|
||||||
<div id="org-setting" class="container clear">
|
<div id="team-members-list" class="container clear">
|
||||||
|
{{template "ng/base/alert" .}}
|
||||||
{{template "org/team/sidebar" .}}
|
{{template "org/team/sidebar" .}}
|
||||||
<div class="grid-2-3 left">
|
<div class="grid-2-3 left">
|
||||||
<div class="setting-content">
|
<div class="setting-content">
|
||||||
|
@ -10,6 +11,32 @@
|
||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
{{.i18n.Tr "org.teams.members"}}
|
{{.i18n.Tr "org.teams.members"}}
|
||||||
</div>
|
</div>
|
||||||
|
<ul class="panel-body setting-list" id="team-members-list">
|
||||||
|
{{if .IsOrganizationOwner}}
|
||||||
|
<li class="search">
|
||||||
|
<form class="form form-align" action="{{$.OrgLink}}/teams/{{$.Team.LowerName}}/action/add" id="repo-collab-form">
|
||||||
|
{{.CsrfTokenHtml}}
|
||||||
|
<input type="hidden" name="uid" value="{{.SignedUser.Id}}">
|
||||||
|
<input class="ipt ipt-large ipt-radius" id="org-team-members-add" name="uname" autocomplete="off" required />
|
||||||
|
<button class="btn btn-blue btn-large btn-radius">{{.i18n.Tr "org.teams.add_team_member"}}</button>
|
||||||
|
<div class="repo-user-list-block">
|
||||||
|
<ul class="menu-down-show menu-vertical menu-radius switching-list user-list" id="org-team-members-list"></ul>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
{{range .Team.Members}}
|
||||||
|
<li class="collab">
|
||||||
|
{{if $.IsOrganizationOwner}}
|
||||||
|
<a class="btn btn-small btn-red btn-radius right" href="{{$.OrgLink}}/teams/{{$.Team.LowerName}}/action/remove?uid={{.Id}}">{{$.i18n.Tr "org.members.remove"}}</a>
|
||||||
|
{{end}}
|
||||||
|
<a class="member" href="/{{.Name}}">
|
||||||
|
<img alt="{{.Name}}" class="pull-left avatar" src="{{.AvatarLink}}">
|
||||||
|
<strong>{{.FullName}}</strong> ({{.Name}})
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{{end}}
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,16 +2,21 @@
|
||||||
{{template "ng/base/header" .}}
|
{{template "ng/base/header" .}}
|
||||||
{{template "org/base/header" .}}
|
{{template "org/base/header" .}}
|
||||||
<div id="repo-wrapper">
|
<div id="repo-wrapper">
|
||||||
<form id="team-create-form" class="form form-align panel panel-radius" action="{{.OrgLink}}/teams/new" method="post">
|
<form id="team-create-form" class="form form-align panel panel-radius" action="{{if .PageIsOrgTeamsNew}}{{.OrgLink}}/teams/new{{else}}{{.OrgLink}}/teams/{{.Team.LowerName}}/edit{{end}}" data-delete-url="{{.OrgLink}}/teams/{{.Team.LowerName}}/delete" method="post">
|
||||||
{{.CsrfTokenHtml}}
|
{{.CsrfTokenHtml}}
|
||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<h2>{{.i18n.Tr "org.create_new_team"}}</h2>
|
<h2>
|
||||||
|
{{if .PageIsOrgTeamsNew}}{{.i18n.Tr "org.create_new_team"}}{{else}}{{.i18n.Tr "org.teams.settings"}}{{end}}
|
||||||
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="panel-content">
|
<div class="panel-content">
|
||||||
{{template "ng/base/alert" .}}
|
{{template "ng/base/alert" .}}
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="req" for="team-name">{{.i18n.Tr "org.team_name"}}</label>
|
<label class="req" for="team-name">{{.i18n.Tr "org.team_name"}}</label>
|
||||||
<input class="ipt ipt-large ipt-radius {{if .Err_TeamName}}ipt-error{{end}}" id="team-name" name="team_name" value="{{.team_name}}" required />
|
{{if eq .Team.LowerName "owners"}}
|
||||||
|
<input type="hidden" name="team_name" value="{{.team_name}}">
|
||||||
|
{{end}}
|
||||||
|
<input class="ipt ipt-large ipt-radius {{if .Err_TeamName}}ipt-error{{end}}" id="team-name" name="team_name" value="{{.team_name}}" required {{if eq .Team.LowerName "owners"}}disabled{{end}} />
|
||||||
<span class="form-label"></span>
|
<span class="form-label"></span>
|
||||||
<span class="help">{{.i18n.Tr "org.team_name_helper"}}</span>
|
<span class="help">{{.i18n.Tr "org.team_name_helper"}}</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -21,6 +26,7 @@
|
||||||
<span class="form-label"></span>
|
<span class="form-label"></span>
|
||||||
<span class="help">{{.i18n.Tr "org.team_desc_helper"}}</span>
|
<span class="help">{{.i18n.Tr "org.team_desc_helper"}}</span>
|
||||||
</div>
|
</div>
|
||||||
|
{{if not (eq .Team.LowerName "owners")}}
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<h4 class="text-center">{{.i18n.Tr "org.team_permission_desc"}}</h4>
|
<h4 class="text-center">{{.i18n.Tr "org.team_permission_desc"}}</h4>
|
||||||
<label></label>
|
<label></label>
|
||||||
|
@ -37,10 +43,19 @@
|
||||||
<p class="text-grey note">{{.i18n.Tr "org.teams.admin_access_helper"}}</p>
|
<p class="text-grey note">{{.i18n.Tr "org.teams.admin_access_helper"}}</p>
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
|
{{end}}
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label></label>
|
<label></label>
|
||||||
<button class="btn btn-large btn-blue btn-radius">{{.i18n.Tr "org.create_new_team"}}</button>
|
{{if .PageIsOrgTeamsNew}}
|
||||||
<a class="btn btn-small btn-gray btn-radius" id="repo-create-cancel" href="{{.OrgLink}}/teams"><strong>{{.i18n.Tr "cancel"}}</strong></a>
|
<button class="btn btn-large btn-blue btn-radius">{{.i18n.Tr "org.create_new_team"}}</button>
|
||||||
|
<a class="btn btn-small btn-gray btn-radius" id="repo-create-cancel" href="{{.OrgLink}}/teams"><strong>{{.i18n.Tr "cancel"}}</strong></a>
|
||||||
|
{{else}}
|
||||||
|
<button class="btn btn-large btn-green btn-radius">{{.i18n.Tr "org.teams.update_settings"}}</button>
|
||||||
|
{{if not (eq .Team.LowerName "owners")}}
|
||||||
|
|
||||||
|
<button class="btn btn-large btn-red btn-radius" id="org-team-delete">{{.i18n.Tr "org.teams.delete_team"}}</button>
|
||||||
|
{{end}}
|
||||||
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<div class="grid-1-3 panel panel-radius left" id="org-team-card">
|
<div class="grid-1-3 panel panel-radius left" id="org-team-card">
|
||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
{{if .Team.IsMember $.SignedUser.Id}}
|
{{if .Team.IsMember $.SignedUser.Id}}
|
||||||
<a class="btn btn-small btn-red btn-header btn-radius right" href="{{.OrgLink}}/teams/{{.Team.LowerName}}/action/leave?page=team">{{$.i18n.Tr "org.teams.leave"}}</a>
|
<a class="btn btn-small btn-red btn-header btn-radius right" href="{{.OrgLink}}/teams/{{.Team.LowerName}}/action/leave?uid={{$.SignedUser.Id}}&page=team">{{$.i18n.Tr "org.teams.leave"}}</a>
|
||||||
{{else}}
|
{{else if .IsOrganizationOwner}}
|
||||||
<a class="btn btn-small btn-blue btn-header btn-radius right" href="{{.OrgLink}}/teams/{{.Team.LowerName}}/action/join?page=team">{{$.i18n.Tr "org.teams.join"}}</a>
|
<a class="btn btn-small btn-blue btn-header btn-radius right" href="{{.OrgLink}}/teams/{{.Team.LowerName}}/action/join?uid={{$.SignedUser.Id}}&page=team">{{$.i18n.Tr "org.teams.join"}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
<strong>{{.Team.Name}}</strong>
|
<strong>{{.Team.Name}}</strong>
|
||||||
</div>
|
</div>
|
||||||
|
@ -11,16 +11,24 @@
|
||||||
<p class="desc">{{if .Team.Description}}{{.Team.Description}}{{else}}{{.i18n.Tr "org.teams.no_desc"}}{{end}}</p>
|
<p class="desc">{{if .Team.Description}}{{.Team.Description}}{{else}}{{.i18n.Tr "org.teams.no_desc"}}{{end}}</p>
|
||||||
<hr>
|
<hr>
|
||||||
<div class="team-stats">
|
<div class="team-stats">
|
||||||
<a class="text-black"><strong>{{.Team.NumMembers}}</strong> {{$.i18n.Tr "org.lower_members"}}</a> ·
|
<a class="text-black" href="{{.OrgLink}}/teams/{{.Team.LowerName}}"><strong>{{.Team.NumMembers}}</strong> {{$.i18n.Tr "org.lower_members"}}</a> ·
|
||||||
<a class="text-black"><strong>{{.Team.NumRepos}}</strong> {{$.i18n.Tr "org.lower_repositories"}}</a>
|
<a class="text-black" href="{{.OrgLink}}/teams/{{.Team.LowerName}}/repositories"><strong>{{.Team.NumRepos}}</strong> {{$.i18n.Tr "org.lower_repositories"}}</a>
|
||||||
</div>
|
</div>
|
||||||
<p class="desc">
|
<p class="desc">
|
||||||
{{if eq .Team.LowerName "owners"}}
|
{{if eq .Team.LowerName "owners"}}
|
||||||
{{.i18n.Tr "org.teams.owners_permission_desc" | Str2html}}
|
{{.i18n.Tr "org.teams.owners_permission_desc" | Str2html}}
|
||||||
|
{{else if (eq .Team.Authorize 1)}}
|
||||||
|
{{.i18n.Tr "org.teams.read_permission_desc" | Str2html}}
|
||||||
|
{{else if (eq .Team.Authorize 2)}}
|
||||||
|
{{.i18n.Tr "org.teams.write_permission_desc" | Str2html}}
|
||||||
|
{{else if (eq .Team.Authorize 3)}}
|
||||||
|
{{.i18n.Tr "org.teams.admin_permission_desc" | Str2html}}
|
||||||
{{end}}
|
{{end}}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
{{if .IsOrganizationOwner}}
|
||||||
<div class="panel-footer">
|
<div class="panel-footer">
|
||||||
<a class="btn btn-medium btn-green btn-link btn-radius" href="{{.OrgLink}}/teams/{{.Team.LowerName}}/edit"><span class="octicon octicon-gear"></span> {{$.i18n.Tr "org.teams.settings"}}</a>
|
<a class="btn btn-medium btn-green btn-link btn-radius" href="{{.OrgLink}}/teams/{{.Team.LowerName}}/edit"><span class="octicon octicon-gear"></span> {{$.i18n.Tr "org.teams.settings"}}</a>
|
||||||
</div>
|
</div>
|
||||||
|
{{end}}
|
||||||
</div>
|
</div>
|
|
@ -6,7 +6,7 @@
|
||||||
{{template "ng/base/alert" .}}
|
{{template "ng/base/alert" .}}
|
||||||
</div>
|
</div>
|
||||||
<div class="org-toolbar clear">
|
<div class="org-toolbar clear">
|
||||||
{{if .IsAdminTeam}}
|
{{if .IsOrganizationOwner}}
|
||||||
<a class="btn btn-green btn-large btn-link btn-radius right" href="{{.OrgLink}}/teams/new"><i class="octicon octicon-repo-create"></i> {{.i18n.Tr "org.create_new_team"}}</a>
|
<a class="btn btn-green btn-large btn-link btn-radius right" href="{{.OrgLink}}/teams/new"><i class="octicon octicon-repo-create"></i> {{.i18n.Tr "org.create_new_team"}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
@ -16,9 +16,9 @@
|
||||||
<div class="panel panel-radius">
|
<div class="panel panel-radius">
|
||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
{{if .IsMember $.SignedUser.Id}}
|
{{if .IsMember $.SignedUser.Id}}
|
||||||
<a class="btn btn-small btn-red btn-header btn-radius right" href="{{$.OrgLink}}/teams/{{.LowerName}}/action/leave">{{$.i18n.Tr "org.teams.leave"}}</a>
|
<a class="btn btn-small btn-red btn-header btn-radius right" href="{{$.OrgLink}}/teams/{{.LowerName}}/action/leave?uid={{$.SignedUser.Id}}">{{$.i18n.Tr "org.teams.leave"}}</a>
|
||||||
{{else}}
|
{{else if $.IsOrganizationOwner}}
|
||||||
<a class="btn btn-small btn-blue btn-header btn-radius right" href="{{$.OrgLink}}/teams/{{.LowerName}}/action/join">{{$.i18n.Tr "org.teams.join"}}</a>
|
<a class="btn btn-small btn-blue btn-header btn-radius right" href="{{$.OrgLink}}/teams/{{.LowerName}}/action/join?uid={{$.SignedUser.Id}}">{{$.i18n.Tr "org.teams.join"}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
<a class="text-black" href="{{$.OrgLink}}/teams/{{.LowerName}}"><strong>{{.Name}}</strong></a>
|
<a class="text-black" href="{{$.OrgLink}}/teams/{{.LowerName}}"><strong>{{.Name}}</strong></a>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue