mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 16:40:24 +08:00 
			
		
		
		
	Finsih add/remove repo in organization
This commit is contained in:
		@@ -141,7 +141,7 @@ func runWeb(*cli.Context) {
 | 
			
		||||
			r.Get("/users/search", v1.SearchUsers)
 | 
			
		||||
 | 
			
		||||
			// Repositories.
 | 
			
		||||
			r.Get("/orgs/:org/repos/search", v1.SearchOrgRepositoreis)
 | 
			
		||||
			r.Get("/repos/search", v1.SearchRepos)
 | 
			
		||||
 | 
			
		||||
			r.Any("/*", func(ctx *middleware.Context) {
 | 
			
		||||
				ctx.JSON(404, &base.ApiJsonErr{"Not Found", v1.DOC_URL})
 | 
			
		||||
@@ -236,7 +236,9 @@ func runWeb(*cli.Context) {
 | 
			
		||||
 | 
			
		||||
			r.Get("/teams", org.Teams)
 | 
			
		||||
			r.Get("/teams/:team", org.TeamMembers)
 | 
			
		||||
			r.Get("/teams/:team/repositories", org.TeamRepositories)
 | 
			
		||||
			r.Get("/teams/:team/action/:action", org.TeamsAction)
 | 
			
		||||
			r.Get("/teams/:team/action/repo/:action", org.TeamsRepoAction)
 | 
			
		||||
		}, middleware.OrgAssignment(true, true))
 | 
			
		||||
 | 
			
		||||
		m.Group("/:org", func(r *macaron.Router) {
 | 
			
		||||
 
 | 
			
		||||
@@ -290,6 +290,9 @@ 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.
 | 
			
		||||
teams.repositories = Team Repositories
 | 
			
		||||
teams.add_team_repository = Add Team Repository
 | 
			
		||||
teams.remove_repo = Remove
 | 
			
		||||
 | 
			
		||||
[action]
 | 
			
		||||
create_repo = created repository <a href="/%s">%s</a>
 | 
			
		||||
 
 | 
			
		||||
@@ -290,6 +290,9 @@ teams.delete_team_success = 指定团队已经被成功删除!
 | 
			
		||||
teams.read_permission_desc = 该团队拥有对所属仓库的 <strong>读取</strong> 权限,团队成员可以进行查看和克隆等只读操作。
 | 
			
		||||
teams.write_permission_desc = 该团队拥有对所属仓库的 <strong>读取</strong> 和 <strong>写入</strong> 的权限。
 | 
			
		||||
teams.admin_permission_desc = 该团队拥有一定的 <strong>管理</strong> 权限,团队成员可以读取、克隆、推送以及添加其它仓库协作者。
 | 
			
		||||
teams.repositories = 团队仓库
 | 
			
		||||
teams.add_team_repository = 添加团队仓库
 | 
			
		||||
teams.remove_repo = 移除仓库
 | 
			
		||||
 | 
			
		||||
[action]
 | 
			
		||||
create_repo = 创建了仓库 <a href="/%s">%s</a>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										2
									
								
								gogs.go
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								gogs.go
									
									
									
									
									
								
							@@ -17,7 +17,7 @@ import (
 | 
			
		||||
	"github.com/gogits/gogs/modules/setting"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const APP_VER = "0.4.7.0825 Alpha"
 | 
			
		||||
const APP_VER = "0.4.7.0826 Alpha"
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	runtime.GOMAXPROCS(runtime.NumCPU())
 | 
			
		||||
 
 | 
			
		||||
@@ -21,10 +21,10 @@ const (
 | 
			
		||||
// Access represents the accessibility of user to repository.
 | 
			
		||||
type Access struct {
 | 
			
		||||
	Id       int64
 | 
			
		||||
	UserName string     `xorm:"unique(s)"`
 | 
			
		||||
	RepoName string     `xorm:"unique(s)"` // <user name>/<repo name>
 | 
			
		||||
	Mode     AccessType `xorm:"unique(s)"`
 | 
			
		||||
	Created  time.Time  `xorm:"created"`
 | 
			
		||||
	UserName string     `xorm:"UNIQUE(s)"`
 | 
			
		||||
	RepoName string     `xorm:"UNIQUE(s)"` // <user name>/<repo name>
 | 
			
		||||
	Mode     AccessType `xorm:"UNIQUE(s)"`
 | 
			
		||||
	Created  time.Time  `xorm:"CREATED"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddAccess adds new access record.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										230
									
								
								models/org.go
									
									
									
									
									
								
							
							
						
						
									
										230
									
								
								models/org.go
									
									
									
									
									
								
							@@ -369,6 +369,13 @@ const (
 | 
			
		||||
	ORG_ADMIN
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func AuthorizeToAccessType(auth AuthorizeType) AccessType {
 | 
			
		||||
	if auth == ORG_READABLE {
 | 
			
		||||
		return READABLE
 | 
			
		||||
	}
 | 
			
		||||
	return WRITABLE
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const OWNER_TEAM = "Owners"
 | 
			
		||||
 | 
			
		||||
// Team represents a organization team.
 | 
			
		||||
@@ -433,6 +440,142 @@ func (t *Team) RemoveMember(uid int64) error {
 | 
			
		||||
	return RemoveTeamMember(t.OrgId, t.Id, uid)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// addAccessWithAuthorize inserts or updates access with given mode.
 | 
			
		||||
func addAccessWithAuthorize(sess *xorm.Session, access *Access, mode AccessType) error {
 | 
			
		||||
	has, err := x.Get(access)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("fail to get access: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	access.Mode = mode
 | 
			
		||||
	if has {
 | 
			
		||||
		if _, err = sess.Id(access.Id).Update(access); err != nil {
 | 
			
		||||
			return fmt.Errorf("fail to update access: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		if _, err = sess.Insert(access); err != nil {
 | 
			
		||||
			return fmt.Errorf("fail to insert access: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddRepository adds new repository to team of organization.
 | 
			
		||||
func (t *Team) AddRepository(repo *Repository) (err error) {
 | 
			
		||||
	idStr := "$" + com.ToStr(repo.Id) + "|"
 | 
			
		||||
	if repo.OwnerId != t.OrgId {
 | 
			
		||||
		return errors.New("Repository not belong to organization")
 | 
			
		||||
	} else if strings.Contains(t.RepoIds, idStr) {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = repo.GetOwner(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	} else if err = t.GetMembers(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sess := x.NewSession()
 | 
			
		||||
	defer sess.Close()
 | 
			
		||||
	if err = sess.Begin(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	t.NumRepos++
 | 
			
		||||
	t.RepoIds += idStr
 | 
			
		||||
	if _, err = sess.Id(t.Id).AllCols().Update(t); err != nil {
 | 
			
		||||
		sess.Rollback()
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Give access to team members.
 | 
			
		||||
	mode := AuthorizeToAccessType(t.Authorize)
 | 
			
		||||
 | 
			
		||||
	for _, u := range t.Members {
 | 
			
		||||
		auth, err := GetHighestAuthorize(t.OrgId, u.Id, t.Id, repo.Id)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			sess.Rollback()
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		access := &Access{
 | 
			
		||||
			UserName: u.LowerName,
 | 
			
		||||
			RepoName: path.Join(repo.Owner.LowerName, repo.LowerName),
 | 
			
		||||
		}
 | 
			
		||||
		if auth == 0 {
 | 
			
		||||
			access.Mode = mode
 | 
			
		||||
			if _, err = sess.Insert(access); err != nil {
 | 
			
		||||
				sess.Rollback()
 | 
			
		||||
				return fmt.Errorf("fail to insert access: %v", err)
 | 
			
		||||
			}
 | 
			
		||||
		} else if auth < t.Authorize {
 | 
			
		||||
			if err = addAccessWithAuthorize(sess, access, mode); err != nil {
 | 
			
		||||
				sess.Rollback()
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return sess.Commit()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RemoveRepository removes repository from team of organization.
 | 
			
		||||
func (t *Team) RemoveRepository(repoId int64) error {
 | 
			
		||||
	idStr := "$" + com.ToStr(repoId) + "|"
 | 
			
		||||
	if !strings.Contains(t.RepoIds, idStr) {
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	repo, err := GetRepositoryById(repoId)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = repo.GetOwner(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	} else if err = t.GetMembers(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sess := x.NewSession()
 | 
			
		||||
	defer sess.Close()
 | 
			
		||||
	if err = sess.Begin(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	t.NumRepos--
 | 
			
		||||
	t.RepoIds = strings.Replace(t.RepoIds, idStr, "", 1)
 | 
			
		||||
	if _, err = sess.Id(t.Id).AllCols().Update(t); err != nil {
 | 
			
		||||
		sess.Rollback()
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Remove access to team members.
 | 
			
		||||
	for _, u := range t.Members {
 | 
			
		||||
		auth, err := GetHighestAuthorize(t.OrgId, u.Id, t.Id, repo.Id)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			sess.Rollback()
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		access := &Access{
 | 
			
		||||
			UserName: u.LowerName,
 | 
			
		||||
			RepoName: path.Join(repo.Owner.LowerName, repo.LowerName),
 | 
			
		||||
		}
 | 
			
		||||
		if auth == 0 {
 | 
			
		||||
			if _, err = sess.Delete(access); err != nil {
 | 
			
		||||
				sess.Rollback()
 | 
			
		||||
				return fmt.Errorf("fail to delete access: %v", err)
 | 
			
		||||
			}
 | 
			
		||||
		} else if auth < t.Authorize {
 | 
			
		||||
			if err = addAccessWithAuthorize(sess, access, AuthorizeToAccessType(auth)); err != nil {
 | 
			
		||||
				sess.Rollback()
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return sess.Commit()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewTeam creates a record of new team.
 | 
			
		||||
// It's caller's responsibility to assign organization ID.
 | 
			
		||||
func NewTeam(t *Team) error {
 | 
			
		||||
@@ -554,16 +697,10 @@ func UpdateTeam(t *Team, authChanged bool) (err error) {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		mode := READABLE
 | 
			
		||||
		if t.Authorize > ORG_READABLE {
 | 
			
		||||
			mode = WRITABLE
 | 
			
		||||
		}
 | 
			
		||||
		access := &Access{
 | 
			
		||||
			Mode: mode,
 | 
			
		||||
		}
 | 
			
		||||
		// Update access.
 | 
			
		||||
		mode := AuthorizeToAccessType(t.Authorize)
 | 
			
		||||
 | 
			
		||||
		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.
 | 
			
		||||
@@ -578,8 +715,11 @@ func UpdateTeam(t *Team, authChanged bool) (err error) {
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				access.UserName = u.LowerName
 | 
			
		||||
				if _, err = sess.Update(access); err != nil {
 | 
			
		||||
				access := &Access{
 | 
			
		||||
					UserName: u.LowerName,
 | 
			
		||||
					RepoName: path.Join(org.LowerName, repo.LowerName),
 | 
			
		||||
				}
 | 
			
		||||
				if err = addAccessWithAuthorize(sess, access, mode); err != nil {
 | 
			
		||||
					sess.Rollback()
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
@@ -617,36 +757,26 @@ func DeleteTeam(t *Team) error {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 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
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			access := &Access{
 | 
			
		||||
				UserName: u.LowerName,
 | 
			
		||||
				RepoName: path.Join(org.LowerName, repo.LowerName),
 | 
			
		||||
			}
 | 
			
		||||
			if auth == 0 {
 | 
			
		||||
				if _, err = sess.Delete(access); err != nil {
 | 
			
		||||
					sess.Rollback()
 | 
			
		||||
					return err
 | 
			
		||||
					return fmt.Errorf("fail to delete access: %v", 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 {
 | 
			
		||||
				if err = addAccessWithAuthorize(sess, access, AuthorizeToAccessType(auth)); err != nil {
 | 
			
		||||
					sess.Rollback()
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
@@ -779,15 +909,6 @@ func AddTeamMember(orgId, teamId, uid int64) error {
 | 
			
		||||
		TeamId: teamId,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mode := READABLE
 | 
			
		||||
	if t.Authorize > ORG_READABLE {
 | 
			
		||||
		mode = WRITABLE
 | 
			
		||||
	}
 | 
			
		||||
	access := &Access{
 | 
			
		||||
		UserName: u.LowerName,
 | 
			
		||||
		Mode:     mode,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if _, err = sess.Insert(tu); err != nil {
 | 
			
		||||
		sess.Rollback()
 | 
			
		||||
		return err
 | 
			
		||||
@@ -797,6 +918,7 @@ func AddTeamMember(orgId, teamId, uid int64) error {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Give access to team repositories.
 | 
			
		||||
	mode := AuthorizeToAccessType(t.Authorize)
 | 
			
		||||
	for _, repo := range t.Repos {
 | 
			
		||||
		auth, err := GetHighestAuthorize(orgId, uid, teamId, repo.Id)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
@@ -804,22 +926,24 @@ func AddTeamMember(orgId, teamId, uid int64) error {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		access.Id = 0
 | 
			
		||||
		access.RepoName = path.Join(org.LowerName, repo.LowerName)
 | 
			
		||||
		access := &Access{
 | 
			
		||||
			UserName: u.LowerName,
 | 
			
		||||
			RepoName: path.Join(org.LowerName, repo.LowerName),
 | 
			
		||||
		}
 | 
			
		||||
		// Equal 0 means given access doesn't exist.
 | 
			
		||||
		if auth == 0 {
 | 
			
		||||
			access.Mode = mode
 | 
			
		||||
			if _, err = sess.Insert(access); err != nil {
 | 
			
		||||
				sess.Rollback()
 | 
			
		||||
				return err
 | 
			
		||||
				return fmt.Errorf("fail to insert access: %v", err)
 | 
			
		||||
			}
 | 
			
		||||
		} else if auth < t.Authorize {
 | 
			
		||||
			if _, err = sess.Update(access); err != nil {
 | 
			
		||||
			if err = addAccessWithAuthorize(sess, access, mode); err != nil {
 | 
			
		||||
				sess.Rollback()
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	fmt.Println("kao")
 | 
			
		||||
 | 
			
		||||
	// We make sure it exists before.
 | 
			
		||||
	ou := new(OrgUser)
 | 
			
		||||
@@ -889,10 +1013,6 @@ func removeTeamMemberWithSess(orgId, teamId, uid int64, sess *xorm.Session) erro
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Delete access to team repositories.
 | 
			
		||||
	access := &Access{
 | 
			
		||||
		UserName: u.LowerName,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, repo := range t.Repos {
 | 
			
		||||
		auth, err := GetHighestAuthorize(orgId, uid, teamId, repo.Id)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
@@ -900,22 +1020,22 @@ func removeTeamMemberWithSess(orgId, teamId, uid int64, sess *xorm.Session) erro
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		access := &Access{
 | 
			
		||||
			UserName: u.LowerName,
 | 
			
		||||
			RepoName: path.Join(org.LowerName, repo.LowerName),
 | 
			
		||||
		}
 | 
			
		||||
		// Delete access if this is the last team user belongs to.
 | 
			
		||||
		if auth == 0 {
 | 
			
		||||
			access.RepoName = path.Join(org.LowerName, repo.LowerName)
 | 
			
		||||
			_, err = sess.Delete(access)
 | 
			
		||||
			if _, err = sess.Delete(access); err != nil {
 | 
			
		||||
				sess.Rollback()
 | 
			
		||||
				return fmt.Errorf("fail to delete access: %v", err)
 | 
			
		||||
			}
 | 
			
		||||
		} else if auth < t.Authorize {
 | 
			
		||||
			// Downgrade authorize level.
 | 
			
		||||
			mode := READABLE
 | 
			
		||||
			if auth > ORG_READABLE {
 | 
			
		||||
				mode = WRITABLE
 | 
			
		||||
			if err = addAccessWithAuthorize(sess, access, AuthorizeToAccessType(auth)); err != nil {
 | 
			
		||||
				sess.Rollback()
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
			access.Mode = mode
 | 
			
		||||
			_, err = sess.Update(access)
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			sess.Rollback()
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -519,12 +519,11 @@ func CreateRepository(u *User, name, desc, lang, license string, private, mirror
 | 
			
		||||
			sess.Rollback()
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		us, err := GetTeamMembers(u.Id, t.Id)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
		if err = t.GetMembers(); err != nil {
 | 
			
		||||
			sess.Rollback()
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		for _, u := range us {
 | 
			
		||||
		for _, u := range t.Members {
 | 
			
		||||
			access.Id = 0
 | 
			
		||||
			access.UserName = u.LowerName
 | 
			
		||||
			if _, err = sess.Insert(access); err != nil {
 | 
			
		||||
@@ -963,6 +962,37 @@ func GetCollaborators(repoName string) (us []*User, err error) {
 | 
			
		||||
	return us, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type SearchOption struct {
 | 
			
		||||
	Keyword string
 | 
			
		||||
	Uid     int64
 | 
			
		||||
	Limit   int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SearchRepositoryByName returns given number of repositories whose name contains keyword.
 | 
			
		||||
func SearchRepositoryByName(opt SearchOption) (repos []*Repository, err error) {
 | 
			
		||||
	// Prevent SQL inject.
 | 
			
		||||
	opt.Keyword = strings.TrimSpace(opt.Keyword)
 | 
			
		||||
	if len(opt.Keyword) == 0 {
 | 
			
		||||
		return repos, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	opt.Keyword = strings.Split(opt.Keyword, " ")[0]
 | 
			
		||||
	if len(opt.Keyword) == 0 {
 | 
			
		||||
		return repos, nil
 | 
			
		||||
	}
 | 
			
		||||
	opt.Keyword = strings.ToLower(opt.Keyword)
 | 
			
		||||
 | 
			
		||||
	repos = make([]*Repository, 0, opt.Limit)
 | 
			
		||||
 | 
			
		||||
	// Append conditions.
 | 
			
		||||
	sess := x.Limit(opt.Limit)
 | 
			
		||||
	if opt.Uid > 0 {
 | 
			
		||||
		sess.Where("owner_id=?", opt.Uid)
 | 
			
		||||
	}
 | 
			
		||||
	sess.And("lower_name like '%" + opt.Keyword + "%'").Find(&repos)
 | 
			
		||||
	return repos, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Watch is connection request for receiving repository notifycation.
 | 
			
		||||
type Watch struct {
 | 
			
		||||
	Id     int64
 | 
			
		||||
 
 | 
			
		||||
@@ -521,21 +521,21 @@ func GetUserByEmail(email string) (*User, error) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SearchUserByName returns given number of users whose name contains keyword.
 | 
			
		||||
func SearchUserByName(key string, limit int) (us []*User, err error) {
 | 
			
		||||
func SearchUserByName(opt SearchOption) (us []*User, err error) {
 | 
			
		||||
	// Prevent SQL inject.
 | 
			
		||||
	key = strings.TrimSpace(key)
 | 
			
		||||
	if len(key) == 0 {
 | 
			
		||||
	opt.Keyword = strings.TrimSpace(opt.Keyword)
 | 
			
		||||
	if len(opt.Keyword) == 0 {
 | 
			
		||||
		return us, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	key = strings.Split(key, " ")[0]
 | 
			
		||||
	if len(key) == 0 {
 | 
			
		||||
	opt.Keyword = strings.Split(opt.Keyword, " ")[0]
 | 
			
		||||
	if len(opt.Keyword) == 0 {
 | 
			
		||||
		return us, nil
 | 
			
		||||
	}
 | 
			
		||||
	key = strings.ToLower(key)
 | 
			
		||||
	opt.Keyword = strings.ToLower(opt.Keyword)
 | 
			
		||||
 | 
			
		||||
	us = make([]*User, 0, limit)
 | 
			
		||||
	err = x.Limit(limit).Where("type=0").And("lower_name like '%" + key + "%'").Find(&us)
 | 
			
		||||
	us = make([]*User, 0, opt.Limit)
 | 
			
		||||
	err = x.Limit(opt.Limit).Where("type=0").And("lower_name like '%" + opt.Keyword + "%'").Find(&us)
 | 
			
		||||
	return us, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1298,32 +1298,38 @@ The register and sign-in page style
 | 
			
		||||
.repo-setting-zone {
 | 
			
		||||
  padding: 30px;
 | 
			
		||||
}
 | 
			
		||||
#team-repositories-list,
 | 
			
		||||
#team-members-list,
 | 
			
		||||
#repo-collab-list {
 | 
			
		||||
  list-style: none;
 | 
			
		||||
  padding: 10px 0 5px 0;
 | 
			
		||||
}
 | 
			
		||||
#team-repositories-list li.collab,
 | 
			
		||||
#team-members-list li.collab,
 | 
			
		||||
#repo-collab-list li.collab {
 | 
			
		||||
  clear: both;
 | 
			
		||||
  height: 50px;
 | 
			
		||||
  padding: 0 15px 0 15px;
 | 
			
		||||
}
 | 
			
		||||
#team-repositories-list a.member,
 | 
			
		||||
#team-members-list a.member,
 | 
			
		||||
#repo-collab-list a.member {
 | 
			
		||||
  color: #444;
 | 
			
		||||
  height: 50px;
 | 
			
		||||
  line-height: 50px;
 | 
			
		||||
}
 | 
			
		||||
#team-repositories-list a.member:hover,
 | 
			
		||||
#team-members-list a.member:hover,
 | 
			
		||||
#repo-collab-list a.member:hover {
 | 
			
		||||
  color: #4183C4;
 | 
			
		||||
}
 | 
			
		||||
#team-repositories-list .avatar,
 | 
			
		||||
#team-members-list .avatar,
 | 
			
		||||
#repo-collab-list .avatar {
 | 
			
		||||
  margin-right: 1em;
 | 
			
		||||
  width: 40px;
 | 
			
		||||
}
 | 
			
		||||
#team-repositories-list .remove-collab,
 | 
			
		||||
#team-members-list .remove-collab,
 | 
			
		||||
#repo-collab-list .remove-collab {
 | 
			
		||||
  color: #DD4B39;
 | 
			
		||||
@@ -1877,14 +1883,26 @@ textarea#issue-add-content {
 | 
			
		||||
#org-team-card .panel-footer {
 | 
			
		||||
  padding: 10px 20px;
 | 
			
		||||
}
 | 
			
		||||
#team-repositories-list .panel-body .search,
 | 
			
		||||
#team-members-list .panel-body .search {
 | 
			
		||||
  padding: 4px 0 10px 10px;
 | 
			
		||||
  border-bottom: 1px solid #dddddd;
 | 
			
		||||
}
 | 
			
		||||
#team-repositories-list li.collab,
 | 
			
		||||
#team-members-list li.collab {
 | 
			
		||||
  padding-top: 10px !important;
 | 
			
		||||
  border-bottom: 1px solid #dddddd;
 | 
			
		||||
}
 | 
			
		||||
#team-members-list li.collab:last-child {
 | 
			
		||||
  border-bottom: 0;
 | 
			
		||||
#team-repositories-list li:last-child,
 | 
			
		||||
#team-members-list li:last-child {
 | 
			
		||||
  border-bottom: 0 !important;
 | 
			
		||||
}
 | 
			
		||||
#team-repositories-list li a .octicon {
 | 
			
		||||
  color: #888;
 | 
			
		||||
}
 | 
			
		||||
#team-repositories-list li .member {
 | 
			
		||||
  color: #428bca;
 | 
			
		||||
  font-size: 14px;
 | 
			
		||||
  height: 40px;
 | 
			
		||||
  line-height: 40px;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -218,6 +218,26 @@ var Gogs = {};
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Search repositories by keyword.
 | 
			
		||||
    Gogs.searchRepos = function (val, $target, $param) {
 | 
			
		||||
        $.ajax({
 | 
			
		||||
            url: '/api/v1/repos/search?q=' + val + '&' + $param,
 | 
			
		||||
            dataType: "json",
 | 
			
		||||
            success: function (json) {
 | 
			
		||||
                if (json.ok && json.data.length) {
 | 
			
		||||
                    var html = '';
 | 
			
		||||
                    $.each(json.data, function (i, item) {
 | 
			
		||||
                        html += '<li><a><span class="octicon octicon-repo"></span> ' + item.repolink + '</a></li>';
 | 
			
		||||
                    });
 | 
			
		||||
                    $target.html(html);
 | 
			
		||||
                    $target.toggleShow();
 | 
			
		||||
                } else {
 | 
			
		||||
                    $target.toggleHide();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
})(jQuery);
 | 
			
		||||
 | 
			
		||||
function initCore() {
 | 
			
		||||
@@ -358,7 +378,7 @@ function initOrgTeamCreate() {
 | 
			
		||||
            e.preventDefault();
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        var $form = $('#team-create-form')
 | 
			
		||||
        var $form = $('#team-create-form');
 | 
			
		||||
        $form.attr('action', $form.data('delete-url'));
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
@@ -383,7 +403,28 @@ function initTeamMembersList() {
 | 
			
		||||
        $('#org-team-members-add').val($(this).text());
 | 
			
		||||
        $ul.toggleHide();
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function initTeamRepositoriesList() {
 | 
			
		||||
    // Add team repository.
 | 
			
		||||
    var $ul = $('#org-team-repositories-list');
 | 
			
		||||
    $('#org-team-repositories-add').on('keyup', function () {
 | 
			
		||||
        var $this = $(this);
 | 
			
		||||
        if (!$this.val()) {
 | 
			
		||||
            $ul.toggleHide();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        Gogs.searchRepos($this.val(), $ul, 'uid=' + $this.data('uid'));
 | 
			
		||||
    }).on('focus', function () {
 | 
			
		||||
        if (!$(this).val()) {
 | 
			
		||||
            $ul.toggleHide();
 | 
			
		||||
        } else {
 | 
			
		||||
            $ul.toggleShow();
 | 
			
		||||
        }
 | 
			
		||||
    }).next().next().find('ul').on("click", 'li', function () {
 | 
			
		||||
        $('#org-team-repositories-add').val($(this).text());
 | 
			
		||||
        $ul.toggleHide();
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
$(document).ready(function () {
 | 
			
		||||
@@ -409,6 +450,9 @@ $(document).ready(function () {
 | 
			
		||||
    if ($('#team-members-list').length) {
 | 
			
		||||
        initTeamMembersList();
 | 
			
		||||
    }
 | 
			
		||||
    if ($('#team-repositories-list').length) {
 | 
			
		||||
        initTeamRepositoriesList();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Tabs('#dashboard-sidebar-menu');
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,4 @@
 | 
			
		||||
@import "../ui/var";
 | 
			
		||||
.org-header-alert .alert {
 | 
			
		||||
	margin-top: 10px;
 | 
			
		||||
}
 | 
			
		||||
@@ -197,18 +198,32 @@
 | 
			
		||||
		padding: 10px 20px;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
#team-repositories-list,
 | 
			
		||||
#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;
 | 
			
		||||
	li {
 | 
			
		||||
		&.collab {
 | 
			
		||||
			padding-top: 10px !important;
 | 
			
		||||
			border-bottom: 1px solid #dddddd;
 | 
			
		||||
		}
 | 
			
		||||
		&:last-child {
 | 
			
		||||
			border-bottom: 0;
 | 
			
		||||
			border-bottom: 0 !important;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
#team-repositories-list {
 | 
			
		||||
	li {
 | 
			
		||||
		a .octicon {
 | 
			
		||||
			color: #888;
 | 
			
		||||
		}
 | 
			
		||||
		.member {
 | 
			
		||||
			color: @linkColor;
 | 
			
		||||
			font-size: 14px;
 | 
			
		||||
			height: 40px;
 | 
			
		||||
			line-height: 40px;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -426,6 +426,7 @@ border-top-right-radius: .25em;
 | 
			
		||||
.repo-setting-zone {
 | 
			
		||||
	padding: 30px;
 | 
			
		||||
}
 | 
			
		||||
#team-repositories-list,
 | 
			
		||||
#team-members-list,
 | 
			
		||||
#repo-collab-list {
 | 
			
		||||
	list-style: none;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										57
									
								
								routers/api/v1/repos.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								routers/api/v1/repos.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
// Copyright 2014 The Gogs Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package v1
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"path"
 | 
			
		||||
 | 
			
		||||
	"github.com/Unknwon/com"
 | 
			
		||||
 | 
			
		||||
	"github.com/gogits/gogs/models"
 | 
			
		||||
	"github.com/gogits/gogs/modules/middleware"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type repo struct {
 | 
			
		||||
	RepoLink string `json:"repolink"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SearchRepos(ctx *middleware.Context) {
 | 
			
		||||
	opt := models.SearchOption{
 | 
			
		||||
		Keyword: path.Base(ctx.Query("q")),
 | 
			
		||||
		Uid:     com.StrTo(ctx.Query("uid")).MustInt64(),
 | 
			
		||||
		Limit:   com.StrTo(ctx.Query("limit")).MustInt(),
 | 
			
		||||
	}
 | 
			
		||||
	if opt.Limit == 0 {
 | 
			
		||||
		opt.Limit = 10
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	repos, err := models.SearchRepositoryByName(opt)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		ctx.JSON(500, map[string]interface{}{
 | 
			
		||||
			"ok":    false,
 | 
			
		||||
			"error": err.Error(),
 | 
			
		||||
		})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	results := make([]*repo, len(repos))
 | 
			
		||||
	for i := range repos {
 | 
			
		||||
		if err = repos[i].GetOwner(); err != nil {
 | 
			
		||||
			ctx.JSON(500, map[string]interface{}{
 | 
			
		||||
				"ok":    false,
 | 
			
		||||
				"error": err.Error(),
 | 
			
		||||
			})
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		results[i] = &repo{
 | 
			
		||||
			RepoLink: path.Join(repos[i].Owner.Name, repos[i].Name),
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx.Render.JSON(200, map[string]interface{}{
 | 
			
		||||
		"ok":   true,
 | 
			
		||||
		"data": results,
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
@@ -1,13 +0,0 @@
 | 
			
		||||
// Copyright 2014 The Gogs Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a MIT-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
package v1
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/gogits/gogs/modules/middleware"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func SearchOrgRepositoreis(ctx *middleware.Context) {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -17,21 +17,29 @@ type user struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func SearchUsers(ctx *middleware.Context) {
 | 
			
		||||
	q := ctx.Query("q")
 | 
			
		||||
	limit, err := com.StrTo(ctx.Query("limit")).Int()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		limit = 10
 | 
			
		||||
	opt := models.SearchOption{
 | 
			
		||||
		Keyword: ctx.Query("q"),
 | 
			
		||||
		Limit:   com.StrTo(ctx.Query("limit")).MustInt(),
 | 
			
		||||
	}
 | 
			
		||||
	if opt.Limit == 0 {
 | 
			
		||||
		opt.Limit = 10
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	us, err := models.SearchUserByName(q, limit)
 | 
			
		||||
	us, err := models.SearchUserByName(opt)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		ctx.JSON(500, nil)
 | 
			
		||||
		ctx.JSON(500, map[string]interface{}{
 | 
			
		||||
			"ok":    false,
 | 
			
		||||
			"error": err.Error(),
 | 
			
		||||
		})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	results := make([]*user, len(us))
 | 
			
		||||
	for i := range us {
 | 
			
		||||
		results[i] = &user{us[i].Name, us[i].AvatarLink()}
 | 
			
		||||
		results[i] = &user{
 | 
			
		||||
			UserName:   us[i].Name,
 | 
			
		||||
			AvatarLink: us[i].AvatarLink(),
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx.Render.JSON(200, map[string]interface{}{
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,8 @@
 | 
			
		||||
package org
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"path"
 | 
			
		||||
 | 
			
		||||
	"github.com/Unknwon/com"
 | 
			
		||||
 | 
			
		||||
	"github.com/gogits/gogs/models"
 | 
			
		||||
@@ -15,9 +17,10 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	TEAMS        base.TplName = "org/team/teams"
 | 
			
		||||
	TEAM_NEW     base.TplName = "org/team/new"
 | 
			
		||||
	TEAM_MEMBERS base.TplName = "org/team/members"
 | 
			
		||||
	TEAMS             base.TplName = "org/team/teams"
 | 
			
		||||
	TEAM_NEW          base.TplName = "org/team/new"
 | 
			
		||||
	TEAM_MEMBERS      base.TplName = "org/team/members"
 | 
			
		||||
	TEAM_REPOSITORIES base.TplName = "org/team/repositories"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func Teams(ctx *middleware.Context) {
 | 
			
		||||
@@ -108,6 +111,38 @@ func TeamsAction(ctx *middleware.Context) {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TeamsRepoAction(ctx *middleware.Context) {
 | 
			
		||||
	if !ctx.Org.IsOwner {
 | 
			
		||||
		ctx.Error(404)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var err error
 | 
			
		||||
	switch ctx.Params(":action") {
 | 
			
		||||
	case "add":
 | 
			
		||||
		repoName := path.Base(ctx.Query("repo-name"))
 | 
			
		||||
		var repo *models.Repository
 | 
			
		||||
		repo, err = models.GetRepositoryByName(ctx.Org.Organization.Id, repoName)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			ctx.Handle(500, "GetRepositoryByName", err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		err = ctx.Org.Team.AddRepository(repo)
 | 
			
		||||
	case "remove":
 | 
			
		||||
		err = ctx.Org.Team.RemoveRepository(com.StrTo(ctx.Query("repoid")).MustInt64())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Error(4, "Action(%s): %v", ctx.Params(":action"), err)
 | 
			
		||||
		ctx.JSON(200, map[string]interface{}{
 | 
			
		||||
			"ok":  false,
 | 
			
		||||
			"err": err.Error(),
 | 
			
		||||
		})
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	ctx.Redirect(ctx.Org.OrgLink + "/teams/" + ctx.Org.Team.LowerName + "/repositories")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewTeam(ctx *middleware.Context) {
 | 
			
		||||
	ctx.Data["Title"] = ctx.Org.Organization.FullName
 | 
			
		||||
	ctx.Data["PageIsOrgTeams"] = true
 | 
			
		||||
@@ -176,6 +211,16 @@ func TeamMembers(ctx *middleware.Context) {
 | 
			
		||||
	ctx.HTML(200, TEAM_MEMBERS)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TeamRepositories(ctx *middleware.Context) {
 | 
			
		||||
	ctx.Data["Title"] = ctx.Org.Team.Name
 | 
			
		||||
	ctx.Data["PageIsOrgTeams"] = true
 | 
			
		||||
	if err := ctx.Org.Team.GetRepositories(); err != nil {
 | 
			
		||||
		ctx.Handle(500, "GetRepositories", err)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	ctx.HTML(200, TEAM_REPOSITORIES)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func EditTeam(ctx *middleware.Context) {
 | 
			
		||||
	ctx.Data["Title"] = ctx.Org.Organization.FullName
 | 
			
		||||
	ctx.Data["PageIsOrgTeams"] = true
 | 
			
		||||
 
 | 
			
		||||
@@ -1 +1 @@
 | 
			
		||||
0.4.7.0825 Alpha
 | 
			
		||||
0.4.7.0826 Alpha
 | 
			
		||||
@@ -0,0 +1,45 @@
 | 
			
		||||
{{template "ng/base/head" .}}
 | 
			
		||||
{{template "ng/base/header" .}}
 | 
			
		||||
{{template "org/base/header" .}}
 | 
			
		||||
<div id="setting-wrapper" class="main-wrapper">
 | 
			
		||||
    <div id="team-members-list" class="container clear">
 | 
			
		||||
		{{template "ng/base/alert" .}}
 | 
			
		||||
		{{template "org/team/sidebar" .}}
 | 
			
		||||
		<div class="grid-2-3 left">
 | 
			
		||||
			<div class="setting-content">
 | 
			
		||||
				<div class="panel panel-radius">
 | 
			
		||||
					<div class="panel-header">
 | 
			
		||||
						{{.i18n.Tr "org.teams.repositories"}}
 | 
			
		||||
					</div>
 | 
			
		||||
					{{$canAddRemove := and $.IsOrganizationOwner (not (eq $.Team.LowerName "owners"))}}
 | 
			
		||||
                    <ul class="panel-body setting-list" id="team-repositories-list">
 | 
			
		||||
                    	{{if $canAddRemove}}
 | 
			
		||||
						<li class="search">
 | 
			
		||||
			                <form class="form form-align" action="{{$.OrgLink}}/teams/{{$.Team.LowerName}}/action/repo/add" id="repo-collab-form">
 | 
			
		||||
			                    {{.CsrfTokenHtml}}
 | 
			
		||||
                                <input class="ipt ipt-large ipt-radius" id="org-team-repositories-add" name="repo-name" autocomplete="off" data-uid="{{.Org.Id}}" required />
 | 
			
		||||
                                <button class="btn btn-blue btn-large btn-radius">{{.i18n.Tr "org.teams.add_team_repository"}}</button>
 | 
			
		||||
								<div class="repo-user-list-block">
 | 
			
		||||
									<ul class="menu-down-show menu-vertical menu-radius switching-list user-list" id="org-team-repositories-list"></ul>
 | 
			
		||||
								</div>
 | 
			
		||||
			                </form>
 | 
			
		||||
						</li>
 | 
			
		||||
						{{end}}
 | 
			
		||||
                		{{range .Team.Repos}}
 | 
			
		||||
                		<li class="collab">
 | 
			
		||||
                			{{if $canAddRemove}}
 | 
			
		||||
							<a class="btn btn-small btn-red btn-radius right" href="{{$.OrgLink}}/teams/{{$.Team.LowerName}}/action/repo/remove?repoid={{.Id}}">{{$.i18n.Tr "org.teams.remove_repo"}}</a>
 | 
			
		||||
							{{end}}
 | 
			
		||||
							<a class="member" href="/{{$.Org.Name}}/{{.Name}}">
 | 
			
		||||
                                <i class="octicon octicon-{{if .IsPrivate}}lock{{else if .IsFork}}repo-forked{{else if .IsMirror}}repo-clone{{else}}repo{{end}}"></i>
 | 
			
		||||
							    <strong>{{$.Org.Name}}/{{.Name}}</strong>
 | 
			
		||||
							</a>
 | 
			
		||||
                		</li>
 | 
			
		||||
                		{{end}}
 | 
			
		||||
                    </ul>
 | 
			
		||||
				</div>
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
</div>
 | 
			
		||||
{{template "ng/base/footer" .}}
 | 
			
		||||
@@ -11,8 +11,8 @@
 | 
			
		||||
    	<p class="desc">{{if .Team.Description}}{{.Team.Description}}{{else}}{{.i18n.Tr "org.teams.no_desc"}}{{end}}</p>
 | 
			
		||||
    	<hr>
 | 
			
		||||
    	<div class="team-stats">
 | 
			
		||||
    		<a class="text-black" href="{{.OrgLink}}/teams/{{.Team.LowerName}}"><strong>{{.Team.NumMembers}}</strong> {{$.i18n.Tr "org.lower_members"}}</a> ·
 | 
			
		||||
    		<a class="text-black" href="{{.OrgLink}}/teams/{{.Team.LowerName}}/repositories"><strong>{{.Team.NumRepos}}</strong> {{$.i18n.Tr "org.lower_repositories"}}</a>
 | 
			
		||||
    		<a class="text-black" href="{{.OrgLink}}/teams/{{.Team.LowerName}}"><span class="octicon octicon-person"></span> <strong>{{.Team.NumMembers}}</strong> {{$.i18n.Tr "org.lower_members"}}</a> ·
 | 
			
		||||
    		<a class="text-black" href="{{.OrgLink}}/teams/{{.Team.LowerName}}/repositories"><span class="octicon octicon-repo"></span> <strong>{{.Team.NumRepos}}</strong> {{$.i18n.Tr "org.lower_repositories"}}</a>
 | 
			
		||||
    	</div>
 | 
			
		||||
    	<p class="desc">
 | 
			
		||||
    		{{if eq .Team.LowerName "owners"}}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user