diff --git a/cmd/web.go b/cmd/web.go index af92b713..90560295 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -195,9 +195,10 @@ func runWeb(*cli.Context) { r.Get("/:org/dashboard", org.Dashboard) r.Get("/:org/members", org.Members) - r.Get("/:org/teams/:team/edit", org.EditTeam) - r.Get("/:org/teams/new", org.NewTeam) r.Get("/:org/teams", org.Teams) + r.Get("/:org/teams/new", org.NewTeam) + r.Post("/:org/teams/new", bindIgnErr(auth.CreateTeamForm{}), org.NewTeamPost) + r.Get("/:org/teams/:team/edit", org.EditTeam) r.Get("/:org/settings", org.Settings) r.Post("/:org/settings", bindIgnErr(auth.OrgSettingForm{}), org.SettingsPost) diff --git a/gogs.go b/gogs.go index bef01859..df736647 100644 --- a/gogs.go +++ b/gogs.go @@ -17,7 +17,7 @@ import ( "github.com/gogits/gogs/modules/setting" ) -const APP_VER = "0.4.5.0629 Alpha" +const APP_VER = "0.4.5.0702 Alpha" func init() { runtime.GOMAXPROCS(runtime.NumCPU()) diff --git a/models/org.go b/models/org.go index 71b1efe9..2625ed42 100644 --- a/models/org.go +++ b/models/org.go @@ -5,11 +5,17 @@ package models import ( + "errors" "strings" "github.com/gogits/gogs/modules/base" ) +var ( + ErrOrgNotExist = errors.New("Organization does not exist") + ErrTeamAlreadyExist = errors.New("Team already exist") +) + // IsOrgOwner returns true if given user is in the owner team. func (org *User) IsOrgOwner(uid int64) bool { return IsOrganizationOwner(org.Id, uid) @@ -156,6 +162,13 @@ func DeleteOrganization(org *User) (err error) { return sess.Commit() } +// ___________ +// \__ ___/___ _____ _____ +// | |_/ __ \\__ \ / \ +// | |\ ___/ / __ \| Y Y \ +// |____| \___ >____ /__|_| / +// \/ \/ \/ + type AuthorizeType int const ( @@ -192,11 +205,41 @@ func (t *Team) GetMembers() (err error) { } // NewTeam creates a record of new team. +// It's caller's responsibility to assign organization ID. func NewTeam(t *Team) error { - // TODO: check if same name team of organization exists. + has, err := x.Id(t.OrgId).Get(new(User)) + if err != nil { + return err + } else if !has { + return ErrOrgNotExist + } + t.LowerName = strings.ToLower(t.Name) - _, err := x.Insert(t) - return err + has, err = x.Where("org_id=?", t.OrgId).And("lower_name=?", t.LowerName).Get(new(Team)) + if err != nil { + return err + } else if has { + return ErrTeamAlreadyExist + } + + sess := x.NewSession() + defer sess.Close() + if err = sess.Begin(); err != nil { + return err + } + + if _, err = sess.Insert(t); err != nil { + sess.Rollback() + return err + } + + // Update organization number of teams. + rawSql := "UPDATE `user` SET num_teams = num_teams + 1 WHERE id = ?" + if _, err = sess.Exec(rawSql, t.OrgId); err != nil { + sess.Rollback() + return err + } + return sess.Commit() } // UpdateTeam updates information of team. diff --git a/models/repo.go b/models/repo.go index 8eec131f..d95f8b1a 100644 --- a/models/repo.go +++ b/models/repo.go @@ -158,7 +158,7 @@ func IsRepositoryExist(u *User, repoName string) (bool, error) { } var ( - illegalEquals = []string{"raw", "install", "api", "avatar", "user", "org", "help", "stars", "issues", "pulls", "commits", "repo", "template", "admin"} + illegalEquals = []string{"raw", "install", "api", "avatar", "user", "org", "help", "stars", "issues", "pulls", "commits", "repo", "template", "admin", "new"} illegalSuffixs = []string{".git"} ) diff --git a/modules/auth/auth.go b/modules/auth/auth.go index eefb5ed6..e9b21510 100644 --- a/modules/auth/auth.go +++ b/modules/auth/auth.go @@ -7,183 +7,49 @@ package auth import ( "net/http" "reflect" - "strings" "github.com/go-martini/martini" "github.com/gogits/gogs/modules/base" - "github.com/gogits/gogs/modules/log" "github.com/gogits/gogs/modules/middleware/binding" ) -// Web form interface. -type Form interface { - Name(field string) string +type AuthenticationForm struct { + Id int64 `form:"id"` + Type int `form:"type"` + AuthName string `form:"name" binding:"Required;MaxSize(50)"` + Domain string `form:"domain"` + Host string `form:"host"` + Port int `form:"port"` + UseSSL bool `form:"usessl"` + BaseDN string `form:"base_dn"` + Attributes string `form:"attributes"` + Filter string `form:"filter"` + MsAdSA string `form:"ms_ad_sa"` + IsActived bool `form:"is_actived"` + SmtpAuth string `form:"smtpauth"` + SmtpHost string `form:"smtphost"` + SmtpPort int `form:"smtpport"` + Tls bool `form:"tls"` + AllowAutoRegister bool `form:"allowautoregister"` } -type RegisterForm struct { - UserName string `form:"username" binding:"Required;AlphaDashDot;MaxSize(30)"` - Email string `form:"email" binding:"Required;Email;MaxSize(50)"` - Password string `form:"passwd" binding:"Required;MinSize(6);MaxSize(30)"` - RetypePasswd string `form:"retypepasswd"` - LoginType string `form:"logintype"` - LoginName string `form:"loginname"` -} - -func (f *RegisterForm) Name(field string) string { +func (f *AuthenticationForm) Name(field string) string { names := map[string]string{ - "UserName": "Username", - "Email": "E-mail address", - "Password": "Password", - "RetypePasswd": "Re-type password", + "AuthName": "Authentication's name", + "Domain": "Domain name", + "Host": "Host address", + "Port": "Port Number", + "UseSSL": "Use SSL", + "BaseDN": "Base DN", + "Attributes": "Search attributes", + "Filter": "Search filter", + "MsAdSA": "Ms Ad SA", } return names[field] } -func (f *RegisterForm) Validate(errs *binding.Errors, req *http.Request, ctx martini.Context) { - data := ctx.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) - validate(errs, data, f) -} - -type LogInForm struct { - UserName string `form:"username" binding:"Required;MaxSize(35)"` - Password string `form:"passwd" binding:"Required;MinSize(6);MaxSize(30)"` - Remember bool `form:"remember"` -} - -func (f *LogInForm) Name(field string) string { - names := map[string]string{ - "UserName": "Username", - "Password": "Password", - } - return names[field] -} - -func (f *LogInForm) Validate(errs *binding.Errors, req *http.Request, ctx martini.Context) { - data := ctx.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) - validate(errs, data, f) -} - -func GetMinMaxSize(field reflect.StructField) string { - for _, rule := range strings.Split(field.Tag.Get("binding"), ";") { - if strings.HasPrefix(rule, "MinSize(") || strings.HasPrefix(rule, "MaxSize(") { - return rule[8 : len(rule)-1] - } - } - return "" -} - -func validate(errs *binding.Errors, data base.TmplData, f Form) { - if errs.Count() == 0 { - return - } else if len(errs.Overall) > 0 { - for _, err := range errs.Overall { - log.Error("%s: %v", reflect.TypeOf(f), err) - } - return - } - - data["HasError"] = true - AssignForm(f, data) - - typ := reflect.TypeOf(f) - val := reflect.ValueOf(f) - - if typ.Kind() == reflect.Ptr { - typ = typ.Elem() - val = val.Elem() - } - - for i := 0; i < typ.NumField(); i++ { - field := typ.Field(i) - - fieldName := field.Tag.Get("form") - // Allow ignored fields in the struct - if fieldName == "-" { - continue - } - - if err, ok := errs.Fields[field.Name]; ok { - data["Err_"+field.Name] = true - switch err { - case binding.BindingRequireError: - data["ErrorMsg"] = f.Name(field.Name) + " cannot be empty" - case binding.BindingAlphaDashError: - data["ErrorMsg"] = f.Name(field.Name) + " must be valid alpha or numeric or dash(-_) characters" - case binding.BindingAlphaDashDotError: - data["ErrorMsg"] = f.Name(field.Name) + " must be valid alpha or numeric or dash(-_) or dot characters" - case binding.BindingMinSizeError: - data["ErrorMsg"] = f.Name(field.Name) + " must contain at least " + GetMinMaxSize(field) + " characters" - case binding.BindingMaxSizeError: - data["ErrorMsg"] = f.Name(field.Name) + " must contain at most " + GetMinMaxSize(field) + " characters" - case binding.BindingEmailError: - data["ErrorMsg"] = f.Name(field.Name) + " is not a valid e-mail address" - case binding.BindingUrlError: - data["ErrorMsg"] = f.Name(field.Name) + " is not a valid URL" - default: - data["ErrorMsg"] = "Unknown error: " + err - } - return - } - } -} - -// AssignForm assign form values back to the template data. -func AssignForm(form interface{}, data base.TmplData) { - typ := reflect.TypeOf(form) - val := reflect.ValueOf(form) - - if typ.Kind() == reflect.Ptr { - typ = typ.Elem() - val = val.Elem() - } - - for i := 0; i < typ.NumField(); i++ { - field := typ.Field(i) - - fieldName := field.Tag.Get("form") - // Allow ignored fields in the struct - if fieldName == "-" { - continue - } - - data[fieldName] = val.Field(i).Interface() - } -} - -type InstallForm struct { - Database string `form:"database" binding:"Required"` - Host string `form:"host"` - User string `form:"user"` - Passwd string `form:"passwd"` - DatabaseName string `form:"database_name"` - SslMode string `form:"ssl_mode"` - DatabasePath string `form:"database_path"` - RepoRootPath string `form:"repo_path"` - RunUser string `form:"run_user"` - Domain string `form:"domain"` - AppUrl string `form:"app_url"` - AdminName string `form:"admin_name" binding:"Required;AlphaDashDot;MaxSize(30)"` - AdminPasswd string `form:"admin_pwd" binding:"Required;MinSize(6);MaxSize(30)"` - AdminEmail string `form:"admin_email" binding:"Required;Email;MaxSize(50)"` - SmtpHost string `form:"smtp_host"` - SmtpEmail string `form:"mailer_user"` - SmtpPasswd string `form:"mailer_pwd"` - RegisterConfirm string `form:"register_confirm"` - MailNotify string `form:"mail_notify"` -} - -func (f *InstallForm) Name(field string) string { - names := map[string]string{ - "Database": "Database name", - "AdminName": "Admin user name", - "AdminPasswd": "Admin password", - "AdminEmail": "Admin e-maill address", - } - return names[field] -} - -func (f *InstallForm) Validate(errors *binding.Errors, req *http.Request, context martini.Context) { +func (f *AuthenticationForm) Validate(errors *binding.Errors, req *http.Request, context martini.Context) { data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) validate(errors, data, f) } diff --git a/modules/auth/authentication.go b/modules/auth/authentication.go deleted file mode 100644 index e9b21510..00000000 --- a/modules/auth/authentication.go +++ /dev/null @@ -1,55 +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 auth - -import ( - "net/http" - "reflect" - - "github.com/go-martini/martini" - - "github.com/gogits/gogs/modules/base" - "github.com/gogits/gogs/modules/middleware/binding" -) - -type AuthenticationForm struct { - Id int64 `form:"id"` - Type int `form:"type"` - AuthName string `form:"name" binding:"Required;MaxSize(50)"` - Domain string `form:"domain"` - Host string `form:"host"` - Port int `form:"port"` - UseSSL bool `form:"usessl"` - BaseDN string `form:"base_dn"` - Attributes string `form:"attributes"` - Filter string `form:"filter"` - MsAdSA string `form:"ms_ad_sa"` - IsActived bool `form:"is_actived"` - SmtpAuth string `form:"smtpauth"` - SmtpHost string `form:"smtphost"` - SmtpPort int `form:"smtpport"` - Tls bool `form:"tls"` - AllowAutoRegister bool `form:"allowautoregister"` -} - -func (f *AuthenticationForm) Name(field string) string { - names := map[string]string{ - "AuthName": "Authentication's name", - "Domain": "Domain name", - "Host": "Host address", - "Port": "Port Number", - "UseSSL": "Use SSL", - "BaseDN": "Base DN", - "Attributes": "Search attributes", - "Filter": "Search filter", - "MsAdSA": "Ms Ad SA", - } - return names[field] -} - -func (f *AuthenticationForm) Validate(errors *binding.Errors, req *http.Request, context martini.Context) { - data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) - validate(errors, data, f) -} diff --git a/modules/auth/org.go b/modules/auth/org.go index f87d10a7..e243627e 100644 --- a/modules/auth/org.go +++ b/modules/auth/org.go @@ -14,6 +14,13 @@ import ( "github.com/gogits/gogs/modules/middleware/binding" ) +// ________ .__ __ .__ +// \_____ \_______ _________ ____ |__|____________ _/ |_|__| ____ ____ +// / | \_ __ \/ ___\__ \ / \| \___ /\__ \\ __\ |/ _ \ / \ +// / | \ | \/ /_/ > __ \| | \ |/ / / __ \| | | ( <_> ) | \ +// \_______ /__| \___ (____ /___| /__/_____ \(____ /__| |__|\____/|___| / +// \/ /_____/ \/ \/ \/ \/ \/ + type CreateOrgForm struct { OrgName string `form:"orgname" binding:"Required;AlphaDashDot;MaxSize(30)"` Email string `form:"email" binding:"Required;Email;MaxSize(50)"` @@ -55,3 +62,29 @@ func (f *OrgSettingForm) Validate(errors *binding.Errors, req *http.Request, con data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) validate(errors, data, f) } + +// ___________ +// \__ ___/___ _____ _____ +// | |_/ __ \\__ \ / \ +// | |\ ___/ / __ \| Y Y \ +// |____| \___ >____ /__|_| / +// \/ \/ \/ + +type CreateTeamForm struct { + TeamName string `form:"name" binding:"Required;AlphaDashDot;MaxSize(30)"` + Description string `form:"desc" binding:"MaxSize(255)"` + Permission string `form:"permission"` +} + +func (f *CreateTeamForm) Name(field string) string { + names := map[string]string{ + "TeamName": "Team name", + "Description": "Team description", + } + return names[field] +} + +func (f *CreateTeamForm) Validate(errs *binding.Errors, req *http.Request, ctx martini.Context) { + data := ctx.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) + validate(errs, data, f) +} diff --git a/modules/auth/user.go b/modules/auth/user.go index 4a781acf..dfb969e8 100644 --- a/modules/auth/user.go +++ b/modules/auth/user.go @@ -7,6 +7,7 @@ package auth import ( "net/http" "reflect" + "strings" "github.com/go-martini/martini" @@ -19,6 +20,178 @@ import ( "github.com/gogits/gogs/modules/setting" ) +// Web form interface. +type Form interface { + Name(field string) string +} + +type RegisterForm struct { + UserName string `form:"username" binding:"Required;AlphaDashDot;MaxSize(30)"` + Email string `form:"email" binding:"Required;Email;MaxSize(50)"` + Password string `form:"passwd" binding:"Required;MinSize(6);MaxSize(30)"` + RetypePasswd string `form:"retypepasswd"` + LoginType string `form:"logintype"` + LoginName string `form:"loginname"` +} + +func (f *RegisterForm) Name(field string) string { + names := map[string]string{ + "UserName": "Username", + "Email": "E-mail address", + "Password": "Password", + "RetypePasswd": "Re-type password", + } + return names[field] +} + +func (f *RegisterForm) Validate(errs *binding.Errors, req *http.Request, ctx martini.Context) { + data := ctx.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) + validate(errs, data, f) +} + +type LogInForm struct { + UserName string `form:"username" binding:"Required;MaxSize(35)"` + Password string `form:"passwd" binding:"Required;MinSize(6);MaxSize(30)"` + Remember bool `form:"remember"` +} + +func (f *LogInForm) Name(field string) string { + names := map[string]string{ + "UserName": "Username", + "Password": "Password", + } + return names[field] +} + +func (f *LogInForm) Validate(errs *binding.Errors, req *http.Request, ctx martini.Context) { + data := ctx.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) + validate(errs, data, f) +} + +func GetMinMaxSize(field reflect.StructField) string { + for _, rule := range strings.Split(field.Tag.Get("binding"), ";") { + if strings.HasPrefix(rule, "MinSize(") || strings.HasPrefix(rule, "MaxSize(") { + return rule[8 : len(rule)-1] + } + } + return "" +} + +func validate(errs *binding.Errors, data base.TmplData, f Form) { + if errs.Count() == 0 { + return + } else if len(errs.Overall) > 0 { + for _, err := range errs.Overall { + log.Error("%s: %v", reflect.TypeOf(f), err) + } + return + } + + data["HasError"] = true + AssignForm(f, data) + + typ := reflect.TypeOf(f) + val := reflect.ValueOf(f) + + if typ.Kind() == reflect.Ptr { + typ = typ.Elem() + val = val.Elem() + } + + for i := 0; i < typ.NumField(); i++ { + field := typ.Field(i) + + fieldName := field.Tag.Get("form") + // Allow ignored fields in the struct + if fieldName == "-" { + continue + } + + if err, ok := errs.Fields[field.Name]; ok { + data["Err_"+field.Name] = true + switch err { + case binding.BindingRequireError: + data["ErrorMsg"] = f.Name(field.Name) + " cannot be empty" + case binding.BindingAlphaDashError: + data["ErrorMsg"] = f.Name(field.Name) + " must be valid alpha or numeric or dash(-_) characters" + case binding.BindingAlphaDashDotError: + data["ErrorMsg"] = f.Name(field.Name) + " must be valid alpha or numeric or dash(-_) or dot characters" + case binding.BindingMinSizeError: + data["ErrorMsg"] = f.Name(field.Name) + " must contain at least " + GetMinMaxSize(field) + " characters" + case binding.BindingMaxSizeError: + data["ErrorMsg"] = f.Name(field.Name) + " must contain at most " + GetMinMaxSize(field) + " characters" + case binding.BindingEmailError: + data["ErrorMsg"] = f.Name(field.Name) + " is not a valid e-mail address" + case binding.BindingUrlError: + data["ErrorMsg"] = f.Name(field.Name) + " is not a valid URL" + default: + data["ErrorMsg"] = "Unknown error: " + err + } + return + } + } +} + +// AssignForm assign form values back to the template data. +func AssignForm(form interface{}, data base.TmplData) { + typ := reflect.TypeOf(form) + val := reflect.ValueOf(form) + + if typ.Kind() == reflect.Ptr { + typ = typ.Elem() + val = val.Elem() + } + + for i := 0; i < typ.NumField(); i++ { + field := typ.Field(i) + + fieldName := field.Tag.Get("form") + // Allow ignored fields in the struct + if fieldName == "-" { + continue + } + + data[fieldName] = val.Field(i).Interface() + } +} + +type InstallForm struct { + Database string `form:"database" binding:"Required"` + Host string `form:"host"` + User string `form:"user"` + Passwd string `form:"passwd"` + DatabaseName string `form:"database_name"` + SslMode string `form:"ssl_mode"` + DatabasePath string `form:"database_path"` + RepoRootPath string `form:"repo_path"` + RunUser string `form:"run_user"` + Domain string `form:"domain"` + AppUrl string `form:"app_url"` + AdminName string `form:"admin_name" binding:"Required;AlphaDashDot;MaxSize(30)"` + AdminPasswd string `form:"admin_pwd" binding:"Required;MinSize(6);MaxSize(30)"` + AdminEmail string `form:"admin_email" binding:"Required;Email;MaxSize(50)"` + SmtpHost string `form:"smtp_host"` + SmtpEmail string `form:"mailer_user"` + SmtpPasswd string `form:"mailer_pwd"` + RegisterConfirm string `form:"register_confirm"` + MailNotify string `form:"mail_notify"` +} + +func (f *InstallForm) Name(field string) string { + names := map[string]string{ + "Database": "Database name", + "AdminName": "Admin user name", + "AdminPasswd": "Admin password", + "AdminEmail": "Admin e-maill address", + } + return names[field] +} + +func (f *InstallForm) Validate(errors *binding.Errors, req *http.Request, context martini.Context) { + data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) + validate(errors, data, f) +} + // SignedInId returns the id of signed in user. func SignedInId(header http.Header, sess session.SessionStore) int64 { if !models.HasEngine { diff --git a/routers/org/teams.go b/routers/org/teams.go index eef6a634..49273925 100644 --- a/routers/org/teams.go +++ b/routers/org/teams.go @@ -8,12 +8,15 @@ import ( "github.com/go-martini/martini" "github.com/gogits/gogs/models" + "github.com/gogits/gogs/modules/auth" "github.com/gogits/gogs/modules/base" + "github.com/gogits/gogs/modules/log" "github.com/gogits/gogs/modules/middleware" ) const ( - TEAMS base.TplName = "org/teams" + TEAMS base.TplName = "org/teams" + TEAM_NEW base.TplName = "org/team_new" ) func Teams(ctx *middleware.Context, params martini.Params) { @@ -46,8 +49,80 @@ func Teams(ctx *middleware.Context, params martini.Params) { } func NewTeam(ctx *middleware.Context, params martini.Params) { - ctx.Data["Title"] = "Organization " + params["org"] + " New Team" - ctx.HTML(200, "org/new_team") + org, err := models.GetUserByName(params["org"]) + if err != nil { + if err == models.ErrUserNotExist { + ctx.Handle(404, "org.NewTeam(GetUserByName)", err) + } else { + ctx.Handle(500, "org.NewTeam(GetUserByName)", err) + } + return + } + ctx.Data["Org"] = org + + // Check ownership of organization. + if !org.IsOrgOwner(ctx.User.Id) { + ctx.Error(403) + return + } + + ctx.HTML(200, TEAM_NEW) +} + +func NewTeamPost(ctx *middleware.Context, params martini.Params, form auth.CreateTeamForm) { + org, err := models.GetUserByName(params["org"]) + if err != nil { + if err == models.ErrUserNotExist { + ctx.Handle(404, "org.NewTeamPost(GetUserByName)", err) + } else { + ctx.Handle(500, "org.NewTeamPost(GetUserByName)", err) + } + return + } + ctx.Data["Org"] = org + + // Check ownership of organization. + if !org.IsOrgOwner(ctx.User.Id) { + ctx.Error(403) + return + } + + if ctx.HasError() { + ctx.HTML(200, TEAM_NEW) + return + } + + // 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 := &models.Team{ + OrgId: org.Id, + Name: form.TeamName, + Description: form.Description, + Authorize: auth, + } + if err = models.NewTeam(t); err != nil { + if err == models.ErrTeamAlreadyExist { + ctx.Data["Err_TeamName"] = true + ctx.RenderWithErr("Team name has already been used", TEAM_NEW, &form) + } else { + ctx.Handle(500, "org.NewTeamPost(NewTeam)", err) + } + return + } + log.Trace("%s Team created: %s/%s", ctx.Req.RequestURI, org.Name, t.Name) + ctx.Redirect("/org/" + org.LowerName + "/teams/" + t.LowerName) } func EditTeam(ctx *middleware.Context, params martini.Params) { diff --git a/templates/VERSION b/templates/VERSION index eccb7a39..8777e130 100644 --- a/templates/VERSION +++ b/templates/VERSION @@ -1 +1 @@ -0.4.5.0629 Alpha \ No newline at end of file +0.4.5.0702 Alpha \ No newline at end of file diff --git a/templates/org/new.tmpl b/templates/org/new.tmpl index bb46db4a..870f3982 100644 --- a/templates/org/new.tmpl +++ b/templates/org/new.tmpl @@ -13,7 +13,7 @@ -
+
diff --git a/templates/org/new_team.tmpl b/templates/org/team_new.tmpl similarity index 64% rename from templates/org/new_team.tmpl rename to templates/org/team_new.tmpl index 752f37d2..0936ec29 100644 --- a/templates/org/new_team.tmpl +++ b/templates/org/team_new.tmpl @@ -4,58 +4,63 @@
- +
-

Organization Name

+

{{.Org.FullName}}

+
-
+ + {{.CsrfTokenHtml}}

Create new team

-
+ {{template "base/alert" .}} +
- + You'll use this name to mention this team in conversations.
-
+ +
- +
-
+ +

This team will be able to view and clone its repositories.

This team will be able to read its repositories, as well as push to them.

This team will be able to push/pull to its repositories, as well as add other collaborators to them.

diff --git a/templates/org/teams.tmpl b/templates/org/teams.tmpl index 6f00db51..decfecf5 100644 --- a/templates/org/teams.tmpl +++ b/templates/org/teams.tmpl @@ -18,6 +18,7 @@
+