Add units to team (#947)
* add units to team * fix lint * finish team setting backend * finished permission controll on routes * fix import blank line * add unit check on ssh/http pull and push and fix test failed * fix fixtures data * remove unused code
This commit is contained in:
parent
5db5e16ab6
commit
fd6034aaf2
18 changed files with 366 additions and 113 deletions
|
@ -143,8 +143,10 @@ func runServ(c *cli.Context) error {
|
||||||
reponame := strings.ToLower(strings.TrimSuffix(rr[1], ".git"))
|
reponame := strings.ToLower(strings.TrimSuffix(rr[1], ".git"))
|
||||||
|
|
||||||
isWiki := false
|
isWiki := false
|
||||||
|
unitType := models.UnitTypeCode
|
||||||
if strings.HasSuffix(reponame, ".wiki") {
|
if strings.HasSuffix(reponame, ".wiki") {
|
||||||
isWiki = true
|
isWiki = true
|
||||||
|
unitType = models.UnitTypeWiki
|
||||||
reponame = reponame[:len(reponame)-5]
|
reponame = reponame[:len(reponame)-5]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -248,6 +250,12 @@ func runServ(c *cli.Context) error {
|
||||||
user.Name, requestedMode, repoPath)
|
user.Name, requestedMode, repoPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !repo.CheckUnitUser(user.ID, unitType) {
|
||||||
|
fail("You do not have allowed for this action",
|
||||||
|
"User %s does not have allowed access to repository %s 's code",
|
||||||
|
user.Name, repoPath)
|
||||||
|
}
|
||||||
|
|
||||||
os.Setenv(models.EnvPusherName, user.Name)
|
os.Setenv(models.EnvPusherName, user.Name)
|
||||||
os.Setenv(models.EnvPusherID, fmt.Sprintf("%d", user.ID))
|
os.Setenv(models.EnvPusherID, fmt.Sprintf("%d", user.ID))
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,4 +12,12 @@
|
||||||
type: 2
|
type: 2
|
||||||
index: 0
|
index: 0
|
||||||
config: "{}"
|
config: "{}"
|
||||||
|
created_unix: 946684810
|
||||||
|
|
||||||
|
-
|
||||||
|
id: 3
|
||||||
|
repo_id: 1
|
||||||
|
type: 7
|
||||||
|
index: 0
|
||||||
|
config: "{}"
|
||||||
created_unix: 946684810
|
created_unix: 946684810
|
|
@ -6,6 +6,7 @@
|
||||||
authorize: 4 # owner
|
authorize: 4 # owner
|
||||||
num_repos: 2
|
num_repos: 2
|
||||||
num_members: 1
|
num_members: 1
|
||||||
|
unit_types: '[1,2,3,4,5,6,7,8,9]'
|
||||||
|
|
||||||
-
|
-
|
||||||
id: 2
|
id: 2
|
||||||
|
@ -15,6 +16,7 @@
|
||||||
authorize: 2 # write
|
authorize: 2 # write
|
||||||
num_repos: 1
|
num_repos: 1
|
||||||
num_members: 2
|
num_members: 2
|
||||||
|
unit_types: '[1,2,3,4,5,6,7,8,9]'
|
||||||
|
|
||||||
-
|
-
|
||||||
id: 3
|
id: 3
|
||||||
|
@ -24,6 +26,7 @@
|
||||||
authorize: 4 # owner
|
authorize: 4 # owner
|
||||||
num_repos: 0
|
num_repos: 0
|
||||||
num_members: 1
|
num_members: 1
|
||||||
|
unit_types: '[1,2,3,4,5,6,7,8,9]'
|
||||||
|
|
||||||
-
|
-
|
||||||
id: 4
|
id: 4
|
||||||
|
@ -33,3 +36,4 @@
|
||||||
authorize: 4 # owner
|
authorize: 4 # owner
|
||||||
num_repos: 0
|
num_repos: 0
|
||||||
num_members: 1
|
num_members: 1
|
||||||
|
unit_types: '[1,2,3,4,5,6,7,8,9]'
|
|
@ -112,6 +112,8 @@ var migrations = []Migration{
|
||||||
NewMigration("add primary key to external login user", addExternalLoginUserPK),
|
NewMigration("add primary key to external login user", addExternalLoginUserPK),
|
||||||
// 31 -> 32
|
// 31 -> 32
|
||||||
NewMigration("add field for login source synchronization", addLoginSourceSyncEnabledColumn),
|
NewMigration("add field for login source synchronization", addLoginSourceSyncEnabledColumn),
|
||||||
|
// v32 -> v33
|
||||||
|
NewMigration("add units for team", addUnitsToRepoTeam),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Migrate database to current version
|
// Migrate database to current version
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2017 The Gogs Authors. All rights reserved.
|
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
|
23
models/migrations/v32.go
Normal file
23
models/migrations/v32.go
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// Copyright 2017 The Gitea 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 migrations
|
||||||
|
|
||||||
|
import "github.com/go-xorm/xorm"
|
||||||
|
|
||||||
|
func addUnitsToRepoTeam(x *xorm.Engine) error {
|
||||||
|
type Team struct {
|
||||||
|
UnitTypes []int `xorm:"json"`
|
||||||
|
}
|
||||||
|
|
||||||
|
err := x.Sync(new(Team))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = x.Update(&Team{
|
||||||
|
UnitTypes: []int{1, 2, 3, 4, 5, 6, 7, 8, 9},
|
||||||
|
})
|
||||||
|
return err
|
||||||
|
}
|
|
@ -24,6 +24,15 @@ type Team struct {
|
||||||
Members []*User `xorm:"-"`
|
Members []*User `xorm:"-"`
|
||||||
NumRepos int
|
NumRepos int
|
||||||
NumMembers int
|
NumMembers int
|
||||||
|
UnitTypes []UnitType `xorm:"json"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUnitTypes returns unit types the team owned, empty means all the unit types
|
||||||
|
func (t *Team) GetUnitTypes() []UnitType {
|
||||||
|
if len(t.UnitTypes) == 0 {
|
||||||
|
return allRepUnitTypes
|
||||||
|
}
|
||||||
|
return t.UnitTypes
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsOwnerTeam returns true if team is owner team.
|
// IsOwnerTeam returns true if team is owner team.
|
||||||
|
@ -183,6 +192,19 @@ func (t *Team) RemoveRepository(repoID int64) error {
|
||||||
return sess.Commit()
|
return sess.Commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EnableUnit returns if the team enables unit type t
|
||||||
|
func (t *Team) EnableUnit(tp UnitType) bool {
|
||||||
|
if len(t.UnitTypes) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
for _, u := range t.UnitTypes {
|
||||||
|
if u == tp {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// IsUsableTeamName tests if a name could be as team name
|
// IsUsableTeamName tests if a name could be as team name
|
||||||
func IsUsableTeamName(name string) error {
|
func IsUsableTeamName(name string) error {
|
||||||
switch name {
|
switch name {
|
||||||
|
|
|
@ -329,8 +329,61 @@ func (repo *Repository) getUnits(e Engine) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func getUnitsByRepoID(e Engine, repoID int64) (units []*RepoUnit, err error) {
|
// CheckUnitUser check whether user could visit the unit of this repository
|
||||||
return units, e.Where("repo_id = ?", repoID).Find(&units)
|
func (repo *Repository) CheckUnitUser(userID int64, unitType UnitType) bool {
|
||||||
|
if err := repo.getUnitsByUserID(x, userID); err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, unit := range repo.Units {
|
||||||
|
if unit.Type == unitType {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadUnitsByUserID loads units according userID's permissions
|
||||||
|
func (repo *Repository) LoadUnitsByUserID(userID int64) error {
|
||||||
|
return repo.getUnitsByUserID(x, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repo *Repository) getUnitsByUserID(e Engine, userID int64) (err error) {
|
||||||
|
if repo.Units != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
err = repo.getUnits(e)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !repo.Owner.IsOrganization() || userID == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
teams, err := getUserTeams(e, repo.OwnerID, userID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var allTypes = make(map[UnitType]struct{}, len(allRepUnitTypes))
|
||||||
|
for _, team := range teams {
|
||||||
|
for _, unitType := range team.UnitTypes {
|
||||||
|
allTypes[unitType] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// unique
|
||||||
|
var newRepoUnits = make([]*RepoUnit, 0, len(repo.Units))
|
||||||
|
for _, u := range repo.Units {
|
||||||
|
if _, ok := allTypes[u.Type]; ok {
|
||||||
|
newRepoUnits = append(newRepoUnits, u)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
repo.Units = newRepoUnits
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnableUnit if this repository enabled some unit
|
// EnableUnit if this repository enabled some unit
|
||||||
|
@ -1595,6 +1648,7 @@ func DeleteRepository(uid, repoID int64) error {
|
||||||
&Release{RepoID: repoID},
|
&Release{RepoID: repoID},
|
||||||
&Collaboration{RepoID: repoID},
|
&Collaboration{RepoID: repoID},
|
||||||
&PullRequest{BaseRepoID: repoID},
|
&PullRequest{BaseRepoID: repoID},
|
||||||
|
&RepoUnit{RepoID: repoID},
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return fmt.Errorf("deleteBeans: %v", err)
|
return fmt.Errorf("deleteBeans: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,3 +135,11 @@ func (r *RepoUnit) ExternalWikiConfig() *ExternalWikiConfig {
|
||||||
func (r *RepoUnit) ExternalTrackerConfig() *ExternalTrackerConfig {
|
func (r *RepoUnit) ExternalTrackerConfig() *ExternalTrackerConfig {
|
||||||
return r.Config.(*ExternalTrackerConfig)
|
return r.Config.(*ExternalTrackerConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getUnitsByRepoID(e Engine, repoID int64) (units []*RepoUnit, err error) {
|
||||||
|
return units, e.Where("repo_id = ?", repoID).Find(&units)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUnitsByRepoIDAndIDs(e Engine, repoID int64, types []UnitType) (units []*RepoUnit, err error) {
|
||||||
|
return units, e.Where("repo_id = ?", repoID).In("`type`", types).Find(&units)
|
||||||
|
}
|
||||||
|
|
168
models/unit.go
168
models/unit.go
|
@ -20,90 +20,21 @@ const (
|
||||||
UnitTypeExternalTracker // 9 ExternalTracker
|
UnitTypeExternalTracker // 9 ExternalTracker
|
||||||
)
|
)
|
||||||
|
|
||||||
// Unit is a tab page of one repository
|
|
||||||
type Unit struct {
|
|
||||||
Type UnitType
|
|
||||||
NameKey string
|
|
||||||
URI string
|
|
||||||
DescKey string
|
|
||||||
Idx int
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enumerate all the units
|
|
||||||
var (
|
var (
|
||||||
UnitCode = Unit{
|
// allRepUnitTypes contains all the unit types
|
||||||
|
allRepUnitTypes = []UnitType{
|
||||||
UnitTypeCode,
|
UnitTypeCode,
|
||||||
"repo.code",
|
|
||||||
"/",
|
|
||||||
"repo.code_desc",
|
|
||||||
0,
|
|
||||||
}
|
|
||||||
|
|
||||||
UnitIssues = Unit{
|
|
||||||
UnitTypeIssues,
|
UnitTypeIssues,
|
||||||
"repo.issues",
|
|
||||||
"/issues",
|
|
||||||
"repo.issues_desc",
|
|
||||||
1,
|
|
||||||
}
|
|
||||||
|
|
||||||
UnitExternalTracker = Unit{
|
|
||||||
UnitTypeExternalTracker,
|
|
||||||
"repo.issues",
|
|
||||||
"/issues",
|
|
||||||
"repo.issues_desc",
|
|
||||||
1,
|
|
||||||
}
|
|
||||||
|
|
||||||
UnitPullRequests = Unit{
|
|
||||||
UnitTypePullRequests,
|
UnitTypePullRequests,
|
||||||
"repo.pulls",
|
|
||||||
"/pulls",
|
|
||||||
"repo.pulls_desc",
|
|
||||||
2,
|
|
||||||
}
|
|
||||||
|
|
||||||
UnitCommits = Unit{
|
|
||||||
UnitTypeCommits,
|
UnitTypeCommits,
|
||||||
"repo.commits",
|
|
||||||
"/commits/master",
|
|
||||||
"repo.commits_desc",
|
|
||||||
3,
|
|
||||||
}
|
|
||||||
|
|
||||||
UnitReleases = Unit{
|
|
||||||
UnitTypeReleases,
|
UnitTypeReleases,
|
||||||
"repo.releases",
|
|
||||||
"/releases",
|
|
||||||
"repo.releases_desc",
|
|
||||||
4,
|
|
||||||
}
|
|
||||||
|
|
||||||
UnitWiki = Unit{
|
|
||||||
UnitTypeWiki,
|
UnitTypeWiki,
|
||||||
"repo.wiki",
|
|
||||||
"/wiki",
|
|
||||||
"repo.wiki_desc",
|
|
||||||
5,
|
|
||||||
}
|
|
||||||
|
|
||||||
UnitExternalWiki = Unit{
|
|
||||||
UnitTypeExternalWiki,
|
|
||||||
"repo.wiki",
|
|
||||||
"/wiki",
|
|
||||||
"repo.wiki_desc",
|
|
||||||
5,
|
|
||||||
}
|
|
||||||
|
|
||||||
UnitSettings = Unit{
|
|
||||||
UnitTypeSettings,
|
UnitTypeSettings,
|
||||||
"repo.settings",
|
UnitTypeExternalWiki,
|
||||||
"/settings",
|
UnitTypeExternalTracker,
|
||||||
"repo.settings_desc",
|
|
||||||
6,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// defaultRepoUnits contains all the default unit types
|
// defaultRepoUnits contains the default unit types
|
||||||
defaultRepoUnits = []UnitType{
|
defaultRepoUnits = []UnitType{
|
||||||
UnitTypeCode,
|
UnitTypeCode,
|
||||||
UnitTypeIssues,
|
UnitTypeIssues,
|
||||||
|
@ -121,6 +52,95 @@ var (
|
||||||
UnitTypeReleases,
|
UnitTypeReleases,
|
||||||
UnitTypeSettings,
|
UnitTypeSettings,
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Unit is a tab page of one repository
|
||||||
|
type Unit struct {
|
||||||
|
Type UnitType
|
||||||
|
NameKey string
|
||||||
|
URI string
|
||||||
|
DescKey string
|
||||||
|
Idx int
|
||||||
|
}
|
||||||
|
|
||||||
|
// CanDisable returns if this unit could be disabled.
|
||||||
|
func (u *Unit) CanDisable() bool {
|
||||||
|
return u.Type != UnitTypeSettings
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enumerate all the units
|
||||||
|
var (
|
||||||
|
UnitCode = Unit{
|
||||||
|
UnitTypeCode,
|
||||||
|
"repo.code",
|
||||||
|
"/",
|
||||||
|
"repo.code.desc",
|
||||||
|
0,
|
||||||
|
}
|
||||||
|
|
||||||
|
UnitIssues = Unit{
|
||||||
|
UnitTypeIssues,
|
||||||
|
"repo.issues",
|
||||||
|
"/issues",
|
||||||
|
"repo.issues.desc",
|
||||||
|
1,
|
||||||
|
}
|
||||||
|
|
||||||
|
UnitExternalTracker = Unit{
|
||||||
|
UnitTypeExternalTracker,
|
||||||
|
"repo.ext_issues",
|
||||||
|
"/issues",
|
||||||
|
"repo.ext_issues.desc",
|
||||||
|
1,
|
||||||
|
}
|
||||||
|
|
||||||
|
UnitPullRequests = Unit{
|
||||||
|
UnitTypePullRequests,
|
||||||
|
"repo.pulls",
|
||||||
|
"/pulls",
|
||||||
|
"repo.pulls.desc",
|
||||||
|
2,
|
||||||
|
}
|
||||||
|
|
||||||
|
UnitCommits = Unit{
|
||||||
|
UnitTypeCommits,
|
||||||
|
"repo.commits",
|
||||||
|
"/commits/master",
|
||||||
|
"repo.commits.desc",
|
||||||
|
3,
|
||||||
|
}
|
||||||
|
|
||||||
|
UnitReleases = Unit{
|
||||||
|
UnitTypeReleases,
|
||||||
|
"repo.releases",
|
||||||
|
"/releases",
|
||||||
|
"repo.releases.desc",
|
||||||
|
4,
|
||||||
|
}
|
||||||
|
|
||||||
|
UnitWiki = Unit{
|
||||||
|
UnitTypeWiki,
|
||||||
|
"repo.wiki",
|
||||||
|
"/wiki",
|
||||||
|
"repo.wiki.desc",
|
||||||
|
5,
|
||||||
|
}
|
||||||
|
|
||||||
|
UnitExternalWiki = Unit{
|
||||||
|
UnitTypeExternalWiki,
|
||||||
|
"repo.ext_wiki",
|
||||||
|
"/wiki",
|
||||||
|
"repo.ext_wiki.desc",
|
||||||
|
5,
|
||||||
|
}
|
||||||
|
|
||||||
|
UnitSettings = Unit{
|
||||||
|
UnitTypeSettings,
|
||||||
|
"repo.settings",
|
||||||
|
"/settings",
|
||||||
|
"repo.settings.desc",
|
||||||
|
6,
|
||||||
|
}
|
||||||
|
|
||||||
// Units contains all the units
|
// Units contains all the units
|
||||||
Units = map[UnitType]Unit{
|
Units = map[UnitType]Unit{
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
package auth
|
package auth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"code.gitea.io/gitea/models"
|
||||||
|
|
||||||
"github.com/go-macaron/binding"
|
"github.com/go-macaron/binding"
|
||||||
"gopkg.in/macaron.v1"
|
"gopkg.in/macaron.v1"
|
||||||
)
|
)
|
||||||
|
@ -53,6 +55,7 @@ type CreateTeamForm struct {
|
||||||
TeamName string `binding:"Required;AlphaDashDot;MaxSize(30)"`
|
TeamName string `binding:"Required;AlphaDashDot;MaxSize(30)"`
|
||||||
Description string `binding:"MaxSize(255)"`
|
Description string `binding:"MaxSize(255)"`
|
||||||
Permission string
|
Permission string
|
||||||
|
Units []models.UnitType
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
|
|
|
@ -493,6 +493,37 @@ func RequireRepoWriter() macaron.Handler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LoadRepoUnits loads repsitory's units, it should be called after repository and user loaded
|
||||||
|
func LoadRepoUnits() macaron.Handler {
|
||||||
|
return func(ctx *Context) {
|
||||||
|
var userID int64
|
||||||
|
if ctx.User != nil {
|
||||||
|
userID = ctx.User.ID
|
||||||
|
}
|
||||||
|
err := ctx.Repo.Repository.LoadUnitsByUserID(userID)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Handle(500, "LoadUnitsByUserID", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckUnit will check whether
|
||||||
|
func CheckUnit(unitType models.UnitType) macaron.Handler {
|
||||||
|
return func(ctx *Context) {
|
||||||
|
var find bool
|
||||||
|
for _, unit := range ctx.Repo.Repository.Units {
|
||||||
|
if unit.Type == unitType {
|
||||||
|
find = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !find {
|
||||||
|
ctx.Handle(404, "CheckUnit", fmt.Errorf("%s: %v", ctx.Tr("units.error.unit_not_allowed"), unitType))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// GitHookService checks if repository Git hooks service has been enabled.
|
// GitHookService checks if repository Git hooks service has been enabled.
|
||||||
func GitHookService() macaron.Handler {
|
func GitHookService() macaron.Handler {
|
||||||
return func(ctx *Context) {
|
return func(ctx *Context) {
|
||||||
|
|
|
@ -505,6 +505,7 @@ push_exist_repo = Pushing an existing repository from the command line
|
||||||
bare_message = This repository does not contain any content.
|
bare_message = This repository does not contain any content.
|
||||||
|
|
||||||
code = Code
|
code = Code
|
||||||
|
code.desc = Code is your program source
|
||||||
branch = Branch
|
branch = Branch
|
||||||
tree = Tree
|
tree = Tree
|
||||||
filter_branch_and_tag = Filter branch or tag
|
filter_branch_and_tag = Filter branch or tag
|
||||||
|
@ -565,6 +566,7 @@ editor.unable_to_upload_files = Failed to upload files to '%s' with error: %v
|
||||||
editor.upload_files_to_dir = Upload files to '%s'
|
editor.upload_files_to_dir = Upload files to '%s'
|
||||||
editor.cannot_commit_to_protected_branch = Can not commit to protected branch '%s'.
|
editor.cannot_commit_to_protected_branch = Can not commit to protected branch '%s'.
|
||||||
|
|
||||||
|
commits.desc = Commits show the history submited
|
||||||
commits.commits = Commits
|
commits.commits = Commits
|
||||||
commits.search = Search commits
|
commits.search = Search commits
|
||||||
commits.find = Search
|
commits.find = Search
|
||||||
|
@ -575,6 +577,10 @@ commits.date = Date
|
||||||
commits.older = Older
|
commits.older = Older
|
||||||
commits.newer = Newer
|
commits.newer = Newer
|
||||||
|
|
||||||
|
ext_issues = Ext Issues
|
||||||
|
ext_issues.desc = Ext Issues link to an external issues management
|
||||||
|
|
||||||
|
issues.desc = Issues management your tasks for this repository
|
||||||
issues.new = New Issue
|
issues.new = New Issue
|
||||||
issues.new.labels = Labels
|
issues.new.labels = Labels
|
||||||
issues.new.no_label = No Label
|
issues.new.no_label = No Label
|
||||||
|
@ -678,6 +684,7 @@ issues.attachment.download = `Click to download "%s"`
|
||||||
issues.subscribe = Subscribe
|
issues.subscribe = Subscribe
|
||||||
issues.unsubscribe = Unsubscribe
|
issues.unsubscribe = Unsubscribe
|
||||||
|
|
||||||
|
pulls.desc = Pulls management your code review and merge requests
|
||||||
pulls.new = New Pull Request
|
pulls.new = New Pull Request
|
||||||
pulls.compare_changes = Compare Changes
|
pulls.compare_changes = Compare Changes
|
||||||
pulls.compare_changes_desc = Compare two branches and make a pull request for changes.
|
pulls.compare_changes_desc = Compare two branches and make a pull request for changes.
|
||||||
|
@ -734,9 +741,13 @@ milestones.filter_sort.most_complete = Most complete
|
||||||
milestones.filter_sort.most_issues = Most issues
|
milestones.filter_sort.most_issues = Most issues
|
||||||
milestones.filter_sort.least_issues = Least issues
|
milestones.filter_sort.least_issues = Least issues
|
||||||
|
|
||||||
|
ext_wiki = Ext Wiki
|
||||||
|
ext_wiki.desc = Ext Wiki links to an external wiki system
|
||||||
|
|
||||||
wiki = Wiki
|
wiki = Wiki
|
||||||
wiki.welcome = Welcome to the project wiki
|
wiki.welcome = Welcome to the project wiki
|
||||||
wiki.welcome_desc = A wiki allows you and your collaborators to easily document your project.
|
wiki.welcome_desc = A wiki allows you and your collaborators to easily document your project.
|
||||||
|
wiki.desc = Wiki is a collection of your documents
|
||||||
wiki.create_first_page = Create the first page
|
wiki.create_first_page = Create the first page
|
||||||
wiki.page = Page
|
wiki.page = Page
|
||||||
wiki.filter_page = Filter page
|
wiki.filter_page = Filter page
|
||||||
|
@ -753,6 +764,7 @@ wiki.pages = Pages
|
||||||
wiki.last_updated = Last updated %s
|
wiki.last_updated = Last updated %s
|
||||||
|
|
||||||
settings = Settings
|
settings = Settings
|
||||||
|
settings.desc = Settings management your settings for repository
|
||||||
settings.options = Options
|
settings.options = Options
|
||||||
settings.collaboration = Collaboration
|
settings.collaboration = Collaboration
|
||||||
settings.collaboration.admin = Admin
|
settings.collaboration.admin = Admin
|
||||||
|
@ -910,6 +922,7 @@ diff.view_file = View File
|
||||||
diff.file_suppressed = File diff suppressed because it is too large
|
diff.file_suppressed = File diff suppressed because it is too large
|
||||||
diff.too_many_files = Some files were not shown because too many files changed in this diff
|
diff.too_many_files = Some files were not shown because too many files changed in this diff
|
||||||
|
|
||||||
|
releases.desc = Releases manage your milestone versions
|
||||||
release.releases = Releases
|
release.releases = Releases
|
||||||
release.new_release = New Release
|
release.new_release = New Release
|
||||||
release.draft = Draft
|
release.draft = Draft
|
||||||
|
@ -968,6 +981,7 @@ team_desc = Description
|
||||||
team_name_helper = You will use this name to mention this team in conversations.
|
team_name_helper = You will use this name to mention this team in conversations.
|
||||||
team_desc_helper = What is this team for?
|
team_desc_helper = What is this team for?
|
||||||
team_permission_desc = What permissions should this team have?
|
team_permission_desc = What permissions should this team have?
|
||||||
|
team_unit_desc = Which units should this team have?
|
||||||
|
|
||||||
form.name_reserved = Organization name '%s' is reserved.
|
form.name_reserved = Organization name '%s' is reserved.
|
||||||
form.name_pattern_not_allowed = Organization name pattern '%s' is not allowed.
|
form.name_pattern_not_allowed = Organization name pattern '%s' is not allowed.
|
||||||
|
@ -1406,3 +1420,7 @@ error.no_committer_account = No account linked to committer's email
|
||||||
error.no_gpg_keys_found = "No known key found for this signature in database"
|
error.no_gpg_keys_found = "No known key found for this signature in database"
|
||||||
error.not_signed_commit = "Not a signed commit"
|
error.not_signed_commit = "Not a signed commit"
|
||||||
error.failed_retrieval_gpg_keys = "Failed to retrieve any key attached to the committer account"
|
error.failed_retrieval_gpg_keys = "Failed to retrieve any key attached to the committer account"
|
||||||
|
|
||||||
|
[units]
|
||||||
|
error.no_unit_allowed_repo = Cannot find any unit allowed on this repository
|
||||||
|
error.unit_not_allowed = You have not allowed to visit this repository unit
|
|
@ -156,6 +156,7 @@ func NewTeam(ctx *context.Context) {
|
||||||
ctx.Data["PageIsOrgTeams"] = true
|
ctx.Data["PageIsOrgTeams"] = true
|
||||||
ctx.Data["PageIsOrgTeamsNew"] = true
|
ctx.Data["PageIsOrgTeamsNew"] = true
|
||||||
ctx.Data["Team"] = &models.Team{}
|
ctx.Data["Team"] = &models.Team{}
|
||||||
|
ctx.Data["Units"] = models.Units
|
||||||
ctx.HTML(200, tplTeamNew)
|
ctx.HTML(200, tplTeamNew)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,6 +171,7 @@ func NewTeamPost(ctx *context.Context, form auth.CreateTeamForm) {
|
||||||
Name: form.TeamName,
|
Name: form.TeamName,
|
||||||
Description: form.Description,
|
Description: form.Description,
|
||||||
Authorize: models.ParseAccessMode(form.Permission),
|
Authorize: models.ParseAccessMode(form.Permission),
|
||||||
|
UnitTypes: form.Units,
|
||||||
}
|
}
|
||||||
ctx.Data["Team"] = t
|
ctx.Data["Team"] = t
|
||||||
|
|
||||||
|
@ -220,6 +222,7 @@ func EditTeam(ctx *context.Context) {
|
||||||
ctx.Data["PageIsOrgTeams"] = true
|
ctx.Data["PageIsOrgTeams"] = true
|
||||||
ctx.Data["team_name"] = ctx.Org.Team.Name
|
ctx.Data["team_name"] = ctx.Org.Team.Name
|
||||||
ctx.Data["desc"] = ctx.Org.Team.Description
|
ctx.Data["desc"] = ctx.Org.Team.Description
|
||||||
|
ctx.Data["Units"] = models.Units
|
||||||
ctx.HTML(200, tplTeamNew)
|
ctx.HTML(200, tplTeamNew)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,6 +261,7 @@ func EditTeamPost(ctx *context.Context, form auth.CreateTeamForm) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
t.Description = form.Description
|
t.Description = form.Description
|
||||||
|
t.UnitTypes = form.Units
|
||||||
if err := models.UpdateTeam(t, isAuthChanged); err != nil {
|
if err := models.UpdateTeam(t, isAuthChanged); err != nil {
|
||||||
ctx.Data["Err_TeamName"] = true
|
ctx.Data["Err_TeamName"] = true
|
||||||
switch {
|
switch {
|
||||||
|
|
|
@ -77,8 +77,10 @@ func HTTP(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
isWiki := false
|
isWiki := false
|
||||||
|
var unitType = models.UnitTypeCode
|
||||||
if strings.HasSuffix(reponame, ".wiki") {
|
if strings.HasSuffix(reponame, ".wiki") {
|
||||||
isWiki = true
|
isWiki = true
|
||||||
|
unitType = models.UnitTypeWiki
|
||||||
reponame = reponame[:len(reponame)-5]
|
reponame = reponame[:len(reponame)-5]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,6 +206,12 @@ func HTTP(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !repo.CheckUnitUser(authUser.ID, unitType) {
|
||||||
|
ctx.HandleText(http.StatusForbidden, fmt.Sprintf("User %s does not have allowed access to repository %s 's code",
|
||||||
|
authUser.Name, repo.RepoPath()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
environ = []string{
|
environ = []string{
|
||||||
models.EnvRepoUsername + "=" + username,
|
models.EnvRepoUsername + "=" + username,
|
||||||
models.EnvRepoName + "=" + reponame,
|
models.EnvRepoName + "=" + reponame,
|
||||||
|
|
|
@ -252,6 +252,25 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
|
||||||
|
|
||||||
// Home render repository home page
|
// Home render repository home page
|
||||||
func Home(ctx *context.Context) {
|
func Home(ctx *context.Context) {
|
||||||
|
if len(ctx.Repo.Repository.Units) > 0 {
|
||||||
|
tp := ctx.Repo.Repository.Units[0].Type
|
||||||
|
if tp == models.UnitTypeCode {
|
||||||
|
renderCode(ctx)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
unit, ok := models.Units[tp]
|
||||||
|
if ok {
|
||||||
|
ctx.Redirect(setting.AppSubURL + fmt.Sprintf("/%s%s",
|
||||||
|
ctx.Repo.Repository.FullName(), unit.URI))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Handle(404, "Home", fmt.Errorf(ctx.Tr("units.error.no_unit_allowed_repo")))
|
||||||
|
}
|
||||||
|
|
||||||
|
func renderCode(ctx *context.Context) {
|
||||||
ctx.Data["PageIsViewCode"] = true
|
ctx.Data["PageIsViewCode"] = true
|
||||||
|
|
||||||
if ctx.Repo.Repository.IsBare {
|
if ctx.Repo.Repository.IsBare {
|
||||||
|
|
|
@ -445,10 +445,11 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||||
|
|
||||||
}, func(ctx *context.Context) {
|
}, func(ctx *context.Context) {
|
||||||
ctx.Data["PageIsSettings"] = true
|
ctx.Data["PageIsSettings"] = true
|
||||||
}, context.UnitTypes())
|
}, context.UnitTypes(), context.LoadRepoUnits(), context.CheckUnit(models.UnitTypeSettings))
|
||||||
}, reqSignIn, context.RepoAssignment(), reqRepoAdmin, context.RepoRef())
|
}, reqSignIn, context.RepoAssignment(), reqRepoAdmin, context.RepoRef())
|
||||||
|
|
||||||
m.Get("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), repo.Action)
|
m.Get("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), repo.Action)
|
||||||
|
|
||||||
m.Group("/:username/:reponame", func() {
|
m.Group("/:username/:reponame", func() {
|
||||||
// FIXME: should use different URLs but mostly same logic for comments of issue and pull reuqest.
|
// FIXME: should use different URLs but mostly same logic for comments of issue and pull reuqest.
|
||||||
// So they can apply their own enable/disable logic on routers.
|
// So they can apply their own enable/disable logic on routers.
|
||||||
|
@ -486,28 +487,6 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||||
m.Get("/:id/:action", repo.ChangeMilestonStatus)
|
m.Get("/:id/:action", repo.ChangeMilestonStatus)
|
||||||
m.Post("/delete", repo.DeleteMilestone)
|
m.Post("/delete", repo.DeleteMilestone)
|
||||||
}, reqRepoWriter, context.RepoRef())
|
}, reqRepoWriter, context.RepoRef())
|
||||||
m.Group("/releases", func() {
|
|
||||||
m.Get("/new", repo.NewRelease)
|
|
||||||
m.Post("/new", bindIgnErr(auth.NewReleaseForm{}), repo.NewReleasePost)
|
|
||||||
m.Post("/delete", repo.DeleteRelease)
|
|
||||||
}, repo.MustBeNotBare, reqRepoWriter, context.RepoRef())
|
|
||||||
m.Group("/releases", func() {
|
|
||||||
m.Get("/edit/*", repo.EditRelease)
|
|
||||||
m.Post("/edit/*", bindIgnErr(auth.EditReleaseForm{}), repo.EditReleasePost)
|
|
||||||
}, repo.MustBeNotBare, reqRepoWriter, func(ctx *context.Context) {
|
|
||||||
var err error
|
|
||||||
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch)
|
|
||||||
if err != nil {
|
|
||||||
ctx.Handle(500, "GetBranchCommit", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.Repo.CommitsCount, err = ctx.Repo.Commit.CommitsCount()
|
|
||||||
if err != nil {
|
|
||||||
ctx.Handle(500, "CommitsCount", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount
|
|
||||||
})
|
|
||||||
|
|
||||||
m.Combo("/compare/*", repo.MustAllowPulls, repo.SetEditorconfigIfExists).
|
m.Combo("/compare/*", repo.MustAllowPulls, repo.SetEditorconfigIfExists).
|
||||||
Get(repo.CompareAndPullRequest).
|
Get(repo.CompareAndPullRequest).
|
||||||
|
@ -539,16 +518,42 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, reqSignIn, context.RepoAssignment(), context.UnitTypes())
|
}, reqSignIn, context.RepoAssignment(), context.UnitTypes(), context.LoadRepoUnits(), context.CheckUnit(models.UnitTypeIssues))
|
||||||
|
|
||||||
|
// Releases
|
||||||
|
m.Group("/:username/:reponame", func() {
|
||||||
|
m.Group("/releases", func() {
|
||||||
|
m.Get("/", repo.MustBeNotBare, repo.Releases)
|
||||||
|
m.Get("/new", repo.NewRelease)
|
||||||
|
m.Post("/new", bindIgnErr(auth.NewReleaseForm{}), repo.NewReleasePost)
|
||||||
|
m.Post("/delete", repo.DeleteRelease)
|
||||||
|
}, repo.MustBeNotBare, reqRepoWriter, context.RepoRef())
|
||||||
|
m.Group("/releases", func() {
|
||||||
|
m.Get("/edit/*", repo.EditRelease)
|
||||||
|
m.Post("/edit/*", bindIgnErr(auth.EditReleaseForm{}), repo.EditReleasePost)
|
||||||
|
}, repo.MustBeNotBare, reqRepoWriter, func(ctx *context.Context) {
|
||||||
|
var err error
|
||||||
|
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch)
|
||||||
|
if err != nil {
|
||||||
|
ctx.Handle(500, "GetBranchCommit", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Repo.CommitsCount, err = ctx.Repo.Commit.CommitsCount()
|
||||||
|
if err != nil {
|
||||||
|
ctx.Handle(500, "CommitsCount", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount
|
||||||
|
})
|
||||||
|
}, reqSignIn, context.RepoAssignment(), context.UnitTypes(), context.LoadRepoUnits(), context.CheckUnit(models.UnitTypeReleases))
|
||||||
|
|
||||||
m.Group("/:username/:reponame", func() {
|
m.Group("/:username/:reponame", func() {
|
||||||
m.Group("", func() {
|
m.Group("", func() {
|
||||||
m.Get("/releases", repo.MustBeNotBare, repo.Releases)
|
|
||||||
m.Get("/^:type(issues|pulls)$", repo.RetrieveLabels, repo.Issues)
|
m.Get("/^:type(issues|pulls)$", repo.RetrieveLabels, repo.Issues)
|
||||||
m.Get("/^:type(issues|pulls)$/:index", repo.ViewIssue)
|
m.Get("/^:type(issues|pulls)$/:index", repo.ViewIssue)
|
||||||
m.Get("/labels/", repo.RetrieveLabels, repo.Labels)
|
m.Get("/labels/", repo.RetrieveLabels, repo.Labels)
|
||||||
m.Get("/milestones", repo.Milestones)
|
m.Get("/milestones", repo.Milestones)
|
||||||
}, context.RepoRef())
|
}, context.RepoRef(), context.CheckUnit(models.UnitTypeIssues))
|
||||||
|
|
||||||
// m.Get("/branches", repo.Branches)
|
// m.Get("/branches", repo.Branches)
|
||||||
m.Post("/branches/:name/delete", reqSignIn, reqRepoWriter, repo.MustBeNotBare, repo.DeleteBranchPost)
|
m.Post("/branches/:name/delete", reqSignIn, reqRepoWriter, repo.MustBeNotBare, repo.DeleteBranchPost)
|
||||||
|
@ -564,20 +569,20 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||||
Post(bindIgnErr(auth.NewWikiForm{}), repo.EditWikiPost)
|
Post(bindIgnErr(auth.NewWikiForm{}), repo.EditWikiPost)
|
||||||
m.Post("/:page/delete", repo.DeleteWikiPagePost)
|
m.Post("/:page/delete", repo.DeleteWikiPagePost)
|
||||||
}, reqSignIn, reqRepoWriter)
|
}, reqSignIn, reqRepoWriter)
|
||||||
}, repo.MustEnableWiki, context.RepoRef())
|
}, repo.MustEnableWiki, context.RepoRef(), context.CheckUnit(models.UnitTypeWiki))
|
||||||
|
|
||||||
m.Group("/wiki", func() {
|
m.Group("/wiki", func() {
|
||||||
m.Get("/raw/*", repo.WikiRaw)
|
m.Get("/raw/*", repo.WikiRaw)
|
||||||
m.Get("/*", repo.WikiRaw)
|
m.Get("/*", repo.WikiRaw)
|
||||||
}, repo.MustEnableWiki)
|
}, repo.MustEnableWiki, context.CheckUnit(models.UnitTypeWiki), context.CheckUnit(models.UnitTypeWiki))
|
||||||
|
|
||||||
m.Get("/archive/*", repo.MustBeNotBare, repo.Download)
|
m.Get("/archive/*", repo.MustBeNotBare, repo.Download, context.CheckUnit(models.UnitTypeCode))
|
||||||
|
|
||||||
m.Group("/pulls/:index", func() {
|
m.Group("/pulls/:index", func() {
|
||||||
m.Get("/commits", context.RepoRef(), repo.ViewPullCommits)
|
m.Get("/commits", context.RepoRef(), repo.ViewPullCommits)
|
||||||
m.Get("/files", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.ViewPullFiles)
|
m.Get("/files", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.ViewPullFiles)
|
||||||
m.Post("/merge", reqRepoWriter, repo.MergePullRequest)
|
m.Post("/merge", reqRepoWriter, repo.MergePullRequest)
|
||||||
}, repo.MustAllowPulls)
|
}, repo.MustAllowPulls, context.CheckUnit(models.UnitTypePullRequests))
|
||||||
|
|
||||||
m.Group("", func() {
|
m.Group("", func() {
|
||||||
m.Get("/src/*", repo.SetEditorconfigIfExists, repo.Home)
|
m.Get("/src/*", repo.SetEditorconfigIfExists, repo.Home)
|
||||||
|
@ -586,21 +591,22 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||||
m.Get("/graph", repo.Graph)
|
m.Get("/graph", repo.Graph)
|
||||||
m.Get("/commit/:sha([a-f0-9]{7,40})$", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.Diff)
|
m.Get("/commit/:sha([a-f0-9]{7,40})$", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.Diff)
|
||||||
m.Get("/forks", repo.Forks)
|
m.Get("/forks", repo.Forks)
|
||||||
}, context.RepoRef())
|
}, context.RepoRef(), context.CheckUnit(models.UnitTypeCode))
|
||||||
m.Get("/commit/:sha([a-f0-9]{7,40})\\.:ext(patch|diff)", repo.MustBeNotBare, repo.RawDiff)
|
m.Get("/commit/:sha([a-f0-9]{7,40})\\.:ext(patch|diff)", repo.MustBeNotBare, repo.RawDiff, context.CheckUnit(models.UnitTypeCode))
|
||||||
|
|
||||||
m.Get("/compare/:before([a-z0-9]{40})\\.\\.\\.:after([a-z0-9]{40})", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.MustBeNotBare, repo.CompareDiff)
|
m.Get("/compare/:before([a-z0-9]{40})\\.\\.\\.:after([a-z0-9]{40})", repo.SetEditorconfigIfExists,
|
||||||
}, ignSignIn, context.RepoAssignment(), context.UnitTypes())
|
repo.SetDiffViewStyle, repo.MustBeNotBare, repo.CompareDiff, context.CheckUnit(models.UnitTypeCode))
|
||||||
|
}, ignSignIn, context.RepoAssignment(), context.UnitTypes(), context.LoadRepoUnits())
|
||||||
m.Group("/:username/:reponame", func() {
|
m.Group("/:username/:reponame", func() {
|
||||||
m.Get("/stars", repo.Stars)
|
m.Get("/stars", repo.Stars)
|
||||||
m.Get("/watchers", repo.Watchers)
|
m.Get("/watchers", repo.Watchers)
|
||||||
}, ignSignIn, context.RepoAssignment(), context.RepoRef(), context.UnitTypes())
|
}, ignSignIn, context.RepoAssignment(), context.RepoRef(), context.UnitTypes(), context.LoadRepoUnits())
|
||||||
|
|
||||||
m.Group("/:username", func() {
|
m.Group("/:username", func() {
|
||||||
m.Group("/:reponame", func() {
|
m.Group("/:reponame", func() {
|
||||||
m.Get("", repo.SetEditorconfigIfExists, repo.Home)
|
m.Get("", repo.SetEditorconfigIfExists, repo.Home)
|
||||||
m.Get("\\.git$", repo.SetEditorconfigIfExists, repo.Home)
|
m.Get("\\.git$", repo.SetEditorconfigIfExists, repo.Home)
|
||||||
}, ignSignIn, context.RepoAssignment(), context.RepoRef(), context.UnitTypes())
|
}, ignSignIn, context.RepoAssignment(), context.RepoRef(), context.UnitTypes(), context.LoadRepoUnits())
|
||||||
|
|
||||||
m.Group("/:reponame", func() {
|
m.Group("/:reponame", func() {
|
||||||
m.Group("/info/lfs", func() {
|
m.Group("/info/lfs", func() {
|
||||||
|
|
|
@ -52,6 +52,21 @@
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
|
<div class="required grouped field">
|
||||||
|
<label>{{.i18n.Tr "org.team_unit_desc"}}</label>
|
||||||
|
<br>
|
||||||
|
{{range $t, $unit := $.Units}}
|
||||||
|
<div class="field">
|
||||||
|
<div class="ui toggle checkbox">
|
||||||
|
<input type="checkbox" class="hidden" name="units" value="{{$unit.Type}}"{{if $.Team.EnableUnit $unit.Type}} checked{{end}}>
|
||||||
|
<label>{{$.i18n.Tr $unit.NameKey}}</label>
|
||||||
|
<span class="help">{{$.i18n.Tr $unit.DescKey}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
</div>
|
||||||
|
<div class="ui divider"></div>
|
||||||
|
|
||||||
<div class="field">
|
<div class="field">
|
||||||
{{if .PageIsOrgTeamsNew}}
|
{{if .PageIsOrgTeamsNew}}
|
||||||
<button class="ui green button">{{.i18n.Tr "org.create_new_team"}}</button>
|
<button class="ui green button">{{.i18n.Tr "org.create_new_team"}}</button>
|
||||||
|
|
Reference in a new issue