| @@ -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) | |||
| @@ -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()) | |||
| @@ -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. | |||
| @@ -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"} | |||
| ) | |||
| @@ -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 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 { | |||
| 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{ | |||
| "Database": "Database name", | |||
| "AdminName": "Admin user name", | |||
| "AdminPasswd": "Admin password", | |||
| "AdminEmail": "Admin e-maill address", | |||
| "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 *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) | |||
| } | |||
| @@ -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) | |||
| } | |||
| @@ -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) | |||
| } | |||
| @@ -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 { | |||
| @@ -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) { | |||
| @@ -1 +1 @@ | |||
| 0.4.5.0629 Alpha | |||
| 0.4.5.0702 Alpha | |||
| @@ -13,7 +13,7 @@ | |||
| </div> | |||
| </div> | |||
| <div class="form-group {{if .Err_Email}}has-error has-feedback{{end}}"> | |||
| <div class="form-group{{if .Err_Email}} has-error has-feedback{{end}}"> | |||
| <label class="col-md-2 control-label">Email<strong class="text-danger">*</strong></label> | |||
| <div class="col-md-8"> | |||
| <input name="email" type="text" class="form-control" placeholder="Type organization's email" value="{{.email}}" required="required"> | |||
| @@ -4,58 +4,63 @@ | |||
| <div class="container clearfix"> | |||
| <div id="org-nav-wrapper"> | |||
| <ul class="nav nav-pills pull-right"> | |||
| <li><a href="#"><i class="fa fa-users"></i>Members | |||
| <span class="label label-default">5</span></a> | |||
| <li><a href="/org/{{.Org.Name}}/members"><i class="fa fa-users"></i>Members | |||
| <span class="label label-default">{{.Org.NumMembers}}</span></a> | |||
| </li> | |||
| <li class="active"><a href="#"><i class="fa fa-tags"></i>Teams | |||
| <span class="label label-default">2</span></a> | |||
| <li class="active"><a href="/org/{{.Org.Name}}/teams"><i class="fa fa-tags"></i>Teams | |||
| <span class="label label-default">{{.Org.NumTeams}}</span></a> | |||
| </li> | |||
| </ul> | |||
| <img class="pull-left org-small-logo" src="https://avatars3.githubusercontent.com/u/6656686?s=140" alt="" width="60"/> | |||
| <img class="pull-left org-small-logo" src="{{.Org.AvatarLink}}?s=140" alt="" width="60"/> | |||
| <div id="org-nav-info"> | |||
| <h2 class="org-name">Organization Name</h2> | |||
| <h2 class="org-name">{{.Org.FullName}}</h2> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div id="body" class="container"> | |||
| <div id="org"> | |||
| <form id="org-teams-create" class="form-horizontal card"> | |||
| <form action="/org/{{.Org.Name}}/teams/new" method="post" id="org-teams-create" class="form-horizontal card"> | |||
| {{.CsrfTokenHtml}} | |||
| <h3>Create new team</h3> | |||
| <div class="form-group"> | |||
| {{template "base/alert" .}} | |||
| <div class="form-group{{if .Err_TeamName}} has-error has-feedback{{end}}"> | |||
| <label class="col-md-2 control-label">Team Name<strong class="text-danger">*</strong></label> | |||
| <div class="col-md-8"> | |||
| <input name="team" type="text" class="form-control" placeholder="Type your team name" value="" required="required"> | |||
| <input name="name" type="text" class="form-control" placeholder="Type your team name" value="{{.name}}" required="required"> | |||
| <span class="help-block">You'll use this name to mention this team in conversations.</span> | |||
| </div> | |||
| </div> | |||
| <div class="form-group"> | |||
| <div class="form-group{{if .Err_Description}} has-error has-feedback{{end}}"> | |||
| <label class="col-md-2 control-label">Description</label> | |||
| <div class="col-md-8"> | |||
| <input name="desc" type="text" class="form-control" placeholder="Type your team description (optional)" value=""> | |||
| <input name="desc" type="text" class="form-control" placeholder="Type your team description (optional)" value="{{.desc}}"> | |||
| </div> | |||
| </div> | |||
| <div class="form-group"> | |||
| <div class="form-group{{if .Err_Permission}} has-error has-feedback{{end}}"> | |||
| <label class="col-md-2 control-label">Permission</label> | |||
| <div class="col-md-8"> | |||
| <div class="radio"> | |||
| <label> | |||
| <input type="radio" name="permission" value="pull" checked=""> | |||
| <strong>Read & Clone</strong> | |||
| <input type="radio" name="permission" value="read" checked=""> | |||
| <strong>Read Access</strong> | |||
| </label> | |||
| <p>This team will be able to view and clone its repositories.</p> | |||
| </div> | |||
| <div class="radio"> | |||
| <label> | |||
| <input type="radio" name="permission" value="push"> | |||
| <strong>Push, Read & Clone</strong> | |||
| <input type="radio" name="permission" value="write"> | |||
| <strong>Write Access</strong> | |||
| </label> | |||
| <p>This team will be able to read its repositories, as well as push to them.</p> | |||
| </div> | |||
| <div class="radio"> | |||
| <label> | |||
| <input type="radio" name="permission" value="admin"> | |||
| <strong>Collaboration, Push, Read & Clone</strong> | |||
| <strong>Admin Access</strong> | |||
| </label> | |||
| <p>This team will be able to push/pull to its repositories, as well as add other collaborators to them.</p> | |||
| </div> | |||
| @@ -18,6 +18,7 @@ | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <div id="body" class="container"> | |||
| <div id="org"> | |||
| <div id="org-teams"> | |||