| @@ -630,7 +630,6 @@ release.tag_name_already_exist = Release with this tag name has already existed. | |||||
| [org] | [org] | ||||
| org_name_holder = Organization Name | org_name_holder = Organization Name | ||||
| org_name_helper = Great organization names are short and memorable. | org_name_helper = Great organization names are short and memorable. | ||||
| org_email_helper = Organization's E-mail receives all notifications and confirmations. | |||||
| create_org = Create Organization | create_org = Create Organization | ||||
| repo_updated = Updated | repo_updated = Updated | ||||
| people = People | people = People | ||||
| @@ -9,8 +9,6 @@ import ( | |||||
| "fmt" | "fmt" | ||||
| "os" | "os" | ||||
| "strings" | "strings" | ||||
| "github.com/gogits/gogs/modules/base" | |||||
| ) | ) | ||||
| var ( | var ( | ||||
| @@ -93,17 +91,6 @@ func (org *User) RemoveOrgRepo(repoID int64) error { | |||||
| return org.removeOrgRepo(x, repoID) | return org.removeOrgRepo(x, repoID) | ||||
| } | } | ||||
| // IsOrgEmailUsed returns true if the e-mail has been used in organization account. | |||||
| func IsOrgEmailUsed(email string) (bool, error) { | |||||
| if len(email) == 0 { | |||||
| return false, nil | |||||
| } | |||||
| return x.Get(&User{ | |||||
| Email: email, | |||||
| Type: ORGANIZATION, | |||||
| }) | |||||
| } | |||||
| // CreateOrganization creates record of a new organization. | // CreateOrganization creates record of a new organization. | ||||
| func CreateOrganization(org, owner *User) (err error) { | func CreateOrganization(org, owner *User) (err error) { | ||||
| if err = IsUsableName(org.Name); err != nil { | if err = IsUsableName(org.Name); err != nil { | ||||
| @@ -117,18 +104,9 @@ func CreateOrganization(org, owner *User) (err error) { | |||||
| return ErrUserAlreadyExist{org.Name} | return ErrUserAlreadyExist{org.Name} | ||||
| } | } | ||||
| isExist, err = IsOrgEmailUsed(org.Email) | |||||
| if err != nil { | |||||
| return err | |||||
| } else if isExist { | |||||
| return ErrEmailAlreadyUsed{org.Email} | |||||
| } | |||||
| org.LowerName = strings.ToLower(org.Name) | org.LowerName = strings.ToLower(org.Name) | ||||
| org.FullName = org.Name | org.FullName = org.Name | ||||
| org.Avatar = base.EncodeMd5(org.Email) | |||||
| org.AvatarEmail = org.Email | |||||
| // No password for organization. | |||||
| org.UseCustomAvatar = true | |||||
| org.NumTeams = 1 | org.NumTeams = 1 | ||||
| org.NumMembers = 1 | org.NumMembers = 1 | ||||
| @@ -141,6 +119,17 @@ func CreateOrganization(org, owner *User) (err error) { | |||||
| if _, err = sess.Insert(org); err != nil { | if _, err = sess.Insert(org); err != nil { | ||||
| return fmt.Errorf("insert organization: %v", err) | return fmt.Errorf("insert organization: %v", err) | ||||
| } | } | ||||
| org.GenerateRandomAvatar() | |||||
| // Add initial creator to organization and owner team. | |||||
| if _, err = sess.Insert(&OrgUser{ | |||||
| Uid: owner.Id, | |||||
| OrgID: org.Id, | |||||
| IsOwner: true, | |||||
| NumTeams: 1, | |||||
| }); err != nil { | |||||
| return fmt.Errorf("insert org-user relation: %v", err) | |||||
| } | |||||
| // Create default owner team. | // Create default owner team. | ||||
| t := &Team{ | t := &Team{ | ||||
| @@ -154,23 +143,11 @@ func CreateOrganization(org, owner *User) (err error) { | |||||
| return fmt.Errorf("insert owner team: %v", err) | return fmt.Errorf("insert owner team: %v", err) | ||||
| } | } | ||||
| // Add initial creator to organization and owner team. | |||||
| ou := &OrgUser{ | |||||
| Uid: owner.Id, | |||||
| OrgID: org.Id, | |||||
| IsOwner: true, | |||||
| NumTeams: 1, | |||||
| } | |||||
| if _, err = sess.Insert(ou); err != nil { | |||||
| return fmt.Errorf("insert org-user relation: %v", err) | |||||
| } | |||||
| tu := &TeamUser{ | |||||
| if _, err = sess.Insert(&TeamUser{ | |||||
| Uid: owner.Id, | Uid: owner.Id, | ||||
| OrgID: org.Id, | OrgID: org.Id, | ||||
| TeamID: t.ID, | TeamID: t.ID, | ||||
| } | |||||
| if _, err = sess.Insert(tu); err != nil { | |||||
| }); err != nil { | |||||
| return fmt.Errorf("insert team-user relation: %v", err) | return fmt.Errorf("insert team-user relation: %v", err) | ||||
| } | } | ||||
| @@ -55,12 +55,12 @@ type User struct { | |||||
| Name string `xorm:"UNIQUE NOT NULL"` | Name string `xorm:"UNIQUE NOT NULL"` | ||||
| FullName string | FullName string | ||||
| // Email is the primary email address (to be used for communication). | // Email is the primary email address (to be used for communication). | ||||
| Email string `xorm:"UNIQUE(s) NOT NULL"` | |||||
| Email string `xorm:"NOT NULL"` | |||||
| Passwd string `xorm:"NOT NULL"` | Passwd string `xorm:"NOT NULL"` | ||||
| LoginType LoginType | LoginType LoginType | ||||
| LoginSource int64 `xorm:"NOT NULL DEFAULT 0"` | LoginSource int64 `xorm:"NOT NULL DEFAULT 0"` | ||||
| LoginName string | LoginName string | ||||
| Type UserType `xorm:"UNIQUE(s)"` | |||||
| Type UserType | |||||
| Orgs []*User `xorm:"-"` | Orgs []*User `xorm:"-"` | ||||
| Repos []*Repository `xorm:"-"` | Repos []*Repository `xorm:"-"` | ||||
| Location string | Location string | ||||
| @@ -132,42 +132,56 @@ func (u *User) HomeLink() string { | |||||
| return setting.AppSubUrl + "/" + u.Name | return setting.AppSubUrl + "/" + u.Name | ||||
| } | } | ||||
| // CustomAvatarPath returns user custom avatar file path. | |||||
| func (u *User) CustomAvatarPath() string { | |||||
| return filepath.Join(setting.AvatarUploadPath, com.ToStr(u.Id)) | |||||
| } | |||||
| // GenerateRandomAvatar generates a random avatar for user. | |||||
| func (u *User) GenerateRandomAvatar() error { | |||||
| seed := u.Email | |||||
| if len(seed) == 0 { | |||||
| seed = u.Name | |||||
| } | |||||
| img, err := avatar.RandomImage([]byte(seed)) | |||||
| if err != nil { | |||||
| return fmt.Errorf("RandomImage: %v", err) | |||||
| } | |||||
| if err = os.MkdirAll(path.Dir(u.CustomAvatarPath()), os.ModePerm); err != nil { | |||||
| return fmt.Errorf("MkdirAll: %v", err) | |||||
| } | |||||
| fw, err := os.Create(u.CustomAvatarPath()) | |||||
| if err != nil { | |||||
| return fmt.Errorf("Create: %v", err) | |||||
| } | |||||
| defer fw.Close() | |||||
| if err = jpeg.Encode(fw, img, nil); err != nil { | |||||
| return fmt.Errorf("Encode: %v", err) | |||||
| } | |||||
| log.Info("New random avatar created: %d", u.Id) | |||||
| return nil | |||||
| } | |||||
| func (u *User) RelAvatarLink() string { | func (u *User) RelAvatarLink() string { | ||||
| defaultImgUrl := "/img/avatar_default.jpg" | defaultImgUrl := "/img/avatar_default.jpg" | ||||
| if u.Id == -1 { | if u.Id == -1 { | ||||
| return defaultImgUrl | return defaultImgUrl | ||||
| } | } | ||||
| imgPath := path.Join(setting.AvatarUploadPath, com.ToStr(u.Id)) | |||||
| switch { | switch { | ||||
| case u.UseCustomAvatar: | case u.UseCustomAvatar: | ||||
| if !com.IsExist(imgPath) { | |||||
| if !com.IsExist(u.CustomAvatarPath()) { | |||||
| return defaultImgUrl | return defaultImgUrl | ||||
| } | } | ||||
| return "/avatars/" + com.ToStr(u.Id) | return "/avatars/" + com.ToStr(u.Id) | ||||
| case setting.DisableGravatar, setting.OfflineMode: | case setting.DisableGravatar, setting.OfflineMode: | ||||
| if !com.IsExist(imgPath) { | |||||
| img, err := avatar.RandomImage([]byte(u.Email)) | |||||
| if err != nil { | |||||
| log.Error(3, "RandomImage: %v", err) | |||||
| return defaultImgUrl | |||||
| if !com.IsExist(u.CustomAvatarPath()) { | |||||
| if err := u.GenerateRandomAvatar(); err != nil { | |||||
| log.Error(3, "GenerateRandomAvatar: %v", err) | |||||
| } | } | ||||
| if err = os.MkdirAll(path.Dir(imgPath), os.ModePerm); err != nil { | |||||
| log.Error(3, "MkdirAll: %v", err) | |||||
| return defaultImgUrl | |||||
| } | |||||
| fw, err := os.Create(imgPath) | |||||
| if err != nil { | |||||
| log.Error(3, "Create: %v", err) | |||||
| return defaultImgUrl | |||||
| } | |||||
| defer fw.Close() | |||||
| if err = jpeg.Encode(fw, img, nil); err != nil { | |||||
| log.Error(3, "Encode: %v", err) | |||||
| return defaultImgUrl | |||||
| } | |||||
| log.Info("New random avatar created: %d", u.Id) | |||||
| } | } | ||||
| return "/avatars/" + com.ToStr(u.Id) | return "/avatars/" + com.ToStr(u.Id) | ||||
| @@ -208,11 +222,6 @@ func (u *User) ValidatePassword(passwd string) bool { | |||||
| return u.Passwd == newUser.Passwd | return u.Passwd == newUser.Passwd | ||||
| } | } | ||||
| // CustomAvatarPath returns user custom avatar file path. | |||||
| func (u *User) CustomAvatarPath() string { | |||||
| return filepath.Join(setting.AvatarUploadPath, com.ToStr(u.Id)) | |||||
| } | |||||
| // UploadAvatar saves custom avatar for user. | // UploadAvatar saves custom avatar for user. | ||||
| // FIXME: split uploads to different subdirs in case we have massive users. | // FIXME: split uploads to different subdirs in case we have massive users. | ||||
| func (u *User) UploadAvatar(data []byte) error { | func (u *User) UploadAvatar(data []byte) error { | ||||
| @@ -494,12 +503,20 @@ func ChangeUserName(u *User, newUserName string) (err error) { | |||||
| } | } | ||||
| func updateUser(e Engine, u *User) error { | func updateUser(e Engine, u *User) error { | ||||
| u.Email = strings.ToLower(u.Email) | |||||
| has, err := e.Where("id!=?", u.Id).And("type=?", u.Type).And("email=?", u.Email).Get(new(User)) | |||||
| if err != nil { | |||||
| return err | |||||
| } else if has { | |||||
| return ErrEmailAlreadyUsed{u.Email} | |||||
| // Organization does not need e-mail. | |||||
| if !u.IsOrganization() { | |||||
| u.Email = strings.ToLower(u.Email) | |||||
| has, err := e.Where("id!=?", u.Id).And("type=?", u.Type).And("email=?", u.Email).Get(new(User)) | |||||
| if err != nil { | |||||
| return err | |||||
| } else if has { | |||||
| return ErrEmailAlreadyUsed{u.Email} | |||||
| } | |||||
| if len(u.AvatarEmail) == 0 { | |||||
| u.AvatarEmail = u.Email | |||||
| } | |||||
| u.Avatar = avatar.HashEmail(u.AvatarEmail) | |||||
| } | } | ||||
| u.LowerName = strings.ToLower(u.Name) | u.LowerName = strings.ToLower(u.Name) | ||||
| @@ -514,13 +531,8 @@ func updateUser(e Engine, u *User) error { | |||||
| u.Description = u.Description[:255] | u.Description = u.Description[:255] | ||||
| } | } | ||||
| if u.AvatarEmail == "" { | |||||
| u.AvatarEmail = u.Email | |||||
| } | |||||
| u.Avatar = avatar.HashEmail(u.AvatarEmail) | |||||
| u.FullName = base.Sanitizer.Sanitize(u.FullName) | u.FullName = base.Sanitizer.Sanitize(u.FullName) | ||||
| _, err = e.Id(u.Id).AllCols().Update(u) | |||||
| _, err := e.Id(u.Id).AllCols().Update(u) | |||||
| return err | return err | ||||
| } | } | ||||
| @@ -17,8 +17,7 @@ import ( | |||||
| // \/ /_____/ \/ \/ \/ \/ \/ | // \/ /_____/ \/ \/ \/ \/ \/ | ||||
| type CreateOrgForm struct { | type CreateOrgForm struct { | ||||
| OrgName string `form:"org_name" binding:"Required;AlphaDashDot;MaxSize(30)"` | |||||
| Email string `form:"email" binding:"Required;Email;MaxSize(50)"` | |||||
| OrgName string `binding:"Required;AlphaDashDot;MaxSize(30)"` | |||||
| } | } | ||||
| func (f *CreateOrgForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { | func (f *CreateOrgForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { | ||||
| @@ -28,11 +27,9 @@ func (f *CreateOrgForm) Validate(ctx *macaron.Context, errs binding.Errors) bind | |||||
| type UpdateOrgSettingForm struct { | type UpdateOrgSettingForm struct { | ||||
| OrgUserName string `form:"uname" binding:"Required;AlphaDashDot;MaxSize(30)" locale:"org.org_name_holder"` | OrgUserName string `form:"uname" binding:"Required;AlphaDashDot;MaxSize(30)" locale:"org.org_name_holder"` | ||||
| OrgFullName string `form:"fullname" binding:"MaxSize(100)"` | OrgFullName string `form:"fullname" binding:"MaxSize(100)"` | ||||
| Email string `form:"email" binding:"Required;Email;MaxSize(50)"` | |||||
| Description string `form:"desc" binding:"MaxSize(255)"` | Description string `form:"desc" binding:"MaxSize(255)"` | ||||
| Website string `form:"website" binding:"Url;MaxSize(100)"` | Website string `form:"website" binding:"Url;MaxSize(100)"` | ||||
| Location string `form:"location" binding:"MaxSize(50)"` | Location string `form:"location" binding:"MaxSize(50)"` | ||||
| Avatar string `form:"avatar" binding:"Required;Email;MaxSize(50)"` | |||||
| } | } | ||||
| func (f *UpdateOrgSettingForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { | func (f *UpdateOrgSettingForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { | ||||
| @@ -17,28 +17,41 @@ | |||||
| } | } | ||||
| } | } | ||||
| @create-page-form-input-padding: 250px !important; | |||||
| #create-page-form { | |||||
| form { | |||||
| margin: auto; | |||||
| width: 800px!important; | |||||
| .ui.message { | |||||
| text-align: center; | |||||
| } | |||||
| .header { | |||||
| padding-left: @create-page-form-input-padding+30px; | |||||
| } | |||||
| .inline.field > label { | |||||
| text-align: right; | |||||
| width: @create-page-form-input-padding; | |||||
| word-wrap: break-word; | |||||
| } | |||||
| .help { | |||||
| margin-left: @create-page-form-input-padding+15px; | |||||
| } | |||||
| .optional .title { | |||||
| margin-left: @create-page-form-input-padding; | |||||
| } | |||||
| input, | |||||
| textarea { | |||||
| width: 50%!important; | |||||
| } | |||||
| } | |||||
| } | |||||
| .repository { | .repository { | ||||
| @input-padding: 250px !important; | |||||
| &.new.repo, | &.new.repo, | ||||
| &.new.migrate, | &.new.migrate, | ||||
| &.new.fork { | &.new.fork { | ||||
| #create-page-form; | |||||
| form { | form { | ||||
| margin: auto; | |||||
| width: 800px!important; | |||||
| .ui.message { | |||||
| text-align: center; | |||||
| } | |||||
| .header { | |||||
| padding-left: @input-padding+30px; | |||||
| } | |||||
| .inline.field > label { | |||||
| text-align: right; | |||||
| width: @input-padding; | |||||
| word-wrap: break-word; | |||||
| } | |||||
| .help { | |||||
| margin-left: @input-padding+15px; | |||||
| } | |||||
| .dropdown { | .dropdown { | ||||
| .dropdown.icon { | .dropdown.icon { | ||||
| margin-top: -7px!important; | margin-top: -7px!important; | ||||
| @@ -50,13 +63,6 @@ | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| .optional .title { | |||||
| margin-left: @input-padding; | |||||
| } | |||||
| input, | |||||
| textarea { | |||||
| width: 50%!important; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -66,7 +72,7 @@ | |||||
| width: 50%!important; | width: 50%!important; | ||||
| } | } | ||||
| #auto-init { | #auto-init { | ||||
| margin-left: @input-padding+15px; | |||||
| margin-left: @create-page-form-input-padding+15px; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -14,4 +14,8 @@ | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| &.new.org { | |||||
| #create-page-form; | |||||
| } | |||||
| } | } | ||||
| @@ -59,25 +59,18 @@ func CreatePost(ctx *middleware.Context, form auth.CreateOrgForm) { | |||||
| org := &models.User{ | org := &models.User{ | ||||
| Name: form.OrgName, | Name: form.OrgName, | ||||
| Email: form.Email, | |||||
| IsActive: true, | IsActive: true, | ||||
| Type: models.ORGANIZATION, | Type: models.ORGANIZATION, | ||||
| } | } | ||||
| var err error | |||||
| if err = models.CreateOrganization(org, ctx.User); err != nil { | |||||
| if err := models.CreateOrganization(org, ctx.User); err != nil { | |||||
| ctx.Data["Err_OrgName"] = true | |||||
| switch { | switch { | ||||
| case models.IsErrUserAlreadyExist(err): | case models.IsErrUserAlreadyExist(err): | ||||
| ctx.Data["Err_OrgName"] = true | |||||
| ctx.RenderWithErr(ctx.Tr("form.org_name_been_taken"), CREATE, &form) | ctx.RenderWithErr(ctx.Tr("form.org_name_been_taken"), CREATE, &form) | ||||
| case models.IsErrEmailAlreadyUsed(err): | |||||
| ctx.Data["Err_Email"] = true | |||||
| ctx.RenderWithErr(ctx.Tr("form.email_been_used"), CREATE, &form) | |||||
| case models.IsErrNameReserved(err): | case models.IsErrNameReserved(err): | ||||
| ctx.Data["Err_OrgName"] = true | |||||
| ctx.RenderWithErr(ctx.Tr("org.form.name_reserved", err.(models.ErrNameReserved).Name), CREATE, &form) | ctx.RenderWithErr(ctx.Tr("org.form.name_reserved", err.(models.ErrNameReserved).Name), CREATE, &form) | ||||
| case models.IsErrNamePatternNotAllowed(err): | case models.IsErrNamePatternNotAllowed(err): | ||||
| ctx.Data["Err_OrgName"] = true | |||||
| ctx.RenderWithErr(ctx.Tr("org.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), CREATE, &form) | ctx.RenderWithErr(ctx.Tr("org.form.name_pattern_not_allowed", err.(models.ErrNamePatternNotAllowed).Pattern), CREATE, &form) | ||||
| default: | default: | ||||
| ctx.Handle(500, "CreateOrganization", err) | ctx.Handle(500, "CreateOrganization", err) | ||||
| @@ -61,19 +61,11 @@ func SettingsPost(ctx *middleware.Context, form auth.UpdateOrgSettingForm) { | |||||
| } | } | ||||
| org.FullName = form.OrgFullName | org.FullName = form.OrgFullName | ||||
| org.Email = form.Email | |||||
| org.Description = form.Description | org.Description = form.Description | ||||
| org.Website = form.Website | org.Website = form.Website | ||||
| org.Location = form.Location | org.Location = form.Location | ||||
| org.Avatar = base.EncodeMd5(form.Avatar) | |||||
| org.AvatarEmail = form.Avatar | |||||
| if err := models.UpdateUser(org); err != nil { | if err := models.UpdateUser(org); err != nil { | ||||
| if models.IsErrEmailAlreadyUsed(err) { | |||||
| ctx.Data["Err_Email"] = true | |||||
| ctx.RenderWithErr(ctx.Tr("form.email_been_used"), SETTINGS_OPTIONS, &form) | |||||
| } else { | |||||
| ctx.Handle(500, "UpdateUser", err) | |||||
| } | |||||
| ctx.Handle(500, "UpdateUser", err) | |||||
| return | return | ||||
| } | } | ||||
| log.Trace("Organization setting updated: %s", org.Name) | log.Trace("Organization setting updated: %s", org.Name) | ||||
| @@ -1,31 +1,30 @@ | |||||
| {{template "ng/base/head" .}} | |||||
| {{template "ng/base/header" .}} | |||||
| <div id="sign-wrapper"> | |||||
| <form class="form-align form panel sign-panel sign-form container panel-radius" id="sign-up-form" action="{{AppSubUrl}}/org/create" method="post"> | |||||
| {{template "base/head" .}} | |||||
| <div class="organization new org"> | |||||
| <div class="ui middle very relaxed page grid"> | |||||
| <div class="column"> | |||||
| <form class="ui form" action="{{.Link}}" method="post"> | |||||
| {{.CsrfTokenHtml}} | {{.CsrfTokenHtml}} | ||||
| <div class="panel-header"> | |||||
| <h2>{{.i18n.Tr "new_org"}}</h2> | |||||
| <h3 class="ui top attached header"> | |||||
| {{.i18n.Tr "new_org"}} | |||||
| </h3> | |||||
| <div class="ui attached segment"> | |||||
| {{template "base/alert" .}} | |||||
| <div class="inline required field {{if .Err_OrgName}}error{{end}}"> | |||||
| <label for="org_name">{{.i18n.Tr "org.org_name_holder"}}</label> | |||||
| <input id="org_name" name="org_name" value="{{.org_name}}" autofocus required> | |||||
| <span class="help">{{.i18n.Tr "org.org_name_helper"}}</span> | |||||
| </div> | |||||
| <div class="inline field"> | |||||
| <label></label> | |||||
| <button class="ui green button"> | |||||
| {{.i18n.Tr "org.create_org"}} | |||||
| </button> | |||||
| <a class="ui button" href="{{AppSubUrl}}/">{{.i18n.Tr "cancel"}}</a> | |||||
| </div> | |||||
| </div> | </div> | ||||
| <div class="panel-content"> | |||||
| {{template "ng/base/alert" .}} | |||||
| <div class="field"> | |||||
| <label class="req" for="org_name">{{.i18n.Tr "org.org_name_holder"}}</label> | |||||
| <input class="ipt ipt-large ipt-radius {{if .Err_OrgName}}ipt-error{{end}}" id="org_name" name="org_name" type="text" value="{{.org_name}}" required/> | |||||
| <label></label> | |||||
| <span class="help">{{.i18n.Tr "org.org_name_helper"}}</span> | |||||
| </div> | |||||
| <div class="field"> | |||||
| <label class="req" for="email">{{.i18n.Tr "email"}}</label> | |||||
| <input class="ipt ipt-large ipt-radius {{if .Err_Email}}ipt-error{{end}}" id="email" name="email" type="email" value="{{.email}}" required/> | |||||
| <label></label> | |||||
| <span class="help">{{.i18n.Tr "org.org_email_helper"}}</span> | |||||
| </div> | |||||
| <div class="field"> | |||||
| <span class="form-label"></span> | |||||
| <button class="btn btn-large btn-blue btn-radius">{{.i18n.Tr "org.create_org"}}</button> | |||||
| <a class="btn btn-small btn-gray btn-radius" id="repo-create-cancel" href="{{AppSubUrl}}/"><strong>{{.i18n.Tr "cancel"}}</strong></a> | |||||
| </div> | |||||
| </div> | |||||
| </form> | |||||
| </form> | |||||
| </div> | |||||
| </div> | |||||
| </div> | </div> | ||||
| {{template "ng/base/footer" .}} | |||||
| {{template "base/footer" .}} | |||||
| @@ -30,10 +30,6 @@ | |||||
| <label for="full-name">{{.i18n.Tr "org.settings.full_name"}}</label> | <label for="full-name">{{.i18n.Tr "org.settings.full_name"}}</label> | ||||
| <input class="ipt ipt-large ipt-radius {{if .Err_FullName}}ipt-error{{end}}" id="full-name" name="fullname" value="{{.Org.FullName}}" /> | <input class="ipt ipt-large ipt-radius {{if .Err_FullName}}ipt-error{{end}}" id="full-name" name="fullname" value="{{.Org.FullName}}" /> | ||||
| </div> | </div> | ||||
| <div class="field"> | |||||
| <label class="req" for="email">{{.i18n.Tr "email"}}</label> | |||||
| <input class="ipt ipt-large ipt-radius {{if .Err_Email}}ipt-error{{end}}" id="email" name="email" type="email" value="{{.Org.Email}}" required /> | |||||
| </div> | |||||
| <div class="field clear"> | <div class="field clear"> | ||||
| <label class="left" for="desc">{{.i18n.Tr "org.org_desc"}}</label> | <label class="left" for="desc">{{.i18n.Tr "org.org_desc"}}</label> | ||||
| <textarea class="ipt ipt-large ipt-radius {{if .Err_Description}}ipt-error{{end}}" id="desc" name="desc">{{.Org.Description}}</textarea> | <textarea class="ipt ipt-large ipt-radius {{if .Err_Description}}ipt-error{{end}}" id="desc" name="desc">{{.Org.Description}}</textarea> | ||||
| @@ -46,10 +42,6 @@ | |||||
| <label for="location">{{.i18n.Tr "org.settings.location"}}</label> | <label for="location">{{.i18n.Tr "org.settings.location"}}</label> | ||||
| <input class="ipt ipt-large ipt-radius {{if .Err_Location}}ipt-error{{end}}" id="location" name="location" type="text" value="{{.Org.Location}}" /> | <input class="ipt ipt-large ipt-radius {{if .Err_Location}}ipt-error{{end}}" id="location" name="location" type="text" value="{{.Org.Location}}" /> | ||||
| </div> | </div> | ||||
| <div class="field {{if DisableGravatar}}hide{{end}}"> | |||||
| <label class="req" for="gravatar-email">Gravatar {{.i18n.Tr "email"}}</label> | |||||
| <input class="ipt ipt-large ipt-radius {{if .Err_Avatar}}ipt-error{{end}}" id="gravatar-email" name="avatar" type="text" value="{{.Org.AvatarEmail}}" /> | |||||
| </div> | |||||
| <div class="field"> | <div class="field"> | ||||
| <span class="form-label"></span> | <span class="form-label"></span> | ||||
| <button class="btn btn-green btn-large btn-radius" id="change-orgname-btn" href="#change-orgname-modal">{{.i18n.Tr "org.settings.update_settings"}}</button> | <button class="btn btn-green btn-large btn-radius" id="change-orgname-btn" href="#change-orgname-modal">{{.i18n.Tr "org.settings.update_settings"}}</button> | ||||