diff --git a/cmd/web.go b/cmd/web.go index 1668fae2..7387d445 100644 --- a/cmd/web.go +++ b/cmd/web.go @@ -194,13 +194,14 @@ func runWeb(*cli.Context) { r.Get("/:org", org.Organization) r.Get("/:org/dashboard", org.Dashboard) r.Get("/:org/members", org.Members) - // organization teams + r.Get("/:org/teams/:team/edit", org.EditTeam) r.Get("/:org/teams/new", org.NewTeam) r.Get("/:org/teams", org.Teams) r.Get("/:org/settings", org.Settings) r.Post("/:org/settings", bindIgnErr(auth.OrgSettingForm{}), org.SettingsPost) + r.Post("/:org/settings/delete", org.DeletePost) }, reqSignIn) m.Group("/:username/:reponame", func(r martini.Router) { diff --git a/gogs.go b/gogs.go index d56760ab..3ad059bc 100644 --- a/gogs.go +++ b/gogs.go @@ -17,7 +17,7 @@ import ( "github.com/gogits/gogs/modules/setting" ) -const APP_VER = "0.4.5.0627 Alpha" +const APP_VER = "0.4.5.0628 Alpha" func init() { runtime.GOMAXPROCS(runtime.NumCPU()) diff --git a/models/org.go b/models/org.go index 553a46aa..025759b0 100644 --- a/models/org.go +++ b/models/org.go @@ -10,6 +10,16 @@ import ( "github.com/gogits/gogs/modules/base" ) +// GetOwnerTeam returns owner team of organization. +func (org *User) GetOwnerTeam() (*Team, error) { + t := &Team{ + OrgId: org.Id, + Name: OWNER_TEAM, + } + _, err := x.Get(t) + return t, err +} + // CreateOrganization creates record of a new organization. func CreateOrganization(org, owner *User) (*User, error) { if !IsLegalName(org.Name) { @@ -86,6 +96,34 @@ func CreateOrganization(org, owner *User) (*User, error) { return org, sess.Commit() } +// TODO: need some kind of mechanism to record failure. +// DeleteOrganization completely and permanently deletes everything of organization. +func DeleteOrganization(org *User) (err error) { + if err := DeleteUser(org); err != nil { + return err + } + + sess := x.NewSession() + defer sess.Close() + if err = sess.Begin(); err != nil { + return err + } + + if _, err = sess.Delete(&Team{OrgId: org.Id}); err != nil { + sess.Rollback() + return err + } + if _, err = sess.Delete(&OrgUser{OrgId: org.Id}); err != nil { + sess.Rollback() + return err + } + if _, err = sess.Delete(&TeamUser{OrgId: org.Id}); err != nil { + sess.Rollback() + return err + } + return sess.Commit() +} + type AuthorizeType int const ( @@ -158,6 +196,12 @@ func GetOrganizationCount(u *User) (int64, error) { return x.Where("uid=?", u.Id).Count(new(OrgUser)) } +// IsOrganizationOwner returns true if given user ID is in the owner team. +func IsOrganizationOwner(orgId, uid int64) bool { + has, _ := x.Where("is_owner=?", true).Get(&OrgUser{Uid: uid, OrgId: orgId}) + return has +} + // ___________ ____ ___ // \__ ___/___ _____ _____ | | \______ ___________ // | |_/ __ \\__ \ / \| | / ___// __ \_ __ \ diff --git a/models/repo.go b/models/repo.go index 85f2a913..3d38ed66 100644 --- a/models/repo.go +++ b/models/repo.go @@ -733,7 +733,7 @@ func UpdateRepository(repo *Repository) error { } // DeleteRepository deletes a repository for a user or orgnaztion. -func DeleteRepository(userId, repoId int64, userName string) (err error) { +func DeleteRepository(userId, repoId int64, userName string) error { repo := &Repository{Id: repoId, OwnerId: userId} has, err := x.Get(repo) if err != nil { @@ -747,6 +747,7 @@ func DeleteRepository(userId, repoId int64, userName string) (err error) { if err = sess.Begin(); err != nil { return err } + if _, err = sess.Delete(&Repository{Id: repoId}); err != nil { sess.Rollback() return err diff --git a/models/user.go b/models/user.go index 8ffad266..9b0bdebe 100644 --- a/models/user.go +++ b/models/user.go @@ -105,10 +105,12 @@ func (u *User) EncodePasswd() { u.Passwd = fmt.Sprintf("%x", newPasswd) } +// IsOrganization returns true if user is actually a organization. func (u *User) IsOrganization() bool { return u.Type == ORGANIZATION } +// GetOrganizations returns all organizations that user belongs to. func (u *User) GetOrganizations() error { ous, err := GetOrgUsersByUserId(u.Id) if err != nil { @@ -125,16 +127,6 @@ func (u *User) GetOrganizations() error { return nil } -// GetOwnerTeam returns owner team of organization. -func (org *User) GetOwnerTeam() (*Team, error) { - t := &Team{ - OrgId: org.Id, - Name: OWNER_TEAM, - } - _, err := x.Get(t) - return t, err -} - // IsUserExist checks if given user name exist, // the user name should be noncased unique. func IsUserExist(name string) (bool, error) { @@ -327,7 +319,8 @@ func UpdateUser(u *User) (err error) { return err } -// DeleteUser completely deletes everything of the user. +// TODO: need some kind of mechanism to record failure. +// DeleteUser completely and permanently deletes everything of user. func DeleteUser(u *User) error { // Check ownership of repository. count, err := GetRepositoryCount(u) @@ -346,32 +339,28 @@ func DeleteUser(u *User) error { } // TODO: check issues, other repos' commits + // TODO: roll backable in some point. // Delete all followers. if _, err = x.Delete(&Follow{FollowId: u.Id}); err != nil { return err } - // Delete oauth2. if _, err = x.Delete(&Oauth2{Uid: u.Id}); err != nil { return err } - // Delete all feeds. if _, err = x.Delete(&Action{UserId: u.Id}); err != nil { return err } - // Delete all watches. if _, err = x.Delete(&Watch{UserId: u.Id}); err != nil { return err } - // Delete all accesses. 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: u.Id}); err != nil { diff --git a/modules/middleware/repo.go b/modules/middleware/repo.go index 43ba1e8c..0c640275 100644 --- a/modules/middleware/repo.go +++ b/modules/middleware/repo.go @@ -44,6 +44,7 @@ func RepoAssignment(redirect bool, args ...bool) martini.Handler { repoName := params["reponame"] refName := params["branchname"] + // TODO: need more advanced onwership and access level check. // Collaborators who have write access can be seen as owners. if ctx.IsSigned { ctx.Repo.IsOwner, err = models.HasAccess(ctx.User.Name, userName+"/"+repoName, models.WRITABLE) diff --git a/routers/org/org.go b/routers/org/org.go index c036a8e5..7b2c4d73 100644 --- a/routers/org/org.go +++ b/routers/org/org.go @@ -30,7 +30,6 @@ func Members(ctx *middleware.Context, params martini.Params) { ctx.HTML(200, "org/members") } - func New(ctx *middleware.Context) { ctx.Data["Title"] = "Create An Organization" ctx.HTML(200, NEW) @@ -160,3 +159,47 @@ func SettingsPost(ctx *middleware.Context, params martini.Params, form auth.OrgS ctx.Flash.Success("Organization profile has been successfully updated.") ctx.Redirect("/org/" + org.Name + "/settings") } + +func DeletePost(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.DeletePost(GetUserByName)", err) + } else { + ctx.Handle(500, "org.DeletePost(GetUserByName)", err) + } + return + } + ctx.Data["Org"] = org + + if !models.IsOrganizationOwner(org.Id, ctx.User.Id) { + ctx.Error(403) + return + } + + tmpUser := models.User{ + Passwd: ctx.Query("password"), + Salt: ctx.User.Salt, + } + tmpUser.EncodePasswd() + if tmpUser.Passwd != ctx.User.Passwd { + ctx.Flash.Error("Password is not correct. Make sure you are owner of this account.") + } else { + if err := models.DeleteOrganization(org); err != nil { + switch err { + case models.ErrUserOwnRepos: + ctx.Flash.Error("This organization still have ownership of repository, you have to delete or transfer them first.") + default: + ctx.Handle(500, "org.DeletePost(DeleteOrganization)", err) + return + } + } else { + ctx.Redirect("/") + return + } + } + + ctx.Redirect("/org/" + org.Name + "/settings") +} diff --git a/routers/repo/setting.go b/routers/repo/setting.go index 3d48e79c..e97eca12 100644 --- a/routers/repo/setting.go +++ b/routers/repo/setting.go @@ -122,13 +122,23 @@ func SettingPost(ctx *middleware.Context, form auth.RepoSettingForm) { return } - if err := models.DeleteRepository(ctx.User.Id, ctx.Repo.Repository.Id, ctx.User.LowerName); err != nil { - ctx.Handle(500, "setting.Delete", err) + if ctx.Repo.Owner.IsOrganization() && + !models.IsOrganizationOwner(ctx.Repo.Owner.Id, ctx.User.Id) { + ctx.Error(403) return } - log.Trace("%s Repository deleted: %s/%s", ctx.Req.RequestURI, ctx.User.LowerName, ctx.Repo.Repository.LowerName) - ctx.Redirect("/") + if err := models.DeleteRepository(ctx.Repo.Owner.Id, ctx.Repo.Repository.Id, ctx.Repo.Owner.Name); err != nil { + ctx.Handle(500, "setting.Delete(DeleteRepository)", err) + return + } + log.Trace("%s Repository deleted: %s/%s", ctx.Req.RequestURI, ctx.Repo.Owner.LowerName, ctx.Repo.Repository.LowerName) + + if ctx.Repo.Owner.IsOrganization() { + ctx.Redirect("/org/" + ctx.Repo.Owner.Name + "/dashboard") + } else { + ctx.Redirect("/") + } } } diff --git a/routers/user/user.go b/routers/user/user.go index a402744b..561fe1c1 100644 --- a/routers/user/user.go +++ b/routers/user/user.go @@ -296,7 +296,7 @@ func DeletePost(ctx *middleware.Context) { case models.ErrUserOwnRepos: ctx.Flash.Error("Your account still have ownership of repository, you have to delete or transfer them first.") default: - ctx.Handle(500, "user.Delete(DeleteUser)", err) + ctx.Handle(500, "user.DeletePost(DeleteUser)", err) return } } else { diff --git a/templates/VERSION b/templates/VERSION index be0ebee0..09c51980 100644 --- a/templates/VERSION +++ b/templates/VERSION @@ -1 +1 @@ -0.4.5.0627 Alpha \ No newline at end of file +0.4.5.0628 Alpha \ No newline at end of file diff --git a/templates/user/dashboard.tmpl b/templates/user/dashboard.tmpl index e1b43e15..2cb19cef 100644 --- a/templates/user/dashboard.tmpl +++ b/templates/user/dashboard.tmpl @@ -76,7 +76,7 @@