From 19e910428951135b9a341554dad54a6546d2ad50 Mon Sep 17 00:00:00 2001 From: Unknown Date: Fri, 27 Jun 2014 03:37:01 -0400 Subject: [PATCH] Organization settings page --- cmd/web.go | 5 +- gogs.go | 2 +- models/org.go | 86 +++++++++++++ models/repo.go | 2 +- models/user.go | 114 ++++-------------- modules/auth/org.go | 30 ++++- modules/auth/repo.go | 2 +- modules/auth/user.go | 2 +- routers/org/org.go | 56 ++++++++- templates/VERSION | 2 +- templates/org/{setting.tmpl => settings.tmpl} | 56 +++------ 11 files changed, 217 insertions(+), 140 deletions(-) rename templates/org/{setting.tmpl => settings.tmpl} (72%) diff --git a/cmd/web.go b/cmd/web.go index 878fdeac7..729a1ba28 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -190,12 +190,13 @@ func runWeb(*cli.Context) { m.Group("/org", func(r martini.Router) { r.Get("/create", org.New) - r.Post("/create", bindIgnErr(auth.CreateOrganizationForm{}), org.NewPost) + r.Post("/create", bindIgnErr(auth.CreateOrgForm{}), org.NewPost) r.Get("/:org", org.Organization) r.Get("/:org/dashboard", org.Dashboard) r.Get("/:org/members", org.Members) r.Get("/:org/teams", org.Teams) - r.Get("/:org/setting", org.Setting) + r.Get("/:org/settings", org.Settings) + r.Post("/:org/settings", bindIgnErr(auth.OrgSettingForm{}), org.SettingsPost) }, reqSignIn) m.Group("/:username/:reponame", func(r martini.Router) { diff --git a/gogs.go b/gogs.go index 5c2c6ed94..d56760ab2 100644 --- a/gogs.go +++ b/gogs.go @@ -17,7 +17,7 @@ import ( "github.com/gogits/gogs/modules/setting" ) -const APP_VER = "0.4.5.0625 Alpha" +const APP_VER = "0.4.5.0627 Alpha" func init() { runtime.GOMAXPROCS(runtime.NumCPU()) diff --git a/models/org.go b/models/org.go index 227151ab0..553a46aa0 100644 --- a/models/org.go +++ b/models/org.go @@ -4,6 +4,88 @@ package models +import ( + "strings" + + "github.com/gogits/gogs/modules/base" +) + +// CreateOrganization creates record of a new organization. +func CreateOrganization(org, owner *User) (*User, error) { + if !IsLegalName(org.Name) { + return nil, ErrUserNameIllegal + } + + isExist, err := IsUserExist(org.Name) + if err != nil { + return nil, err + } else if isExist { + return nil, ErrUserAlreadyExist + } + + isExist, err = IsEmailUsed(org.Email) + if err != nil { + return nil, err + } else if isExist { + return nil, ErrEmailAlreadyUsed + } + + org.LowerName = strings.ToLower(org.Name) + org.FullName = org.Name + org.Avatar = base.EncodeMd5(org.Email) + org.AvatarEmail = org.Email + // No password for organization. + org.NumTeams = 1 + org.NumMembers = 1 + + sess := x.NewSession() + defer sess.Close() + if err = sess.Begin(); err != nil { + return nil, err + } + + if _, err = sess.Insert(org); err != nil { + sess.Rollback() + return nil, err + } + + // Create default owner team. + t := &Team{ + OrgId: org.Id, + Name: OWNER_TEAM, + Authorize: ORG_ADMIN, + NumMembers: 1, + } + if _, err = sess.Insert(t); err != nil { + sess.Rollback() + return nil, err + } + + // Add initial creator to organization and owner team. + ou := &OrgUser{ + Uid: owner.Id, + OrgId: org.Id, + IsOwner: true, + NumTeam: 1, + } + if _, err = sess.Insert(ou); err != nil { + sess.Rollback() + return nil, err + } + + tu := &TeamUser{ + Uid: owner.Id, + OrgId: org.Id, + TeamId: t.Id, + } + if _, err = sess.Insert(tu); err != nil { + sess.Rollback() + return nil, err + } + + return org, sess.Commit() +} + type AuthorizeType int const ( @@ -72,6 +154,10 @@ func GetOrgUsersByOrgId(orgId int64) ([]*OrgUser, error) { return ous, err } +func GetOrganizationCount(u *User) (int64, error) { + return x.Where("uid=?", u.Id).Count(new(OrgUser)) +} + // ___________ ____ ___ // \__ ___/___ _____ _____ | | \______ ___________ // | |_/ __ \\__ \ / \| | / ___// __ \_ __ \ diff --git a/models/repo.go b/models/repo.go index 840529b95..85f2a913d 100644 --- a/models/repo.go +++ b/models/repo.go @@ -240,7 +240,7 @@ func MirrorUpdate() { "git", "remote", "update"); err != nil { return errors.New("git remote update: " + stderr) } else if err = git.UnpackRefs(repoPath); err != nil { - return err + return errors.New("UnpackRefs: " + err.Error()) } m.NextUpdate = time.Now().Add(time.Duration(m.Interval) * time.Hour) diff --git a/models/user.go b/models/user.go index f67911ca6..8ffad2663 100644 --- a/models/user.go +++ b/models/user.go @@ -30,6 +30,7 @@ const ( var ( ErrUserOwnRepos = errors.New("User still have ownership of repositories") + ErrUserHasOrgs = errors.New("User still have membership of organization") ErrUserAlreadyExist = errors.New("User already exist") ErrUserNotExist = errors.New("User does not exist") ErrUserNotKeyOwner = errors.New("User does not the owner of public key") @@ -69,8 +70,9 @@ type User struct { Updated time.Time `xorm:"updated"` // For organization. - NumTeams int - NumMembers int + Description string + NumTeams int + NumMembers int } // HomeLink returns the user home page link. @@ -211,81 +213,6 @@ func CreateUser(u *User) (*User, error) { return u, err } -// CreateOrganization creates record of a new organization. -func CreateOrganization(org, owner *User) (*User, error) { - if !IsLegalName(org.Name) { - return nil, ErrUserNameIllegal - } - - isExist, err := IsUserExist(org.Name) - if err != nil { - return nil, err - } else if isExist { - return nil, ErrUserAlreadyExist - } - - isExist, err = IsEmailUsed(org.Email) - if err != nil { - return nil, err - } else if isExist { - return nil, ErrEmailAlreadyUsed - } - - org.LowerName = strings.ToLower(org.Name) - org.Avatar = base.EncodeMd5(org.Email) - org.AvatarEmail = org.Email - // No password for organization. - org.NumTeams = 1 - org.NumMembers = 1 - - sess := x.NewSession() - defer sess.Close() - if err = sess.Begin(); err != nil { - return nil, err - } - - if _, err = sess.Insert(org); err != nil { - sess.Rollback() - return nil, err - } - - // Create default owner team. - t := &Team{ - OrgId: org.Id, - Name: OWNER_TEAM, - Authorize: ORG_ADMIN, - NumMembers: 1, - } - if _, err = sess.Insert(t); err != nil { - sess.Rollback() - return nil, err - } - - // Add initial creator to organization and owner team. - ou := &OrgUser{ - Uid: owner.Id, - OrgId: org.Id, - IsOwner: true, - NumTeam: 1, - } - if _, err = sess.Insert(ou); err != nil { - sess.Rollback() - return nil, err - } - - tu := &TeamUser{ - Uid: owner.Id, - OrgId: org.Id, - TeamId: t.Id, - } - if _, err = sess.Insert(tu); err != nil { - sess.Rollback() - return nil, err - } - - return org, sess.Commit() -} - // GetUsers returns given number of user objects with offset. func GetUsers(num, offset int) ([]User, error) { users := make([]User, 0, num) @@ -392,51 +319,62 @@ func UpdateUser(u *User) (err error) { if len(u.Website) > 255 { u.Website = u.Website[:255] } + if len(u.Description) > 255 { + u.Description = u.Description[:255] + } _, err = x.Id(u.Id).AllCols().Update(u) return err } // DeleteUser completely deletes everything of the user. -func DeleteUser(user *User) error { +func DeleteUser(u *User) error { // Check ownership of repository. - count, err := GetRepositoryCount(user) + count, err := GetRepositoryCount(u) if err != nil { - return errors.New("modesl.GetRepositories: " + err.Error()) + return errors.New("modesl.GetRepositories(GetRepositoryCount): " + err.Error()) } else if count > 0 { return ErrUserOwnRepos } + // Check membership of organization. + count, err = GetOrganizationCount(u) + if err != nil { + return errors.New("modesl.GetRepositories(GetOrganizationCount): " + err.Error()) + } else if count > 0 { + return ErrUserHasOrgs + } + // TODO: check issues, other repos' commits // Delete all followers. - if _, err = x.Delete(&Follow{FollowId: user.Id}); err != nil { + if _, err = x.Delete(&Follow{FollowId: u.Id}); err != nil { return err } // Delete oauth2. - if _, err = x.Delete(&Oauth2{Uid: user.Id}); err != nil { + if _, err = x.Delete(&Oauth2{Uid: u.Id}); err != nil { return err } // Delete all feeds. - if _, err = x.Delete(&Action{UserId: user.Id}); err != nil { + if _, err = x.Delete(&Action{UserId: u.Id}); err != nil { return err } // Delete all watches. - if _, err = x.Delete(&Watch{UserId: user.Id}); err != nil { + if _, err = x.Delete(&Watch{UserId: u.Id}); err != nil { return err } // Delete all accesses. - if _, err = x.Delete(&Access{UserName: user.LowerName}); err != nil { + if _, err = x.Delete(&Access{UserName: u.LowerName}); err != nil { return err } // Delete all SSH keys. keys := make([]*PublicKey, 0, 10) - if err = x.Find(&keys, &PublicKey{OwnerId: user.Id}); err != nil { + if err = x.Find(&keys, &PublicKey{OwnerId: u.Id}); err != nil { return err } for _, key := range keys { @@ -446,11 +384,11 @@ func DeleteUser(user *User) error { } // Delete user directory. - if err = os.RemoveAll(UserPath(user.Name)); err != nil { + if err = os.RemoveAll(UserPath(u.Name)); err != nil { return err } - _, err = x.Delete(user) + _, err = x.Delete(u) return err } diff --git a/modules/auth/org.go b/modules/auth/org.go index a60fbb851..f87d10a70 100644 --- a/modules/auth/org.go +++ b/modules/auth/org.go @@ -14,12 +14,12 @@ import ( "github.com/gogits/gogs/modules/middleware/binding" ) -type CreateOrganizationForm struct { +type CreateOrgForm struct { OrgName string `form:"orgname" binding:"Required;AlphaDashDot;MaxSize(30)"` Email string `form:"email" binding:"Required;Email;MaxSize(50)"` } -func (f *CreateOrganizationForm) Name(field string) string { +func (f *CreateOrgForm) Name(field string) string { names := map[string]string{ "OrgName": "Organization name", "Email": "E-mail address", @@ -27,7 +27,31 @@ func (f *CreateOrganizationForm) Name(field string) string { return names[field] } -func (f *CreateOrganizationForm) Validate(errs *binding.Errors, req *http.Request, ctx martini.Context) { +func (f *CreateOrgForm) 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 OrgSettingForm struct { + DisplayName string `form:"display_name" binding:"Required;MaxSize(100)"` + Email string `form:"email" binding:"Required;Email;MaxSize(50)"` + Description string `form:"desc" binding:"MaxSize(255)"` + Website string `form:"site" binding:"Url;MaxSize(100)"` + Location string `form:"location" binding:"MaxSize(50)"` +} + +func (f *OrgSettingForm) Name(field string) string { + names := map[string]string{ + "DisplayName": "Display name", + "Email": "E-mail address", + "Description": "Description", + "Website": "Website address", + "Location": "Location", + } + return names[field] +} + +func (f *OrgSettingForm) 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/repo.go b/modules/auth/repo.go index db13743de..d3d215322 100644 --- a/modules/auth/repo.go +++ b/modules/auth/repo.go @@ -71,7 +71,7 @@ func (f *MigrateRepoForm) Validate(errors *binding.Errors, req *http.Request, co type RepoSettingForm struct { RepoName string `form:"name" binding:"Required;AlphaDash;MaxSize(100)"` - Description string `form:"desc" binding:"MaxSize(100)"` + Description string `form:"desc" binding:"MaxSize(255)"` Website string `form:"site" binding:"Url;MaxSize(100)"` Branch string `form:"branch"` Interval int `form:"interval"` diff --git a/modules/auth/user.go b/modules/auth/user.go index 20f993362..4a781acfa 100644 --- a/modules/auth/user.go +++ b/modules/auth/user.go @@ -93,7 +93,7 @@ func (f *UpdateProfileForm) Name(field string) string { names := map[string]string{ "UserName": "Username", "Email": "E-mail address", - "Website": "Website", + "Website": "Website address", "Location": "Location", "Avatar": "Gravatar Email", } diff --git a/routers/org/org.go b/routers/org/org.go index 0595a81b3..4f57b9a96 100644 --- a/routers/org/org.go +++ b/routers/org/org.go @@ -16,7 +16,8 @@ import ( ) const ( - NEW base.TplName = "org/new" + NEW base.TplName = "org/new" + SETTINGS base.TplName = "org/settings" ) func Organization(ctx *middleware.Context, params martini.Params) { @@ -39,7 +40,7 @@ func New(ctx *middleware.Context) { ctx.HTML(200, NEW) } -func NewPost(ctx *middleware.Context, form auth.CreateOrganizationForm) { +func NewPost(ctx *middleware.Context, form auth.CreateOrgForm) { ctx.Data["Title"] = "Create An Organization" if ctx.HasError() { @@ -114,7 +115,52 @@ func Dashboard(ctx *middleware.Context, params martini.Params) { ctx.HTML(200, user.DASHBOARD) } -func Setting(ctx *middleware.Context, param martini.Params) { - ctx.Data["Title"] = "Setting" - ctx.HTML(200, "org/setting") +func Settings(ctx *middleware.Context, params martini.Params) { + ctx.Data["Title"] = "Settings" + + org, err := models.GetUserByName(params["org"]) + if err != nil { + if err == models.ErrUserNotExist { + ctx.Handle(404, "org.Settings(GetUserByName)", err) + } else { + ctx.Handle(500, "org.Settings(GetUserByName)", err) + } + return + } + ctx.Data["Org"] = org + + ctx.HTML(200, SETTINGS) +} + +func SettingsPost(ctx *middleware.Context, params martini.Params, form auth.OrgSettingForm) { + ctx.Data["Title"] = "Settings" + + org, err := models.GetUserByName(params["org"]) + if err != nil { + if err == models.ErrUserNotExist { + ctx.Handle(404, "org.SettingsPost(GetUserByName)", err) + } else { + ctx.Handle(500, "org.SettingsPost(GetUserByName)", err) + } + return + } + ctx.Data["Org"] = org + + if ctx.HasError() { + ctx.HTML(200, SETTINGS) + return + } + + org.FullName = form.DisplayName + org.Email = form.Email + org.Description = form.Description + org.Website = form.Website + org.Location = form.Location + if err = models.UpdateUser(org); err != nil { + ctx.Handle(500, "org.SettingsPost(UpdateUser)", err) + return + } + log.Trace("%s Organization setting updated: %s", ctx.Req.RequestURI, org.LowerName) + ctx.Flash.Success("Organization profile has been successfully updated.") + ctx.Redirect("/org/" + org.Name + "/settings") } diff --git a/templates/VERSION b/templates/VERSION index b5cda695b..be0ebee0f 100644 --- a/templates/VERSION +++ b/templates/VERSION @@ -1 +1 @@ -0.4.5.0625 Alpha \ No newline at end of file +0.4.5.0627 Alpha \ No newline at end of file diff --git a/templates/org/setting.tmpl b/templates/org/settings.tmpl similarity index 72% rename from templates/org/setting.tmpl rename to templates/org/settings.tmpl index 1be9707a1..e19c027d4 100644 --- a/templates/org/setting.tmpl +++ b/templates/org/settings.tmpl @@ -4,32 +4,20 @@
-
+
    @@ -40,52 +28,46 @@ {{template "base/alert" .}}
    - Repository Options + Organization Options
    -
    + {{.CsrfTokenHtml}} -
    - - +
    +
    - +
    -
    +
    -
    - +
    -
    +
    -
    - +
    -
    +
    -
    - +
    -
    +
    -
    - +