diff options
author | Lunny Xiao <xiaolunwen@gmail.com> | 2017-09-14 16:16:22 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-09-14 16:16:22 +0800 |
commit | 1739e84ac02c0384c04576a00abab9348293f9c7 (patch) | |
tree | 1015e68f36421f274d2e883ff3ddb0cb29b6af71 /routers | |
parent | be3319b3d545289b772d7a92b4b62205863954d9 (diff) | |
download | gitea-1739e84ac02c0384c04576a00abab9348293f9c7.tar.gz gitea-1739e84ac02c0384c04576a00abab9348293f9c7.zip |
improve protected branch to add whitelist support (#2451)
* improve protected branch to add whitelist support
* fix lint
* fix style check
* fix tests
* fix description on UI and import
* fix test
* bug fixed
* fix tests and languages
* move isSliceInt64Eq to util pkg; improve function names & typo
Diffstat (limited to 'routers')
-rw-r--r-- | routers/private/branch.go | 24 | ||||
-rw-r--r-- | routers/private/internal.go | 1 | ||||
-rw-r--r-- | routers/repo/editor.go | 2 | ||||
-rw-r--r-- | routers/repo/issue.go | 2 | ||||
-rw-r--r-- | routers/repo/pull.go | 2 | ||||
-rw-r--r-- | routers/repo/setting.go | 138 | ||||
-rw-r--r-- | routers/repo/setting_protected_branch.go | 186 | ||||
-rw-r--r-- | routers/routes/routes.go | 4 |
8 files changed, 216 insertions, 143 deletions
diff --git a/routers/private/branch.go b/routers/private/branch.go index 8e42f73039..448c61f1db 100644 --- a/routers/private/branch.go +++ b/routers/private/branch.go @@ -24,7 +24,29 @@ func GetProtectedBranchBy(ctx *macaron.Context) { ctx.JSON(200, protectBranch) } else { ctx.JSON(200, &models.ProtectedBranch{ - CanPush: true, + ID: 0, + }) + } +} + +// CanUserPush returns if user push +func CanUserPush(ctx *macaron.Context) { + pbID := ctx.ParamsInt64(":pbid") + userID := ctx.ParamsInt64(":userid") + + protectBranch, err := models.GetProtectedBranchByID(pbID) + if err != nil { + ctx.JSON(500, map[string]interface{}{ + "err": err.Error(), + }) + return + } else if protectBranch != nil { + ctx.JSON(200, map[string]interface{}{ + "can_push": protectBranch.CanUserPush(userID), + }) + } else { + ctx.JSON(200, map[string]interface{}{ + "can_push": false, }) } } diff --git a/routers/private/internal.go b/routers/private/internal.go index 3e7233226a..b69411dd06 100644 --- a/routers/private/internal.go +++ b/routers/private/internal.go @@ -42,6 +42,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Group("/", func() { m.Post("/ssh/:id/update", UpdatePublicKey) m.Post("/push/update", PushUpdate) + m.Get("/protectedbranch/:pbid/:userid", CanUserPush) m.Get("/branch/:id/*", GetProtectedBranchBy) }, CheckInternalToken) } diff --git a/routers/repo/editor.go b/routers/repo/editor.go index bb0475338d..42ede9a28f 100644 --- a/routers/repo/editor.go +++ b/routers/repo/editor.go @@ -32,7 +32,7 @@ const ( ) func renderCommitRights(ctx *context.Context) bool { - canCommit, err := ctx.Repo.CanCommitToBranch() + canCommit, err := ctx.Repo.CanCommitToBranch(ctx.User) if err != nil { log.Error(4, "CanCommitToBranch: %v", err) } diff --git a/routers/repo/issue.go b/routers/repo/issue.go index 0cd4edabb6..d5d1af7e49 100644 --- a/routers/repo/issue.go +++ b/routers/repo/issue.go @@ -694,7 +694,7 @@ func ViewIssue(ctx *context.Context) { log.Error(4, "GetHeadRepo: %v", err) } else if pull.HeadRepo != nil && pull.HeadBranch != pull.HeadRepo.DefaultBranch && ctx.User.IsWriterOfRepo(pull.HeadRepo) { // Check if branch is not protected - if protected, err := pull.HeadRepo.IsProtectedBranch(pull.HeadBranch); err != nil { + if protected, err := pull.HeadRepo.IsProtectedBranch(pull.HeadBranch, ctx.User); err != nil { log.Error(4, "IsProtectedBranch: %v", err) } else if !protected { canDelete = true diff --git a/routers/repo/pull.go b/routers/repo/pull.go index 47fcff3128..87d3bdc26d 100644 --- a/routers/repo/pull.go +++ b/routers/repo/pull.go @@ -841,7 +841,7 @@ func CleanUpPullRequest(ctx *context.Context) { } // Check if branch is not protected - if protected, err := pr.HeadRepo.IsProtectedBranch(pr.HeadBranch); err != nil || protected { + if protected, err := pr.HeadRepo.IsProtectedBranch(pr.HeadBranch, ctx.User); err != nil || protected { if err != nil { log.Error(4, "HeadRepo.IsProtectedBranch: %v", err) } diff --git a/routers/repo/setting.go b/routers/repo/setting.go index 6e12c7ad6d..eb4136b07d 100644 --- a/routers/repo/setting.go +++ b/routers/repo/setting.go @@ -25,6 +25,7 @@ const ( tplGithooks base.TplName = "repo/settings/githooks" tplGithookEdit base.TplName = "repo/settings/githook_edit" tplDeployKeys base.TplName = "repo/settings/deploy_keys" + tplProtectedBranch base.TplName = "repo/settings/protected_branch" ) // Settings show a repository's settings page @@ -437,143 +438,6 @@ func DeleteCollaboration(ctx *context.Context) { }) } -// ProtectedBranch render the page to protect the repository -func ProtectedBranch(ctx *context.Context) { - ctx.Data["Title"] = ctx.Tr("repo.settings") - ctx.Data["PageIsSettingsBranches"] = true - - protectedBranches, err := ctx.Repo.Repository.GetProtectedBranches() - if err != nil { - ctx.Handle(500, "GetProtectedBranches", err) - return - } - ctx.Data["ProtectedBranches"] = protectedBranches - - branches := ctx.Data["Branches"].([]string) - leftBranches := make([]string, 0, len(branches)-len(protectedBranches)) - for _, b := range branches { - var protected bool - for _, pb := range protectedBranches { - if b == pb.BranchName { - protected = true - break - } - } - if !protected { - leftBranches = append(leftBranches, b) - } - } - - ctx.Data["LeftBranches"] = leftBranches - - ctx.HTML(200, tplBranches) -} - -// ProtectedBranchPost response for protect for a branch of a repository -func ProtectedBranchPost(ctx *context.Context) { - ctx.Data["Title"] = ctx.Tr("repo.settings") - ctx.Data["PageIsSettingsBranches"] = true - - repo := ctx.Repo.Repository - - switch ctx.Query("action") { - case "default_branch": - if ctx.HasError() { - ctx.HTML(200, tplBranches) - return - } - - branch := ctx.Query("branch") - if !ctx.Repo.GitRepo.IsBranchExist(branch) { - ctx.Status(404) - return - } else if repo.DefaultBranch != branch { - repo.DefaultBranch = branch - if err := ctx.Repo.GitRepo.SetDefaultBranch(branch); err != nil { - if !git.IsErrUnsupportedVersion(err) { - ctx.Handle(500, "SetDefaultBranch", err) - return - } - } - if err := repo.UpdateDefaultBranch(); err != nil { - ctx.Handle(500, "SetDefaultBranch", err) - return - } - } - - log.Trace("Repository basic settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name) - - ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success")) - ctx.Redirect(setting.AppSubURL + ctx.Req.URL.Path) - case "protected_branch": - if ctx.HasError() { - ctx.JSON(200, map[string]string{ - "redirect": setting.AppSubURL + ctx.Req.URL.Path, - }) - return - } - - branchName := strings.ToLower(ctx.Query("branchName")) - if len(branchName) == 0 || !ctx.Repo.GitRepo.IsBranchExist(branchName) { - ctx.JSON(200, map[string]string{ - "redirect": setting.AppSubURL + ctx.Req.URL.Path, - }) - return - } - - canPush := ctx.QueryBool("canPush") - - if canPush { - if err := ctx.Repo.Repository.AddProtectedBranch(branchName, canPush); err != nil { - ctx.Flash.Error(ctx.Tr("repo.settings.add_protected_branch_failed", branchName)) - ctx.JSON(200, map[string]string{ - "status": "ok", - }) - return - } - - ctx.Flash.Success(ctx.Tr("repo.settings.add_protected_branch_success", branchName)) - ctx.JSON(200, map[string]string{ - "redirect": setting.AppSubURL + ctx.Req.URL.Path, - }) - } else { - if err := ctx.Repo.Repository.DeleteProtectedBranch(ctx.QueryInt64("id")); err != nil { - ctx.Flash.Error("DeleteProtectedBranch: " + err.Error()) - } else { - ctx.Flash.Success(ctx.Tr("repo.settings.remove_protected_branch_success", branchName)) - } - - ctx.JSON(200, map[string]interface{}{ - "status": "ok", - }) - } - default: - ctx.Handle(404, "", nil) - } -} - -// ChangeProtectedBranch response for changing access of a protect branch -func ChangeProtectedBranch(ctx *context.Context) { - if err := ctx.Repo.Repository.ChangeProtectedBranch( - ctx.QueryInt64("id"), - ctx.QueryBool("canPush")); err != nil { - log.Error(4, "ChangeProtectedBranch: %v", err) - } -} - -// DeleteProtectedBranch delete a protection for a branch of a repository -func DeleteProtectedBranch(ctx *context.Context) { - if err := ctx.Repo.Repository.DeleteProtectedBranch(ctx.QueryInt64("id")); err != nil { - ctx.Flash.Error("DeleteProtectedBranch: " + err.Error()) - } else { - ctx.Flash.Success(ctx.Tr("repo.settings.remove_protected_branch_success")) - } - - ctx.JSON(200, map[string]interface{}{ - "redirect": ctx.Repo.RepoLink + "/settings/branches", - }) -} - // parseOwnerAndRepo get repos by owner func parseOwnerAndRepo(ctx *context.Context) (*models.User, *models.Repository) { owner, err := models.GetUserByName(ctx.Params(":username")) diff --git a/routers/repo/setting_protected_branch.go b/routers/repo/setting_protected_branch.go new file mode 100644 index 0000000000..7ab8ca218e --- /dev/null +++ b/routers/repo/setting_protected_branch.go @@ -0,0 +1,186 @@ +// Copyright 2017 The Gitea 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 repo + +import ( + "fmt" + "strings" + + "code.gitea.io/git" + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/modules/auth" + "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" +) + +// ProtectedBranch render the page to protect the repository +func ProtectedBranch(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("repo.settings") + ctx.Data["PageIsSettingsBranches"] = true + + protectedBranches, err := ctx.Repo.Repository.GetProtectedBranches() + if err != nil { + ctx.Handle(500, "GetProtectedBranches", err) + return + } + ctx.Data["ProtectedBranches"] = protectedBranches + + branches := ctx.Data["Branches"].([]string) + leftBranches := make([]string, 0, len(branches)-len(protectedBranches)) + for _, b := range branches { + var protected bool + for _, pb := range protectedBranches { + if b == pb.BranchName { + protected = true + break + } + } + if !protected { + leftBranches = append(leftBranches, b) + } + } + + ctx.Data["LeftBranches"] = leftBranches + + ctx.HTML(200, tplBranches) +} + +// ProtectedBranchPost response for protect for a branch of a repository +func ProtectedBranchPost(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("repo.settings") + ctx.Data["PageIsSettingsBranches"] = true + + repo := ctx.Repo.Repository + + switch ctx.Query("action") { + case "default_branch": + if ctx.HasError() { + ctx.HTML(200, tplBranches) + return + } + + branch := ctx.Query("branch") + if !ctx.Repo.GitRepo.IsBranchExist(branch) { + ctx.Status(404) + return + } else if repo.DefaultBranch != branch { + repo.DefaultBranch = branch + if err := ctx.Repo.GitRepo.SetDefaultBranch(branch); err != nil { + if !git.IsErrUnsupportedVersion(err) { + ctx.Handle(500, "SetDefaultBranch", err) + return + } + } + if err := repo.UpdateDefaultBranch(); err != nil { + ctx.Handle(500, "SetDefaultBranch", err) + return + } + } + + log.Trace("Repository basic settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name) + + ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success")) + ctx.Redirect(setting.AppSubURL + ctx.Req.URL.Path) + default: + ctx.Handle(404, "", nil) + } +} + +// SettingsProtectedBranch renders the protected branch setting page +func SettingsProtectedBranch(c *context.Context) { + branch := c.Params("*") + if !c.Repo.GitRepo.IsBranchExist(branch) { + c.NotFound() + return + } + + c.Data["Title"] = c.Tr("repo.settings.protected_branches") + " - " + branch + c.Data["PageIsSettingsBranches"] = true + + protectBranch, err := models.GetProtectedBranchBy(c.Repo.Repository.ID, branch) + if err != nil { + if !models.IsErrBranchNotExist(err) { + c.Handle(500, "GetProtectBranchOfRepoByName", err) + return + } + } + + if protectBranch == nil { + // No options found, create defaults. + protectBranch = &models.ProtectedBranch{ + BranchName: branch, + } + } + + users, err := c.Repo.Repository.GetWriters() + if err != nil { + c.Handle(500, "Repo.Repository.GetWriters", err) + return + } + c.Data["Users"] = users + c.Data["whitelist_users"] = strings.Join(base.Int64sToStrings(protectBranch.WhitelistUserIDs), ",") + + if c.Repo.Owner.IsOrganization() { + teams, err := c.Repo.Owner.TeamsWithAccessToRepo(c.Repo.Repository.ID, models.AccessModeWrite) + if err != nil { + c.Handle(500, "Repo.Owner.TeamsWithAccessToRepo", err) + return + } + c.Data["Teams"] = teams + c.Data["whitelist_teams"] = strings.Join(base.Int64sToStrings(protectBranch.WhitelistTeamIDs), ",") + } + + c.Data["Branch"] = protectBranch + c.HTML(200, tplProtectedBranch) +} + +// SettingsProtectedBranchPost updates the protected branch settings +func SettingsProtectedBranchPost(ctx *context.Context, f auth.ProtectBranchForm) { + branch := ctx.Params("*") + if !ctx.Repo.GitRepo.IsBranchExist(branch) { + ctx.NotFound() + return + } + + protectBranch, err := models.GetProtectedBranchBy(ctx.Repo.Repository.ID, branch) + if err != nil { + if !models.IsErrBranchNotExist(err) { + ctx.Handle(500, "GetProtectBranchOfRepoByName", err) + return + } + } + + if f.Protected { + if protectBranch == nil { + // No options found, create defaults. + protectBranch = &models.ProtectedBranch{ + RepoID: ctx.Repo.Repository.ID, + BranchName: branch, + } + } + + protectBranch.EnableWhitelist = f.EnableWhitelist + whitelistUsers, _ := base.StringsToInt64s(strings.Split(f.WhitelistUsers, ",")) + whitelistTeams, _ := base.StringsToInt64s(strings.Split(f.WhitelistTeams, ",")) + err = models.UpdateProtectBranch(ctx.Repo.Repository, protectBranch, whitelistUsers, whitelistTeams) + if err != nil { + ctx.Handle(500, "UpdateProtectBranch", err) + return + } + ctx.Flash.Success(ctx.Tr("repo.settings.update_protect_branch_success", branch)) + ctx.Redirect(fmt.Sprintf("%s/settings/branches/%s", ctx.Repo.RepoLink, branch)) + } else { + if protectBranch != nil { + if err := ctx.Repo.Repository.DeleteProtectedBranch(protectBranch.ID); err != nil { + ctx.Handle(500, "DeleteProtectedBranch", err) + return + } + } + ctx.Flash.Success(ctx.Tr("repo.settings.remove_protected_branch_success", branch)) + ctx.Redirect(fmt.Sprintf("%s/settings/branches", ctx.Repo.RepoLink)) + } +} diff --git a/routers/routes/routes.go b/routers/routes/routes.go index 938dec1dcf..067bf6a7f6 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -433,8 +433,8 @@ func RegisterRoutes(m *macaron.Macaron) { }) m.Group("/branches", func() { m.Combo("").Get(repo.ProtectedBranch).Post(repo.ProtectedBranchPost) - m.Post("/can_push", repo.ChangeProtectedBranch) - m.Post("/delete", repo.DeleteProtectedBranch) + m.Combo("/*").Get(repo.SettingsProtectedBranch). + Post(bindIgnErr(auth.ProtectBranchForm{}), repo.SettingsProtectedBranchPost) }, repo.MustBeNotBare) m.Group("/hooks", func() { |