summaryrefslogtreecommitdiffstats
path: root/routers
diff options
context:
space:
mode:
authorLunny Xiao <xiaolunwen@gmail.com>2018-11-28 19:26:14 +0800
committerGitHub <noreply@github.com>2018-11-28 19:26:14 +0800
commiteabbddcd98717ef20d8475e819f403c50f4a9787 (patch)
treeefc525e7ec60d56d3bec72019febfa088a128b89 /routers
parent0222623be9fa4a56d870213f77b92139cefc2518 (diff)
downloadgitea-eabbddcd98717ef20d8475e819f403c50f4a9787.tar.gz
gitea-eabbddcd98717ef20d8475e819f403c50f4a9787.zip
Restrict permission check on repositories and fix some problems (#5314)
* fix units permission problems * fix some bugs and merge LoadUnits to repoAssignment * refactor permission struct and add some copyright heads * remove unused codes * fix routes units check * improve permission check * add unit tests for permission * fix typo * fix tests * fix some routes * fix api permission check * improve permission check * fix some permission check * fix tests * fix tests * improve some permission check * fix some permission check * refactor AccessLevel * fix bug * fix tests * fix tests * fix tests * fix AccessLevel * rename CanAccess * fix tests * fix comment * fix bug * add missing unit for test repos * fix bug * rename some functions * fix routes check
Diffstat (limited to 'routers')
-rw-r--r--routers/api/v1/api.go142
-rw-r--r--routers/api/v1/org/team.go6
-rw-r--r--routers/api/v1/repo/collaborators.go18
-rw-r--r--routers/api/v1/repo/file.go6
-rw-r--r--routers/api/v1/repo/fork.go3
-rw-r--r--routers/api/v1/repo/issue.go15
-rw-r--r--routers/api/v1/repo/issue_label.go41
-rw-r--r--routers/api/v1/repo/label.go16
-rw-r--r--routers/api/v1/repo/pull.go15
-rw-r--r--routers/api/v1/repo/release.go12
-rw-r--r--routers/api/v1/repo/repo.go20
-rw-r--r--routers/api/v1/user/repo.go7
-rw-r--r--routers/api/v1/user/star.go10
-rw-r--r--routers/api/v1/user/watch.go10
-rw-r--r--routers/private/internal.go36
-rw-r--r--routers/repo/activity.go6
-rw-r--r--routers/repo/branch.go5
-rw-r--r--routers/repo/http.go37
-rw-r--r--routers/repo/issue.go187
-rw-r--r--routers/repo/issue_watch.go25
-rw-r--r--routers/repo/pull.go24
-rw-r--r--routers/repo/release.go6
-rw-r--r--routers/repo/setting_protected_branch.go17
-rw-r--r--routers/repo/view.go10
-rw-r--r--routers/repo/wiki.go13
-rw-r--r--routers/routes/routes.go79
-rw-r--r--routers/user/home.go7
27 files changed, 409 insertions, 364 deletions
diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go
index 0be8f84836..47e556c881 100644
--- a/routers/api/v1/api.go
+++ b/routers/api/v1/api.go
@@ -1,5 +1,5 @@
// Copyright 2015 The Gogs Authors. All rights reserved.
-// Copyright 2018 The Gitea Authors. All rights reserved.
+// Copyright 2016 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.
@@ -71,7 +71,6 @@ import (
"code.gitea.io/gitea/routers/api/v1/repo"
_ "code.gitea.io/gitea/routers/api/v1/swagger" // for swagger generation
"code.gitea.io/gitea/routers/api/v1/user"
- "code.gitea.io/gitea/routers/api/v1/utils"
api "code.gitea.io/sdk/gitea"
"github.com/go-macaron/binding"
@@ -152,24 +151,18 @@ func repoAssignment() macaron.Handler {
return
}
repo.Owner = owner
+ ctx.Repo.Repository = repo
- if ctx.IsSigned && ctx.User.IsAdmin {
- ctx.Repo.AccessMode = models.AccessModeOwner
- } else {
- mode, err := models.AccessLevel(utils.UserID(ctx), repo)
- if err != nil {
- ctx.Error(500, "AccessLevel", err)
- return
- }
- ctx.Repo.AccessMode = mode
+ ctx.Repo.Permission, err = models.GetUserRepoPermission(repo, ctx.User)
+ if err != nil {
+ ctx.Error(500, "GetUserRepoPermission", err)
+ return
}
if !ctx.Repo.HasAccess() {
ctx.Status(404)
return
}
-
- ctx.Repo.Repository = repo
}
}
@@ -196,7 +189,8 @@ func reqBasicAuth() macaron.Handler {
}
}
-func reqAdmin() macaron.Handler {
+// reqSiteAdmin user should be the site admin
+func reqSiteAdmin() macaron.Handler {
return func(ctx *context.Context) {
if !ctx.IsSigned || !ctx.User.IsAdmin {
ctx.Error(403)
@@ -205,15 +199,56 @@ func reqAdmin() macaron.Handler {
}
}
-func reqRepoWriter() macaron.Handler {
+// reqOwner user should be the owner of the repo.
+func reqOwner() macaron.Handler {
+ return func(ctx *context.Context) {
+ if !ctx.Repo.IsOwner() {
+ ctx.Error(403)
+ return
+ }
+ }
+}
+
+// reqAdmin user should be an owner or a collaborator with admin write of a repository
+func reqAdmin() macaron.Handler {
+ return func(ctx *context.Context) {
+ if !ctx.Repo.IsAdmin() {
+ ctx.Error(403)
+ return
+ }
+ }
+}
+
+func reqRepoReader(unitType models.UnitType) macaron.Handler {
+ return func(ctx *context.Context) {
+ if !ctx.Repo.CanRead(unitType) {
+ ctx.Error(403)
+ return
+ }
+ }
+}
+
+func reqAnyRepoReader() macaron.Handler {
return func(ctx *context.Context) {
- if !ctx.Repo.IsWriter() {
+ if !ctx.Repo.HasAccess() {
ctx.Error(403)
return
}
}
}
+func reqRepoWriter(unitTypes ...models.UnitType) macaron.Handler {
+ return func(ctx *context.Context) {
+ for _, unitType := range unitTypes {
+ if ctx.Repo.CanWrite(unitType) {
+ return
+ }
+ }
+
+ ctx.Error(403)
+ }
+}
+
func reqOrgMembership() macaron.Handler {
return func(ctx *context.APIContext) {
var orgID int64
@@ -308,22 +343,22 @@ func orgAssignment(args ...bool) macaron.Handler {
}
func mustEnableIssues(ctx *context.APIContext) {
- if !ctx.Repo.Repository.UnitEnabled(models.UnitTypeIssues) {
+ if !ctx.Repo.CanRead(models.UnitTypeIssues) {
ctx.Status(404)
return
}
}
func mustAllowPulls(ctx *context.Context) {
- if !ctx.Repo.Repository.AllowsPulls() {
+ if !(ctx.Repo.Repository.CanEnablePulls() && ctx.Repo.CanRead(models.UnitTypePullRequests)) {
ctx.Status(404)
return
}
}
func mustEnableIssuesOrPulls(ctx *context.Context) {
- if !ctx.Repo.Repository.UnitEnabled(models.UnitTypeIssues) &&
- !ctx.Repo.Repository.AllowsPulls() {
+ if !ctx.Repo.CanRead(models.UnitTypeIssues) &&
+ !(ctx.Repo.Repository.CanEnablePulls() && ctx.Repo.CanRead(models.UnitTypePullRequests)) {
ctx.Status(404)
return
}
@@ -443,7 +478,8 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Post("/migrate", reqToken(), bind(auth.MigrateRepoForm{}), repo.Migrate)
m.Group("/:username/:reponame", func() {
- m.Combo("").Get(repo.Get).Delete(reqToken(), repo.Delete)
+ m.Combo("").Get(reqAnyRepoReader(), repo.Get).
+ Delete(reqToken(), reqOwner(), repo.Delete)
m.Group("/hooks", func() {
m.Combo("").Get(repo.ListHooks).
Post(bind(api.CreateHookOption{}), repo.CreateHook)
@@ -453,31 +489,30 @@ func RegisterRoutes(m *macaron.Macaron) {
Delete(repo.DeleteHook)
m.Post("/tests", context.RepoRef(), repo.TestHook)
})
- }, reqToken(), reqRepoWriter())
+ }, reqToken(), reqAdmin())
m.Group("/collaborators", func() {
m.Get("", repo.ListCollaborators)
m.Combo("/:collaborator").Get(repo.IsCollaborator).
Put(bind(api.AddCollaboratorOption{}), repo.AddCollaborator).
Delete(repo.DeleteCollaborator)
- }, reqToken())
- m.Get("/raw/*", context.RepoRefByType(context.RepoRefAny), repo.GetRawFile)
- m.Get("/archive/*", repo.GetArchive)
+ }, reqToken(), reqAdmin())
+ m.Get("/raw/*", context.RepoRefByType(context.RepoRefAny), reqRepoReader(models.UnitTypeCode), repo.GetRawFile)
+ m.Get("/archive/*", reqRepoReader(models.UnitTypeCode), repo.GetArchive)
m.Combo("/forks").Get(repo.ListForks).
- Post(reqToken(), bind(api.CreateForkOption{}), repo.CreateFork)
+ Post(reqToken(), reqRepoReader(models.UnitTypeCode), bind(api.CreateForkOption{}), repo.CreateFork)
m.Group("/branches", func() {
m.Get("", repo.ListBranches)
m.Get("/*", context.RepoRefByType(context.RepoRefBranch), repo.GetBranch)
- })
+ }, reqRepoReader(models.UnitTypeCode))
m.Group("/keys", func() {
m.Combo("").Get(repo.ListDeployKeys).
Post(bind(api.CreateKeyOption{}), repo.CreateDeployKey)
m.Combo("/:id").Get(repo.GetDeployKey).
Delete(repo.DeleteDeploykey)
- }, reqToken(), reqRepoWriter())
+ }, reqToken(), reqAdmin())
m.Group("/times", func() {
m.Combo("").Get(repo.ListTrackedTimesByRepository)
m.Combo("/:timetrackingusername").Get(repo.ListTrackedTimesByUser)
-
}, mustEnableIssues)
m.Group("/issues", func() {
m.Combo("").Get(repo.ListIssues).
@@ -517,17 +552,17 @@ func RegisterRoutes(m *macaron.Macaron) {
}, mustEnableIssuesOrPulls)
m.Group("/labels", func() {
m.Combo("").Get(repo.ListLabels).
- Post(reqToken(), bind(api.CreateLabelOption{}), repo.CreateLabel)
+ Post(reqToken(), reqRepoWriter(models.UnitTypeIssues, models.UnitTypePullRequests), bind(api.CreateLabelOption{}), repo.CreateLabel)
m.Combo("/:id").Get(repo.GetLabel).
- Patch(reqToken(), bind(api.EditLabelOption{}), repo.EditLabel).
- Delete(reqToken(), repo.DeleteLabel)
+ Patch(reqToken(), reqRepoWriter(models.UnitTypeIssues, models.UnitTypePullRequests), bind(api.EditLabelOption{}), repo.EditLabel).
+ Delete(reqToken(), reqRepoWriter(models.UnitTypeIssues, models.UnitTypePullRequests), repo.DeleteLabel)
})
m.Group("/milestones", func() {
m.Combo("").Get(repo.ListMilestones).
- Post(reqToken(), reqRepoWriter(), bind(api.CreateMilestoneOption{}), repo.CreateMilestone)
+ Post(reqToken(), reqRepoWriter(models.UnitTypeIssues, models.UnitTypePullRequests), bind(api.CreateMilestoneOption{}), repo.CreateMilestone)
m.Combo("/:id").Get(repo.GetMilestone).
- Patch(reqToken(), reqRepoWriter(), bind(api.EditMilestoneOption{}), repo.EditMilestone).
- Delete(reqToken(), reqRepoWriter(), repo.DeleteMilestone)
+ Patch(reqToken(), reqRepoWriter(models.UnitTypeIssues, models.UnitTypePullRequests), bind(api.EditMilestoneOption{}), repo.EditMilestone).
+ Delete(reqToken(), reqRepoWriter(models.UnitTypeIssues, models.UnitTypePullRequests), repo.DeleteMilestone)
})
m.Get("/stargazers", repo.ListStargazers)
m.Get("/subscribers", repo.ListSubscribers)
@@ -538,45 +573,44 @@ func RegisterRoutes(m *macaron.Macaron) {
})
m.Group("/releases", func() {
m.Combo("").Get(repo.ListReleases).
- Post(reqToken(), reqRepoWriter(), context.ReferencesGitRepo(), bind(api.CreateReleaseOption{}), repo.CreateRelease)
+ Post(reqToken(), reqRepoWriter(models.UnitTypeReleases), context.ReferencesGitRepo(), bind(api.CreateReleaseOption{}), repo.CreateRelease)
m.Group("/:id", func() {
m.Combo("").Get(repo.GetRelease).
- Patch(reqToken(), reqRepoWriter(), context.ReferencesGitRepo(), bind(api.EditReleaseOption{}), repo.EditRelease).
- Delete(reqToken(), reqRepoWriter(), repo.DeleteRelease)
+ Patch(reqToken(), reqRepoWriter(models.UnitTypeReleases), context.ReferencesGitRepo(), bind(api.EditReleaseOption{}), repo.EditRelease).
+ Delete(reqToken(), reqRepoWriter(models.UnitTypeReleases), repo.DeleteRelease)
m.Group("/assets", func() {
m.Combo("").Get(repo.ListReleaseAttachments).
- Post(reqToken(), reqRepoWriter(), repo.CreateReleaseAttachment)
+ Post(reqToken(), reqRepoWriter(models.UnitTypeReleases), repo.CreateReleaseAttachment)
m.Combo("/:asset").Get(repo.GetReleaseAttachment).
- Patch(reqToken(), reqRepoWriter(), bind(api.EditAttachmentOptions{}), repo.EditReleaseAttachment).
- Delete(reqToken(), reqRepoWriter(), repo.DeleteReleaseAttachment)
+ Patch(reqToken(), reqRepoWriter(models.UnitTypeReleases), bind(api.EditAttachmentOptions{}), repo.EditReleaseAttachment).
+ Delete(reqToken(), reqRepoWriter(models.UnitTypeReleases), repo.DeleteReleaseAttachment)
})
})
- })
- m.Post("/mirror-sync", reqToken(), reqRepoWriter(), repo.MirrorSync)
- m.Get("/editorconfig/:filename", context.RepoRef(), repo.GetEditorconfig)
+ }, reqRepoReader(models.UnitTypeReleases))
+ m.Post("/mirror-sync", reqToken(), reqRepoWriter(models.UnitTypeCode), repo.MirrorSync)
+ m.Get("/editorconfig/:filename", context.RepoRef(), reqRepoReader(models.UnitTypeCode), repo.GetEditorconfig)
m.Group("/pulls", func() {
m.Combo("").Get(bind(api.ListPullRequestsOptions{}), repo.ListPullRequests).
- Post(reqToken(), reqRepoWriter(), bind(api.CreatePullRequestOption{}), repo.CreatePullRequest)
+ Post(reqToken(), bind(api.CreatePullRequestOption{}), repo.CreatePullRequest)
m.Group("/:index", func() {
m.Combo("").Get(repo.GetPullRequest).
- Patch(reqToken(), reqRepoWriter(), bind(api.EditPullRequestOption{}), repo.EditPullRequest)
+ Patch(reqToken(), reqRepoWriter(models.UnitTypePullRequests), bind(api.EditPullRequestOption{}), repo.EditPullRequest)
m.Combo("/merge").Get(repo.IsPullRequestMerged).
- Post(reqToken(), reqRepoWriter(), bind(auth.MergePullRequestForm{}), repo.MergePullRequest)
+ Post(reqToken(), reqRepoWriter(models.UnitTypePullRequests), bind(auth.MergePullRequestForm{}), repo.MergePullRequest)
})
-
- }, mustAllowPulls, context.ReferencesGitRepo())
+ }, mustAllowPulls, reqRepoReader(models.UnitTypeCode), context.ReferencesGitRepo())
m.Group("/statuses", func() {
m.Combo("/:sha").Get(repo.GetCommitStatuses).
- Post(reqToken(), reqRepoWriter(), bind(api.CreateStatusOption{}), repo.NewCommitStatus)
- })
+ Post(reqToken(), bind(api.CreateStatusOption{}), repo.NewCommitStatus)
+ }, reqRepoReader(models.UnitTypeCode))
m.Group("/commits/:ref", func() {
m.Get("/status", repo.GetCombinedCommitStatusByRef)
m.Get("/statuses", repo.GetCommitStatusesByRef)
- })
+ }, reqRepoReader(models.UnitTypeCode))
m.Group("/git", func() {
m.Get("/refs", repo.GetGitAllRefs)
m.Get("/refs/*", repo.GetGitRefs)
- })
+ }, reqRepoReader(models.UnitTypeCode))
}, repoAssignment())
})
@@ -645,7 +679,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Post("/repos", bind(api.CreateRepoOption{}), admin.CreateRepo)
})
})
- }, reqToken(), reqAdmin())
+ }, reqToken(), reqSiteAdmin())
m.Group("/topics", func() {
m.Get("/search", repo.TopicSearch)
diff --git a/routers/api/v1/org/team.go b/routers/api/v1/org/team.go
index 8b67eda42f..a22d25eae3 100644
--- a/routers/api/v1/org/team.go
+++ b/routers/api/v1/org/team.go
@@ -311,7 +311,7 @@ func GetTeamRepos(ctx *context.APIContext) {
}
repos := make([]*api.Repository, len(team.Repos))
for i, repo := range team.Repos {
- access, err := models.AccessLevel(ctx.User.ID, repo)
+ access, err := models.AccessLevel(ctx.User, repo)
if err != nil {
ctx.Error(500, "GetTeamRepos", err)
return
@@ -366,7 +366,7 @@ func AddTeamRepository(ctx *context.APIContext) {
if ctx.Written() {
return
}
- if access, err := models.AccessLevel(ctx.User.ID, repo); err != nil {
+ if access, err := models.AccessLevel(ctx.User, repo); err != nil {
ctx.Error(500, "AccessLevel", err)
return
} else if access < models.AccessModeAdmin {
@@ -413,7 +413,7 @@ func RemoveTeamRepository(ctx *context.APIContext) {
if ctx.Written() {
return
}
- if access, err := models.AccessLevel(ctx.User.ID, repo); err != nil {
+ if access, err := models.AccessLevel(ctx.User, repo); err != nil {
ctx.Error(500, "AccessLevel", err)
return
} else if access < models.AccessModeAdmin {
diff --git a/routers/api/v1/repo/collaborators.go b/routers/api/v1/repo/collaborators.go
index c52472b0f8..2f254f7103 100644
--- a/routers/api/v1/repo/collaborators.go
+++ b/routers/api/v1/repo/collaborators.go
@@ -1,4 +1,5 @@
// Copyright 2016 The Gogs Authors. All rights reserved.
+// Copyright 2018 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.
@@ -34,10 +35,6 @@ func ListCollaborators(ctx *context.APIContext) {
// responses:
// "200":
// "$ref": "#/responses/UserList"
- if !ctx.Repo.IsWriter() {
- ctx.Error(403, "", "User does not have push access")
- return
- }
collaborators, err := ctx.Repo.Repository.GetCollaborators()
if err != nil {
ctx.Error(500, "ListCollaborators", err)
@@ -78,10 +75,6 @@ func IsCollaborator(ctx *context.APIContext) {
// "$ref": "#/responses/empty"
// "404":
// "$ref": "#/responses/empty"
- if !ctx.Repo.IsWriter() {
- ctx.Error(403, "", "User does not have push access")
- return
- }
user, err := models.GetUserByName(ctx.Params(":collaborator"))
if err != nil {
if models.IsErrUserNotExist(err) {
@@ -133,10 +126,6 @@ func AddCollaborator(ctx *context.APIContext, form api.AddCollaboratorOption) {
// responses:
// "204":
// "$ref": "#/responses/empty"
- if !ctx.Repo.IsWriter() {
- ctx.Error(403, "", "User does not have push access")
- return
- }
collaborator, err := models.GetUserByName(ctx.Params(":collaborator"))
if err != nil {
if models.IsErrUserNotExist(err) {
@@ -193,11 +182,6 @@ func DeleteCollaborator(ctx *context.APIContext) {
// responses:
// "204":
// "$ref": "#/responses/empty"
- if !ctx.Repo.IsWriter() {
- ctx.Error(403, "", "User does not have push access")
- return
- }
-
collaborator, err := models.GetUserByName(ctx.Params(":collaborator"))
if err != nil {
if models.IsErrUserNotExist(err) {
diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go
index 610247bc27..81f2332089 100644
--- a/routers/api/v1/repo/file.go
+++ b/routers/api/v1/repo/file.go
@@ -1,4 +1,5 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
+// Copyright 2018 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.
@@ -38,11 +39,6 @@ func GetRawFile(ctx *context.APIContext) {
// responses:
// 200:
// description: success
- if !ctx.Repo.HasAccess() {
- ctx.Status(404)
- return
- }
-
if ctx.Repo.Repository.IsBare {
ctx.Status(404)
return
diff --git a/routers/api/v1/repo/fork.go b/routers/api/v1/repo/fork.go
index 843559d523..d10f668712 100644
--- a/routers/api/v1/repo/fork.go
+++ b/routers/api/v1/repo/fork.go
@@ -7,7 +7,6 @@ package repo
import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
- "code.gitea.io/gitea/routers/api/v1/utils"
api "code.gitea.io/sdk/gitea"
)
@@ -40,7 +39,7 @@ func ListForks(ctx *context.APIContext) {
}
apiForks := make([]*api.Repository, len(forks))
for i, fork := range forks {
- access, err := models.AccessLevel(utils.UserID(ctx), fork)
+ access, err := models.AccessLevel(ctx.User, fork)
if err != nil {
ctx.Error(500, "AccessLevel", err)
return
diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go
index cd78135a62..7a8ed09b48 100644
--- a/routers/api/v1/repo/issue.go
+++ b/routers/api/v1/repo/issue.go
@@ -169,7 +169,7 @@ func CreateIssue(ctx *context.APIContext, form api.CreateIssueOption) {
// "$ref": "#/responses/Issue"
var deadlineUnix util.TimeStamp
- if form.Deadline != nil && ctx.Repo.IsWriter() {
+ if form.Deadline != nil && ctx.Repo.CanWrite(models.UnitTypeIssues) {
deadlineUnix = util.TimeStamp(form.Deadline.Unix())
}
@@ -184,7 +184,7 @@ func CreateIssue(ctx *context.APIContext, form api.CreateIssueOption) {
var assigneeIDs = make([]int64, 0)
var err error
- if ctx.Repo.IsWriter() {
+ if ctx.Repo.CanWrite(models.UnitTypeIssues) {
issue.MilestoneID = form.Milestone
assigneeIDs, err = models.MakeIDsFromAPIAssigneesToAdd(form.Assignee, form.Assignees)
if err != nil {
@@ -274,7 +274,7 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
return
}
- if !issue.IsPoster(ctx.User.ID) && !ctx.Repo.IsWriter() {
+ if !issue.IsPoster(ctx.User.ID) && !ctx.Repo.CanWrite(models.UnitTypeIssues) {
ctx.Status(403)
return
}
@@ -288,7 +288,7 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
// Update the deadline
var deadlineUnix util.TimeStamp
- if form.Deadline != nil && !form.Deadline.IsZero() && ctx.Repo.IsWriter() {
+ if form.Deadline != nil && !form.Deadline.IsZero() && ctx.Repo.CanWrite(models.UnitTypeIssues) {
deadlineUnix = util.TimeStamp(form.Deadline.Unix())
}
@@ -305,8 +305,7 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
// Pass one or more user logins to replace the set of assignees on this Issue.
// Send an empty array ([]) to clear all assignees from the Issue.
- if ctx.Repo.IsWriter() && (form.Assignees != nil || form.Assignee != nil) {
-
+ if ctx.Repo.CanWrite(models.UnitTypeIssues) && (form.Assignees != nil || form.Assignee != nil) {
oneAssignee := ""
if form.Assignee != nil {
oneAssignee = *form.Assignee
@@ -319,7 +318,7 @@ func EditIssue(ctx *context.APIContext, form api.EditIssueOption) {
}
}
- if ctx.Repo.IsWriter() && form.Milestone != nil &&
+ if ctx.Repo.CanWrite(models.UnitTypeIssues) && form.Milestone != nil &&
issue.MilestoneID != *form.Milestone {
oldMilestoneID := issue.MilestoneID
issue.MilestoneID = *form.Milestone
@@ -403,7 +402,7 @@ func UpdateIssueDeadline(ctx *context.APIContext, form api.EditDeadlineOption) {
return
}
- if !ctx.Repo.IsWriter() {
+ if !ctx.Repo.CanWrite(models.UnitTypeIssues) {
ctx.Status(403)
return
}
diff --git a/routers/api/v1/repo/issue_label.go b/routers/api/v1/repo/issue_label.go
index 35defa25b5..715dd0ed77 100644
--- a/routers/api/v1/repo/issue_label.go
+++ b/routers/api/v1/repo/issue_label.go
@@ -1,4 +1,5 @@
// Copyright 2016 The Gogs Authors. All rights reserved.
+// Copyright 2018 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.
@@ -90,11 +91,6 @@ func AddIssueLabels(ctx *context.APIContext, form api.IssueLabelsOption) {
// responses:
// "200":
// "$ref": "#/responses/LabelList"
- if !ctx.Repo.IsWriter() {
- ctx.Status(403)
- return
- }
-
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
if err != nil {
if models.IsErrIssueNotExist(err) {
@@ -105,6 +101,11 @@ func AddIssueLabels(ctx *context.APIContext, form api.IssueLabelsOption) {
return
}
+ if !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) {
+ ctx.Status(403)
+ return
+ }
+
labels, err := models.GetLabelsInRepoByIDs(ctx.Repo.Repository.ID, form.Labels)
if err != nil {
ctx.Error(500, "GetLabelsInRepoByIDs", err)
@@ -162,11 +163,6 @@ func DeleteIssueLabel(ctx *context.APIContext) {
// responses:
// "204":
// "$ref": "#/responses/empty"
- if !ctx.Repo.IsWriter() {
- ctx.Status(403)
- return
- }
-
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
if err != nil {
if models.IsErrIssueNotExist(err) {
@@ -177,6 +173,11 @@ func DeleteIssueLabel(ctx *context.APIContext) {
return
}
+ if !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) {
+ ctx.Status(403)
+ return
+ }
+
label, err := models.GetLabelInRepoByID(ctx.Repo.Repository.ID, ctx.ParamsInt64(":id"))
if err != nil {
if models.IsErrLabelNotExist(err) {
@@ -228,11 +229,6 @@ func ReplaceIssueLabels(ctx *context.APIContext, form api.IssueLabelsOption) {
// responses:
// "200":
// "$ref": "#/responses/LabelList"
- if !ctx.Repo.IsWriter() {
- ctx.Status(403)
- return
- }
-
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
if err != nil {
if models.IsErrIssueNotExist(err) {
@@ -243,6 +239,11 @@ func ReplaceIssueLabels(ctx *context.APIContext, form api.IssueLabelsOption) {
return
}
+ if !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) {
+ ctx.Status(403)
+ return
+ }
+
labels, err := models.GetLabelsInRepoByIDs(ctx.Repo.Repository.ID, form.Labels)
if err != nil {
ctx.Error(500, "GetLabelsInRepoByIDs", err)
@@ -294,11 +295,6 @@ func ClearIssueLabels(ctx *context.APIContext) {
// responses:
// "204":
// "$ref": "#/responses/empty"
- if !ctx.Repo.IsWriter() {
- ctx.Status(403)
- return
- }
-
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
if err != nil {
if models.IsErrIssueNotExist(err) {
@@ -309,6 +305,11 @@ func ClearIssueLabels(ctx *context.APIContext) {
return
}
+ if !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) {
+ ctx.Status(403)
+ return
+ }
+
if err := issue.ClearLabels(ctx.User); err != nil {
ctx.Error(500, "ClearLabels", err)
return
diff --git a/routers/api/v1/repo/label.go b/routers/api/v1/repo/label.go
index 359ccf0e41..df7a370041 100644
--- a/routers/api/v1/repo/label.go
+++ b/routers/api/v1/repo/label.go
@@ -1,4 +1,5 @@
// Copyright 2016 The Gogs Authors. All rights reserved.
+// Copyright 2018 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.
@@ -123,11 +124,6 @@ func CreateLabel(ctx *context.APIContext, form api.CreateLabelOption) {
// responses:
// "201":
// "$ref": "#/responses/Label"
- if !ctx.Repo.IsWriter() {
- ctx.Status(403)
- return
- }
-
label := &models.Label{
Name: form.Name,
Color: form.Color,
@@ -173,11 +169,6 @@ func EditLabel(ctx *context.APIContext, form api.EditLabelOption) {
// responses:
// "200":
// "$ref": "#/responses/Label"
- if !ctx.Repo.IsWriter() {
- ctx.Status(403)
- return
- }
-
label, err := models.GetLabelInRepoByID(ctx.Repo.Repository.ID, ctx.ParamsInt64(":id"))
if err != nil {
if models.IsErrLabelNotExist(err) {
@@ -226,11 +217,6 @@ func DeleteLabel(ctx *context.APIContext) {
// responses:
// "204":
// "$ref": "#/responses/empty"
- if !ctx.Repo.IsWriter() {
- ctx.Status(403)
- return
- }
-
if err := models.DeleteLabel(ctx.Repo.Repository.ID, ctx.ParamsInt64(":id")); err != nil {
ctx.Error(500, "DeleteLabel", err)
return
diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go
index 83ef886d7d..a0117794ad 100644
--- a/routers/api/v1/repo/pull.go
+++ b/routers/api/v1/repo/pull.go
@@ -351,7 +351,7 @@ func EditPullRequest(ctx *context.APIContext, form api.EditPullRequestOption) {
pr.LoadIssue()
issue := pr.Issue
- if !issue.IsPoster(ctx.User.ID) && !ctx.Repo.IsWriter() {
+ if !issue.IsPoster(ctx.User.ID) && !ctx.Repo.CanWrite(models.UnitTypePullRequests) {
ctx.Status(403)
return
}
@@ -382,7 +382,7 @@ func EditPullRequest(ctx *context.APIContext, form api.EditPullRequestOption) {
// Pass one or more user logins to replace the set of assignees on this Issue.
// Send an empty array ([]) to clear all assignees from the Issue.
- if ctx.Repo.IsWriter() && (form.Assignees != nil || len(form.Assignee) > 0) {
+ if ctx.Repo.CanWrite(models.UnitTypePullRequests) && (form.Assignees != nil || len(form.Assignee) > 0) {
err = models.UpdateAPIAssignee(issue, form.Assignee, form.Assignees, ctx.User)
if err != nil {
@@ -395,7 +395,7 @@ func EditPullRequest(ctx *context.APIContext, form api.EditPullRequestOption) {
}
}
- if ctx.Repo.IsWriter() && form.Milestone != 0 &&
+ if ctx.Repo.CanWrite(models.UnitTypePullRequests) && form.Milestone != 0 &&
issue.MilestoneID != form.Milestone {
oldMilestoneID := issue.MilestoneID
issue.MilestoneID = form.Milestone
@@ -405,7 +405,7 @@ func EditPullRequest(ctx *context.APIContext, form api.EditPullRequestOption) {
}
}
- if ctx.Repo.IsWriter() && (form.Labels != nil && len(form.Labels) > 0) {
+ if ctx.Repo.CanWrite(models.UnitTypePullRequests) && (form.Labels != nil && len(form.Labels) > 0) {
labels, err := models.GetLabelsInRepoByIDs(ctx.Repo.Repository.ID, form.Labels)
if err != nil {
ctx.Error(500, "GetLabelsInRepoByIDsError", err)
@@ -663,7 +663,12 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption)
}
}
- if !ctx.User.IsWriterOfRepo(headRepo) && !ctx.User.IsAdmin {
+ perm, err := models.GetUserRepoPermission(headRepo, ctx.User)
+ if err != nil {
+ ctx.ServerError("GetUserRepoPermission", err)
+ return nil, nil, nil, nil, "", ""
+ }
+ if !perm.CanWrite(models.UnitTypeCode) {
log.Trace("ParseCompareInfo[%d]: does not have write access or site admin", baseRepo.ID)
ctx.Status(404)
return nil, nil, nil, nil, "", ""
diff --git a/routers/api/v1/repo/release.go b/routers/api/v1/repo/release.go
index 282ff582c5..caa2905e93 100644
--- a/routers/api/v1/repo/release.go
+++ b/routers/api/v1/repo/release.go
@@ -122,10 +122,6 @@ func CreateRelease(ctx *context.APIContext, form api.CreateReleaseOption) {
// responses:
// "201":
// "$ref": "#/responses/Release"
- if ctx.Repo.AccessMode < models.AccessModeWrite {
- ctx.Status(403)
- return
- }
rel, err := models.GetRelease(ctx.Repo.Repository.ID, form.TagName)
if err != nil {
if !models.IsErrReleaseNotExist(err) {
@@ -209,10 +205,6 @@ func EditRelease(ctx *context.APIContext, form api.EditReleaseOption) {
// responses:
// "200":
// "$ref": "#/responses/Release"
- if ctx.Repo.AccessMode < models.AccessModeWrite {
- ctx.Status(403)
- return
- }
id := ctx.ParamsInt64(":id")
rel, err := models.GetReleaseByID(id)
if err != nil && !models.IsErrReleaseNotExist(err) {
@@ -285,10 +277,6 @@ func DeleteRelease(ctx *context.APIContext) {
// responses:
// "204":
// "$ref": "#/responses/empty"
- if ctx.Repo.AccessMode < models.AccessModeWrite {
- ctx.Status(403)
- return
- }
id := ctx.ParamsInt64(":id")
rel, err := models.GetReleaseByID(id)
if err != nil && !models.IsErrReleaseNotExist(err) {
diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go
index bf6346eebd..6d8125a77f 100644
--- a/routers/api/v1/repo/repo.go
+++ b/routers/api/v1/repo/repo.go
@@ -1,4 +1,5 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
+// Copyright 2018 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.
@@ -183,11 +184,6 @@ func Search(ctx *context.APIContext) {
return
}
- var userID int64
- if ctx.IsSigned {
- userID = ctx.User.ID
- }
-
results := make([]*api.Repository, len(repos))
for i, repo := range repos {
if err = repo.GetOwner(); err != nil {
@@ -197,7 +193,7 @@ func Search(ctx *context.APIContext) {
})
return
}
- accessMode, err := models.AccessLevel(userID, repo)
+ accessMode, err := models.AccessLevel(ctx.User, repo)
if err != nil {
ctx.JSON(500, api.SearchError{
OK: false,
@@ -469,15 +465,15 @@ func GetByID(ctx *context.APIContext) {
return
}
- access, err := models.AccessLevel(ctx.User.ID, repo)
+ perm, err := models.GetUserRepoPermission(repo, ctx.User)
if err != nil {
ctx.Error(500, "AccessLevel", err)
return
- } else if access < models.AccessModeRead {
+ } else if !perm.HasAccess() {
ctx.Status(404)
return
}
- ctx.JSON(200, repo.APIFormat(access))
+ ctx.JSON(200, repo.APIFormat(perm.AccessMode))
}
// Delete one repository
@@ -503,10 +499,6 @@ func Delete(ctx *context.APIContext) {
// "$ref": "#/responses/empty"
// "403":
// "$ref": "#/responses/forbidden"
- if !ctx.Repo.IsAdmin() {
- ctx.Error(403, "", "Must have admin rights")
- return
- }
owner := ctx.Repo.Owner
repo := ctx.Repo.Repository
@@ -553,7 +545,7 @@ func MirrorSync(ctx *context.APIContext) {
// "$ref": "#/responses/empty"
repo := ctx.Repo.Repository
- if !ctx.Repo.IsWriter() {
+ if !ctx.Repo.CanWrite(models.UnitTypeCode) {
ctx.Error(403, "MirrorSync", "Must have write access")
}
diff --git a/routers/api/v1/user/repo.go b/routers/api/v1/user/repo.go
index 5dccfac960..1ddb3bd57b 100644
--- a/routers/api/v1/user/repo.go
+++ b/routers/api/v1/user/repo.go
@@ -17,13 +17,10 @@ func listUserRepos(ctx *context.APIContext, u *models.User, private bool) {
ctx.Error(500, "GetUserRepositories", err)
return
}
+
apiRepos := make([]*api.Repository, 0, len(repos))
- var ctxUserID int64
- if ctx.User != nil {
- ctxUserID = ctx.User.ID
- }
for i := range repos {
- access, err := models.AccessLevel(ctxUserID, repos[i])
+ access, err := models.AccessLevel(ctx.User, repos[i])
if err != nil {
ctx.Error(500, "AccessLevel", err)
return
diff --git a/routers/api/v1/user/star.go b/routers/api/v1/user/star.go
index 1cf4f5239c..b0016399c8 100644
--- a/routers/api/v1/user/star.go
+++ b/routers/api/v1/user/star.go
@@ -13,15 +13,15 @@ import (
// getStarredRepos returns the repos that the user with the specified userID has
// starred
-func getStarredRepos(userID int64, private bool) ([]*api.Repository, error) {
- starredRepos, err := models.GetStarredRepos(userID, private)
+func getStarredRepos(user *models.User, private bool) ([]*api.Repository, error) {
+ starredRepos, err := models.GetStarredRepos(user.ID, private)
if err != nil {
return nil, err
}
repos := make([]*api.Repository, len(starredRepos))
for i, starred := range starredRepos {
- access, err := models.AccessLevel(userID, starred)
+ access, err := models.AccessLevel(user, starred)
if err != nil {
return nil, err
}
@@ -48,7 +48,7 @@ func GetStarredRepos(ctx *context.APIContext) {
// "$ref": "#/responses/RepositoryList"
user := GetUserByParams(ctx)
private := user.ID == ctx.User.ID
- repos, err := getStarredRepos(user.ID, private)
+ repos, err := getStarredRepos(user, private)
if err != nil {
ctx.Error(500, "getStarredRepos", err)
}
@@ -65,7 +65,7 @@ func GetMyStarredRepos(ctx *context.APIContext) {
// responses:
// "200":
// "$ref": "#/responses/RepositoryList"
- repos, err := getStarredRepos(ctx.User.ID, true)
+ repos, err := getStarredRepos(ctx.User, true)
if err != nil {
ctx.Error(500, "getStarredRepos", err)
}
diff --git a/routers/api/v1/user/watch.go b/routers/api/v1/user/watch.go
index 2971bf6869..4afa18be2a 100644
--- a/routers/api/v1/user/watch.go
+++ b/routers/api/v1/user/watch.go
@@ -14,15 +14,15 @@ import (
// getWatchedRepos returns the repos that the user with the specified userID is
// watching
-func getWatchedRepos(userID int64, private bool) ([]*api.Repository, error) {
- watchedRepos, err := models.GetWatchedRepos(userID, private)
+func getWatchedRepos(user *models.User, private bool) ([]*api.Repository, error) {
+ watchedRepos, err := models.GetWatchedRepos(user.ID, private)
if err != nil {
return nil, err
}
repos := make([]*api.Repository, len(watchedRepos))
for i, watched := range watchedRepos {
- access, err := models.AccessLevel(userID, watched)
+ access, err := models.AccessLevel(user, watched)
if err != nil {
return nil, err
}
@@ -49,7 +49,7 @@ func GetWatchedRepos(ctx *context.APIContext) {
// "$ref": "#/responses/RepositoryList"
user := GetUserByParams(ctx)
private := user.ID == ctx.User.ID
- repos, err := getWatchedRepos(user.ID, private)
+ repos, err := getWatchedRepos(user, private)
if err != nil {
ctx.Error(500, "getWatchedRepos", err)
}
@@ -66,7 +66,7 @@ func GetMyWatchedRepos(ctx *context.APIContext) {
// responses:
// "200":
// "$ref": "#/responses/RepositoryList"
- repos, err := getWatchedRepos(ctx.User.ID, true)
+ repos, err := getWatchedRepos(ctx.User, true)
if err != nil {
ctx.Error(500, "getWatchedRepos", err)
}
diff --git a/routers/private/internal.go b/routers/private/internal.go
index 23e0122642..0221b1fee8 100644
--- a/routers/private/internal.go
+++ b/routers/private/internal.go
@@ -38,8 +38,8 @@ func GetRepositoryByOwnerAndName(ctx *macaron.Context) {
ctx.JSON(200, repo)
}
-//AccessLevel chainload to models.AccessLevel
-func AccessLevel(ctx *macaron.Context) {
+//CheckUnitUser chainload to models.CheckUnitUser
+func CheckUnitUser(ctx *macaron.Context) {
repoID := ctx.ParamsInt64(":repoid")
userID := ctx.ParamsInt64(":userid")
repo, err := models.GetRepositoryByID(repoID)
@@ -49,32 +49,27 @@ func AccessLevel(ctx *macaron.Context) {
})
return
}
- al, err := models.AccessLevel(userID, repo)
- if err != nil {
- ctx.JSON(500, map[string]interface{}{
- "err": err.Error(),
- })
- return
+
+ var user *models.User
+ if userID > 0 {
+ user, err = models.GetUserByID(userID)
+ if err != nil {
+ ctx.JSON(500, map[string]interface{}{
+ "err": err.Error(),
+ })
+ return
+ }
}
- ctx.JSON(200, al)
-}
-//CheckUnitUser chainload to models.CheckUnitUser
-func CheckUnitUser(ctx *macaron.Context) {
- repoID := ctx.ParamsInt64(":repoid")
- userID := ctx.ParamsInt64(":userid")
- repo, err := models.GetRepositoryByID(repoID)
+ perm, err := models.GetUserRepoPermission(repo, user)
if err != nil {
ctx.JSON(500, map[string]interface{}{
"err": err.Error(),
})
return
}
- if repo.CheckUnitUser(userID, ctx.QueryBool("isAdmin"), models.UnitType(ctx.QueryInt("unitType"))) {
- ctx.PlainText(200, []byte("success"))
- return
- }
- ctx.PlainText(404, []byte("no access"))
+
+ ctx.JSON(200, perm.UnitAccessMode(models.UnitType(ctx.QueryInt("unitType"))))
}
// RegisterRoutes registers all internal APIs routes to web application.
@@ -85,7 +80,6 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/ssh/:id/user", GetUserByKeyID)
m.Post("/ssh/:id/update", UpdatePublicKey)
m.Post("/repositories/:repoid/keys/:keyid/update", UpdateDeployKey)
- m.Get("/repositories/:repoid/user/:userid/accesslevel", AccessLevel)
m.Get("/repositories/:repoid/user/:userid/checkunituser", CheckUnitUser)
m.Get("/repositories/:repoid/has-keys/:keyid", HasDeployKey)
m.Post("/push/update", PushUpdate)
diff --git a/routers/repo/activity.go b/routers/repo/activity.go
index a0a25dc936..5d90d73506 100644
--- a/routers/repo/activity.go
+++ b/routers/repo/activity.go
@@ -45,9 +45,9 @@ func Activity(ctx *context.Context) {
var err error
if ctx.Data["Activity"], err = models.GetActivityStats(ctx.Repo.Repository.ID, timeFrom,
- ctx.Repo.Repository.UnitEnabled(models.UnitTypeReleases),
- ctx.Repo.Repository.UnitEnabled(models.UnitTypeIssues),
- ctx.Repo.Repository.UnitEnabled(models.UnitTypePullRequests)); err != nil {
+ ctx.Repo.CanRead(models.UnitTypeReleases),
+ ctx.Repo.CanRead(models.UnitTypeIssues),
+ ctx.Repo.CanRead(models.UnitTypePullRequests)); err != nil {
ctx.ServerError("GetActivityStats", err)
return
}
diff --git a/routers/repo/branch.go b/routers/repo/branch.go
index 7b1e2a8bbe..295aeaa24b 100644
--- a/routers/repo/branch.go
+++ b/routers/repo/branch.go
@@ -1,4 +1,5 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
+// Copyright 2018 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.
@@ -33,7 +34,7 @@ func Branches(ctx *context.Context) {
ctx.Data["Title"] = "Branches"
ctx.Data["IsRepoToolbarBranches"] = true
ctx.Data["DefaultBranch"] = ctx.Repo.Repository.DefaultBranch
- ctx.Data["IsWriter"] = ctx.Repo.IsWriter()
+ ctx.Data["IsWriter"] = ctx.Repo.CanWrite(models.UnitTypeCode)
ctx.Data["IsMirror"] = ctx.Repo.Repository.IsMirror
ctx.Data["PageIsViewCode"] = true
ctx.Data["PageIsBranches"] = true
@@ -161,7 +162,7 @@ func loadBranches(ctx *context.Context) []*Branch {
}
}
- if ctx.Repo.IsWriter() {
+ if ctx.Repo.CanWrite(models.UnitTypeCode) {
deletedBranches, err := getDeletedBranches(ctx)
if err != nil {
ctx.ServerError("getDeletedBranches", err)
diff --git a/routers/repo/http.go b/routers/repo/http.go
index 5b469754ad..ec5fbe6c0d 100644
--- a/routers/repo/http.go
+++ b/routers/repo/http.go
@@ -182,36 +182,19 @@ func HTTP(ctx *context.Context) {
}
}
- if !isPublicPull {
- has, err := models.HasAccess(authUser.ID, repo, accessMode)
- if err != nil {
- ctx.ServerError("HasAccess", err)
- return
- } else if !has {
- if accessMode == models.AccessModeRead {
- has, err = models.HasAccess(authUser.ID, repo, models.AccessModeWrite)
- if err != nil {
- ctx.ServerError("HasAccess2", err)
- return
- } else if !has {
- ctx.HandleText(http.StatusForbidden, "User permission denied")
- return
- }
- } else {
- ctx.HandleText(http.StatusForbidden, "User permission denied")
- return
- }
- }
+ perm, err := models.GetUserRepoPermission(repo, authUser)
+ if err != nil {
+ ctx.ServerError("GetUserRepoPermission", err)
+ return
+ }
- if !isPull && repo.IsMirror {
- ctx.HandleText(http.StatusForbidden, "mirror repository is read-only")
- return
- }
+ if !perm.CanAccess(accessMode, unitType) {
+ ctx.HandleText(http.StatusForbidden, "User permission denied")
+ return
}
- if !repo.CheckUnitUser(authUser.ID, authUser.IsAdmin, unitType) {
- ctx.HandleText(http.StatusForbidden, fmt.Sprintf("User %s does not have allowed access to repository %s 's code",
- authUser.Name, repo.RepoPath()))
+ if !isPull && repo.IsMirror {
+ ctx.HandleText(http.StatusForbidden, "mirror repository is read-only")
return
}
diff --git a/routers/repo/issue.go b/routers/repo/issue.go
index 08bdf311f9..8d95f33940 100644
--- a/routers/repo/issue.go
+++ b/routers/repo/issue.go
@@ -1,4 +1,5 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
+// Copyright 2018 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.
@@ -63,8 +64,8 @@ var (
// MustEnableIssues check if repository enable internal issues
func MustEnableIssues(ctx *context.Context) {
- if !ctx.Repo.Repository.UnitEnabled(models.UnitTypeIssues) &&
- !ctx.Repo.Repository.UnitEnabled(models.UnitTypeExternalTracker) {
+ if !ctx.Repo.CanRead(models.UnitTypeIssues) &&
+ !ctx.Repo.CanRead(models.UnitTypeExternalTracker) {
ctx.NotFound("MustEnableIssues", nil)
return
}
@@ -76,9 +77,9 @@ func MustEnableIssues(ctx *context.Context) {
}
}
-// MustAllowPulls check if repository enable pull requests
+// MustAllowPulls check if repository enable pull requests and user have right to do that
func MustAllowPulls(ctx *context.Context) {
- if !ctx.Repo.Repository.AllowsPulls() {
+ if !ctx.Repo.Repository.CanEnablePulls() || !ctx.Repo.CanRead(models.UnitTypePullRequests) {
ctx.NotFound("MustAllowPulls", nil)
return
}
@@ -280,7 +281,7 @@ func RetrieveRepoMilestonesAndAssignees(ctx *context.Context, repo *models.Repos
// RetrieveRepoMetas find all the meta information of a repository
func RetrieveRepoMetas(ctx *context.Context, repo *models.Repository) []*models.Label {
- if !ctx.Repo.IsWriter() {
+ if !ctx.Repo.CanWrite(models.UnitTypeIssues) {
return nil
}
@@ -369,7 +370,7 @@ func NewIssue(ctx *context.Context) {
}
// ValidateRepoMetas check and returns repository's meta informations
-func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm) ([]int64, []int64, int64) {
+func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm, isPull bool) ([]int64, []int64, int64) {
var (
repo = ctx.Repo.Repository
err error
@@ -380,10 +381,6 @@ func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm) ([]int64
return nil, nil, 0
}
- if !ctx.Repo.IsWriter() {
- return nil, nil, 0
- }
-
var labelIDs []int64
hasSelected := false
// Check labels.
@@ -427,9 +424,19 @@ func ValidateRepoMetas(ctx *context.Context, form auth.CreateIssueForm) ([]int64
// Check if the passed assignees actually exists and has write access to the repo
for _, aID := range assigneeIDs {
- _, err = repo.GetUserIfHasWriteAccess(aID)
+ user, err := models.GetUserByID(aID)
+ if err != nil {
+ ctx.ServerError("GetUserByID", err)
+ return nil, nil, 0
+ }
+
+ perm, err := models.GetUserRepoPermission(repo, user)
if err != nil {
- ctx.ServerError("GetUserIfHasWriteAccess", err)
+ ctx.ServerError("GetUserRepoPermission", err)
+ return nil, nil, 0
+ }
+ if !perm.CanWriteIssuesOrPulls(isPull) {
+ ctx.ServerError("CanWriteIssuesOrPulls", fmt.Errorf("No permission for %s", user.Name))
return nil, nil, 0
}
}
@@ -458,7 +465,7 @@ func NewIssuePost(ctx *context.Context, form auth.CreateIssueForm) {
attachments []string
)
- labelIDs, assigneeIDs, milestoneID := ValidateRepoMetas(ctx, form)
+ labelIDs, assigneeIDs, milestoneID := ValidateRepoMetas(ctx, form, false)
if ctx.Written() {
return
}
@@ -498,31 +505,23 @@ func NewIssuePost(ctx *context.Context, form auth.CreateIssueForm) {
// commentTag returns the CommentTag for a comment in/with the given repo, poster and issue
func commentTag(repo *models.Repository, poster *models.User, issue *models.Issue) (models.CommentTag, error) {
- if repo.IsOwnedBy(poster.ID) {
- return models.CommentTagOwner, nil
- } else if repo.Owner.IsOrganization() {
- isOwner, err := repo.Owner.IsOwnedBy(poster.ID)
- if err != nil {
- return models.CommentTagNone, err
- } else if isOwner {
- return models.CommentTagOwner, nil
- }
+ perm, err := models.GetUserRepoPermission(repo, poster)
+ if err != nil {
+ return models.CommentTagNone, err
}
- if poster.IsWriterOfRepo(repo) {
- return models.CommentTagWriter, nil
+ if perm.IsOwner() {
+ return models.CommentTagOwner, nil
} else if poster.ID == issue.PosterID {
return models.CommentTagPoster, nil
+ } else if perm.CanWrite(models.UnitTypeCode) {
+ return models.CommentTagWriter, nil
}
+
return models.CommentTagNone, nil
}
// ViewIssue render issue view page
func ViewIssue(ctx *context.Context) {
- ctx.Data["RequireHighlightJS"] = true
- ctx.Data["RequireDropzone"] = true
- ctx.Data["RequireTribute"] = true
- renderAttachmentSettings(ctx)
-
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
if err != nil {
if models.IsErrIssueNotExist(err) {
@@ -532,25 +531,6 @@ func ViewIssue(ctx *context.Context) {
}
return
}
- ctx.Data["Title"] = fmt.Sprintf("#%d - %s", issue.Index, issue.Title)
-
- var iw *models.IssueWatch
- var exists bool
- if ctx.User != nil {
- iw, exists, err = models.GetIssueWatch(ctx.User.ID, issue.ID)
- if err != nil {
- ctx.ServerError("GetIssueWatch", err)
- return
- }
- if !exists {
- iw = &models.IssueWatch{
- UserID: ctx.User.ID,
- IssueID: issue.ID,
- IsWatching: models.IsWatching(ctx.User.ID, ctx.Repo.Repository.ID),
- }
- }
- }
- ctx.Data["IssueWatch"] = iw
// Make sure type and URL matches.
if ctx.Params(":type") == "issues" && issue.IsPull {
@@ -576,6 +556,31 @@ func ViewIssue(ctx *context.Context) {
ctx.Data["PageIsIssueList"] = true
}
+ ctx.Data["RequireHighlightJS"] = true
+ ctx.Data["RequireDropzone"] = true
+ ctx.Data["RequireTribute"] = true
+ renderAttachmentSettings(ctx)
+
+ ctx.Data["Title"] = fmt.Sprintf("#%d - %s", issue.Index, issue.Title)
+
+ var iw *models.IssueWatch
+ var exists bool
+ if ctx.User != nil {
+ iw, exists, err = models.GetIssueWatch(ctx.User.ID, issue.ID)
+ if err != nil {
+ ctx.ServerError("GetIssueWatch", err)
+ return
+ }
+ if !exists {
+ iw = &models.IssueWatch{
+ UserID: ctx.User.ID,
+ IssueID: issue.ID,
+ IsWatching: models.IsWatching(ctx.User.ID, ctx.Repo.Repository.ID),
+ }
+ }
+ }
+ ctx.Data["IssueWatch"] = iw
+
issue.RenderedContent = string(markdown.Render([]byte(issue.Content), ctx.Repo.RepoLink,
ctx.Repo.Repository.ComposeMetas()))
@@ -616,7 +621,7 @@ func ViewIssue(ctx *context.Context) {
ctx.Data["Labels"] = labels
// Check milestone and assignee.
- if ctx.Repo.IsWriter() {
+ if ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) {
RetrieveRepoMilestonesAndAssignees(ctx, repo)
if ctx.Written() {
return
@@ -761,13 +766,20 @@ func ViewIssue(ctx *context.Context) {
if ctx.IsSigned {
if err := pull.GetHeadRepo(); err != nil {
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, ctx.User); err != nil {
- log.Error(4, "IsProtectedBranch: %v", err)
- } else if !protected {
- canDelete = true
- ctx.Data["DeleteBranchLink"] = ctx.Repo.RepoLink + "/pulls/" + com.ToStr(issue.Index) + "/cleanup"
+ } else if pull.HeadRepo != nil && pull.HeadBranch != pull.HeadRepo.DefaultBranch {
+ perm, err := models.GetUserRepoPermission(pull.HeadRepo, ctx.User)
+ if err != nil {
+ ctx.ServerError("GetUserRepoPermission", err)
+ return
+ }
+ if perm.CanWrite(models.UnitTypeCode) {
+ // Check if branch is not protected
+ if protected, err := pull.HeadRepo.IsProtectedBranch(pull.HeadBranch, ctx.User); err != nil {
+ log.Error(4, "IsProtectedBranch: %v", err)
+ } else if !protected {
+ canDelete = true
+ ctx.Data["DeleteBranchLink"] = ctx.Repo.RepoLink + "/pulls/" + com.ToStr(issue.Index) + "/cleanup"
+ }
}
}
}
@@ -779,7 +791,7 @@ func ViewIssue(ctx *context.Context) {
}
prConfig := prUnit.PullRequestsConfig()
- ctx.Data["AllowMerge"] = ctx.Data["IsRepositoryWriter"]
+ ctx.Data["AllowMerge"] = ctx.Repo.CanWrite(models.UnitTypeCode)
if err := pull.CheckUserAllowedToMerge(ctx.User); err != nil {
if !models.IsErrNotAllowedToMerge(err) {
ctx.ServerError("CheckUserAllowedToMerge", err)
@@ -818,8 +830,9 @@ func ViewIssue(ctx *context.Context) {
ctx.Data["NumParticipants"] = len(participants)
ctx.Data["Issue"] = issue
ctx.Data["ReadOnly"] = true
- ctx.Data["IsIssueOwner"] = ctx.Repo.IsWriter() || (ctx.IsSigned && issue.IsPoster(ctx.User.ID))
ctx.Data["SignInLink"] = setting.AppSubURL + "/user/login?redirect_to=" + ctx.Data["Link"].(string)
+ ctx.Data["IsIssuePoster"] = ctx.IsSigned && issue.IsPoster(ctx.User.ID)
+ ctx.Data["IsIssueWriter"] = ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull)
ctx.HTML(200, tplIssueView)
}
@@ -842,8 +855,8 @@ func GetActionIssue(ctx *context.Context) *models.Issue {
}
func checkIssueRights(ctx *context.Context, issue *models.Issue) {
- if issue.IsPull && !ctx.Repo.Repository.UnitEnabled(models.UnitTypePullRequests) ||
- !issue.IsPull && !ctx.Repo.Repository.UnitEnabled(models.UnitTypeIssues) {
+ if issue.IsPull && !ctx.Repo.CanRead(models.UnitTypePullRequests) ||
+ !issue.IsPull && !ctx.Repo.CanRead(models.UnitTypeIssues) {
ctx.NotFound("IssueOrPullRequestUnitNotAllowed", nil)
}
}
@@ -868,8 +881,8 @@ func getActionIssues(ctx *context.Context) []*models.Issue {
return nil
}
// Check access rights for all issues
- issueUnitEnabled := ctx.Repo.Repository.UnitEnabled(models.UnitTypeIssues)
- prUnitEnabled := ctx.Repo.Repository.UnitEnabled(models.UnitTypePullRequests)
+ issueUnitEnabled := ctx.Repo.CanRead(models.UnitTypeIssues)
+ prUnitEnabled := ctx.Repo.CanRead(models.UnitTypePullRequests)
for _, issue := range issues {
if issue.IsPull && !prUnitEnabled || !issue.IsPull && !issueUnitEnabled {
ctx.NotFound("IssueOrPullRequestUnitNotAllowed", nil)
@@ -890,7 +903,7 @@ func UpdateIssueTitle(ctx *context.Context) {
return
}
- if !ctx.IsSigned || (!issue.IsPoster(ctx.User.ID) && !ctx.Repo.IsWriter()) {
+ if !ctx.IsSigned || (!issue.IsPoster(ctx.User.ID) && !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull)) {
ctx.Error(403)
return
}
@@ -918,7 +931,7 @@ func UpdateIssueContent(ctx *context.Context) {
return
}
- if !ctx.IsSigned || (ctx.User.ID != issue.PosterID && !ctx.Repo.IsWriter()) {
+ if !ctx.IsSigned || (ctx.User.ID != issue.PosterID && !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull)) {
ctx.Error(403)
return
}
@@ -1037,6 +1050,11 @@ func NewComment(ctx *context.Context, form auth.CreateCommentForm) {
return
}
+ if !ctx.IsSigned || (ctx.User.ID != issue.PosterID && !ctx.Repo.CanReadIssuesOrPulls(issue.IsPull)) {
+ ctx.Error(403)
+ return
+ }
+
var attachments []string
if setting.AttachmentEnabled {
attachments = form.Files
@@ -1051,7 +1069,7 @@ func NewComment(ctx *context.Context, form auth.CreateCommentForm) {
var comment *models.Comment
defer func() {
// Check if issue admin/poster changes the status of issue.
- if (ctx.Repo.IsWriter() || (ctx.IsSigned && issue.IsPoster(ctx.User.ID))) &&
+ if (ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) || (ctx.IsSigned && issue.IsPoster(ctx.User.ID))) &&
(form.Status == "reopen" || form.Status == "close") &&
!(issue.IsPull && issue.PullRequest.HasMerged) {
@@ -1140,7 +1158,12 @@ func UpdateCommentContent(ctx *context.Context) {
return
}
- if !ctx.IsSigned || (ctx.User.ID != comment.PosterID && !ctx.Repo.IsAdmin()) {
+ if err := comment.LoadIssue(); err != nil {
+ ctx.NotFoundOrServerError("LoadIssue", models.IsErrIssueNotExist, err)
+ return
+ }
+
+ if !ctx.IsSigned || (ctx.User.ID != comment.PosterID && !ctx.Repo.CanWriteIssuesOrPulls(comment.Issue.IsPull)) {
ctx.Error(403)
return
} else if comment.Type != models.CommentTypeComment && comment.Type != models.CommentTypeCode {
@@ -1174,7 +1197,12 @@ func DeleteComment(ctx *context.Context) {
return
}
- if !ctx.IsSigned || (ctx.User.ID != comment.PosterID && !ctx.Repo.IsAdmin()) {
+ if err := comment.LoadIssue(); err != nil {
+ ctx.NotFoundOrServerError("LoadIssue", models.IsErrIssueNotExist, err)
+ return
+ }
+
+ if !ctx.IsSigned || (ctx.User.ID != comment.PosterID && !ctx.Repo.CanWriteIssuesOrPulls(comment.Issue.IsPull)) {
ctx.Error(403)
return
} else if comment.Type != models.CommentTypeComment && comment.Type != models.CommentTypeCode {
@@ -1417,6 +1445,11 @@ func ChangeIssueReaction(ctx *context.Context, form auth.ReactionForm) {
return
}
+ if !ctx.IsSigned || (ctx.User.ID != issue.PosterID && !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull)) {
+ ctx.Error(403)
+ return
+ }
+
if ctx.HasError() {
ctx.ServerError("ChangeIssueReaction", errors.New(ctx.GetErrMsg()))
return
@@ -1486,20 +1519,22 @@ func ChangeCommentReaction(ctx *context.Context, form auth.ReactionForm) {
return
}
- issue, err := models.GetIssueByID(comment.IssueID)
- checkIssueRights(ctx, issue)
- if ctx.Written() {
+ if err := comment.LoadIssue(); err != nil {
+ ctx.NotFoundOrServerError("LoadIssue", models.IsErrIssueNotExist, err)
return
}
- if ctx.HasError() {
- ctx.ServerError("ChangeCommentReaction", errors.New(ctx.GetErrMsg()))
+ if !ctx.IsSigned || (ctx.User.ID != comment.PosterID && !ctx.Repo.CanWriteIssuesOrPulls(comment.Issue.IsPull)) {
+ ctx.Error(403)
+ return
+ } else if comment.Type != models.CommentTypeComment && comment.Type != models.CommentTypeCode {
+ ctx.Error(204)
return
}
switch ctx.Params(":action") {
case "react":
- reaction, err := models.CreateCommentReaction(ctx.User, issue, comment, form.Content)
+ reaction, err := models.CreateCommentReaction(ctx.User, comment.Issue, comment, form.Content)
if err != nil {
log.Info("CreateCommentReaction: %s", err)
break
@@ -1511,9 +1546,9 @@ func ChangeCommentReaction(ctx *context.Context, form auth.ReactionForm) {
break
}
- log.Trace("Reaction for comment created: %d/%d/%d/%d", ctx.Repo.Repository.ID, issue.ID, comment.ID, reaction.ID)
+ log.Trace("Reaction for comment created: %d/%d/%d/%d", ctx.Repo.Repository.ID, comment.Issue.ID, comment.ID, reaction.ID)
case "unreact":
- if err := models.DeleteCommentReaction(ctx.User, issue, comment, form.Content); err != nil {
+ if err := models.DeleteCommentReaction(ctx.User, comment.Issue, comment, form.Content); err != nil {
ctx.ServerError("DeleteCommentReaction", err)
return
}
@@ -1525,7 +1560,7 @@ func ChangeCommentReaction(ctx *context.Context, form auth.ReactionForm) {
break
}
- log.Trace("Reaction for comment removed: %d/%d/%d", ctx.Repo.Repository.ID, issue.ID, comment.ID)
+ log.Trace("Reaction for comment removed: %d/%d/%d", ctx.Repo.Repository.ID, comment.Issue.ID, comment.ID)
default:
ctx.NotFound(fmt.Sprintf("Unknown action %s", ctx.Params(":action")), nil)
return
diff --git a/routers/repo/issue_watch.go b/routers/repo/issue_watch.go
index a499b70d9c..c6a436801a 100644
--- a/routers/repo/issue_watch.go
+++ b/routers/repo/issue_watch.go
@@ -14,23 +14,28 @@ import (
)
// IssueWatch sets issue watching
-func IssueWatch(c *context.Context) {
- watch, err := strconv.ParseBool(c.Req.PostForm.Get("watch"))
- if err != nil {
- c.ServerError("watch is not bool", err)
+func IssueWatch(ctx *context.Context) {
+ issue := GetActionIssue(ctx)
+ if ctx.Written() {
return
}
- issue := GetActionIssue(c)
- if c.Written() {
+ if !ctx.IsSigned || (ctx.User.ID != issue.PosterID && !ctx.Repo.CanReadIssuesOrPulls(issue.IsPull)) {
+ ctx.Error(403)
+ return
+ }
+
+ watch, err := strconv.ParseBool(ctx.Req.PostForm.Get("watch"))
+ if err != nil {
+ ctx.ServerError("watch is not bool", err)
return
}
- if err := models.CreateOrUpdateIssueWatch(c.User.ID, issue.ID, watch); err != nil {
- c.ServerError("CreateOrUpdateIssueWatch", err)
+ if err := models.CreateOrUpdateIssueWatch(ctx.User.ID, issue.ID, watch); err != nil {
+ ctx.ServerError("CreateOrUpdateIssueWatch", err)
return
}
- url := fmt.Sprintf("%s/issues/%d", c.Repo.RepoLink, issue.Index)
- c.Redirect(url, http.StatusSeeOther)
+ url := fmt.Sprintf("%s/issues/%d", ctx.Repo.RepoLink, issue.Index)
+ ctx.Redirect(url, http.StatusSeeOther)
}
diff --git a/routers/repo/pull.go b/routers/repo/pull.go
index 4ec1c27cea..4adfb96e74 100644
--- a/routers/repo/pull.go
+++ b/routers/repo/pull.go
@@ -57,7 +57,13 @@ func getForkRepository(ctx *context.Context) *models.Repository {
return nil
}
- if !forkRepo.CanBeForked() || !forkRepo.HasAccess(ctx.User) {
+ perm, err := models.GetUserRepoPermission(forkRepo, ctx.User)
+ if err != nil {
+ ctx.ServerError("GetUserRepoPermission", err)
+ return nil
+ }
+
+ if forkRepo.IsBare || !perm.CanRead(models.UnitTypeCode) {
ctx.NotFound("getForkRepository", nil)
return nil
}
@@ -669,7 +675,12 @@ func ParseCompareInfo(ctx *context.Context) (*models.User, *models.Repository, *
}
}
- if !ctx.User.IsWriterOfRepo(headRepo) && !ctx.User.IsAdmin {
+ perm, err := models.GetUserRepoPermission(headRepo, ctx.User)
+ if err != nil {
+ ctx.ServerError("GetUserRepoPermission", err)
+ return nil, nil, nil, nil, "", ""
+ }
+ if !perm.CanWrite(models.UnitTypeCode) {
log.Trace("ParseCompareInfo[%d]: does not have write access or site admin", baseRepo.ID)
ctx.NotFound("ParseCompareInfo", nil)
return nil, nil, nil, nil, "", ""
@@ -823,7 +834,7 @@ func CompareAndPullRequestPost(ctx *context.Context, form auth.CreateIssueForm)
return
}
- labelIDs, assigneeIDs, milestoneID := ValidateRepoMetas(ctx, form)
+ labelIDs, assigneeIDs, milestoneID := ValidateRepoMetas(ctx, form, true)
if ctx.Written() {
return
}
@@ -969,7 +980,12 @@ func CleanUpPullRequest(ctx *context.Context) {
return
}
- if !ctx.User.IsWriterOfRepo(pr.HeadRepo) {
+ perm, err := models.GetUserRepoPermission(pr.HeadRepo, ctx.User)
+ if err != nil {
+ ctx.ServerError("GetUserRepoPermission", err)
+ return
+ }
+ if !perm.CanWrite(models.UnitTypeCode) {
ctx.NotFound("CleanUpPullRequest", nil)
return
}
diff --git a/routers/repo/release.go b/routers/repo/release.go
index bae87efdcd..5a869520f0 100644
--- a/routers/repo/release.go
+++ b/routers/repo/release.go
@@ -1,4 +1,5 @@
// Copyright 2014 The Gogs Authors. All rights reserved.
+// Copyright 2018 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.
@@ -65,8 +66,11 @@ func Releases(ctx *context.Context) {
limit = 10
}
+ writeAccess := ctx.Repo.CanWrite(models.UnitTypeReleases)
+ ctx.Data["CanCreateRelease"] = writeAccess
+
opts := models.FindReleasesOptions{
- IncludeDrafts: ctx.Repo.IsWriter(),
+ IncludeDrafts: writeAccess,
IncludeTags: true,
}
diff --git a/routers/repo/setting_protected_branch.go b/routers/repo/setting_protected_branch.go
index db12f0afcd..c8f6f843da 100644
--- a/routers/repo/setting_protected_branch.go
+++ b/routers/repo/setting_protected_branch.go
@@ -165,12 +165,21 @@ func SettingsProtectedBranchPost(ctx *context.Context, f auth.ProtectBranchForm)
}
}
+ var whitelistUsers, whitelistTeams, mergeWhitelistUsers, mergeWhitelistTeams []int64
protectBranch.EnableWhitelist = f.EnableWhitelist
- whitelistUsers, _ := base.StringsToInt64s(strings.Split(f.WhitelistUsers, ","))
- whitelistTeams, _ := base.StringsToInt64s(strings.Split(f.WhitelistTeams, ","))
+ if strings.TrimSpace(f.WhitelistUsers) != "" {
+ whitelistUsers, _ = base.StringsToInt64s(strings.Split(f.WhitelistUsers, ","))
+ }
+ if strings.TrimSpace(f.WhitelistTeams) != "" {
+ whitelistTeams, _ = base.StringsToInt64s(strings.Split(f.WhitelistTeams, ","))
+ }
protectBranch.EnableMergeWhitelist = f.EnableMergeWhitelist
- mergeWhitelistUsers, _ := base.StringsToInt64s(strings.Split(f.MergeWhitelistUsers, ","))
- mergeWhitelistTeams, _ := base.StringsToInt64s(strings.Split(f.MergeWhitelistTeams, ","))
+ if strings.TrimSpace(f.MergeWhitelistUsers) != "" {
+ mergeWhitelistUsers, _ = base.StringsToInt64s(strings.Split(f.MergeWhitelistUsers, ","))
+ }
+ if strings.TrimSpace(f.MergeWhitelistTeams) != "" {
+ mergeWhitelistTeams, _ = base.StringsToInt64s(strings.Split(f.MergeWhitelistTeams, ","))
+ }
err = models.UpdateProtectBranch(ctx.Repo.Repository, protectBranch, whitelistUsers, whitelistTeams, mergeWhitelistUsers, mergeWhitelistTeams)
if err != nil {
ctx.ServerError("UpdateProtectBranch", err)
diff --git a/routers/repo/view.go b/routers/repo/view.go
index 657fe315a2..78a305aa28 100644
--- a/routers/repo/view.go
+++ b/routers/repo/view.go
@@ -137,7 +137,7 @@ func renderDirectory(ctx *context.Context, treeLink string) {
ctx.Data["LatestCommitStatus"] = models.CalcCommitStatus(statuses)
// Check permission to add or upload new file.
- if ctx.Repo.IsWriter() && ctx.Repo.IsViewBranch {
+ if ctx.Repo.CanWrite(models.UnitTypeCode) && ctx.Repo.IsViewBranch {
ctx.Data["CanAddFile"] = true
ctx.Data["CanUploadFile"] = setting.Repository.Upload.Enabled
}
@@ -256,7 +256,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
ctx.Data["EditFileTooltip"] = ctx.Tr("repo.editor.edit_this_file")
} else if !ctx.Repo.IsViewBranch {
ctx.Data["EditFileTooltip"] = ctx.Tr("repo.editor.must_be_on_a_branch")
- } else if !ctx.Repo.IsWriter() {
+ } else if !ctx.Repo.CanWrite(models.UnitTypeCode) {
ctx.Data["EditFileTooltip"] = ctx.Tr("repo.editor.fork_before_edit")
}
@@ -275,16 +275,16 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
ctx.Data["DeleteFileTooltip"] = ctx.Tr("repo.editor.delete_this_file")
} else if !ctx.Repo.IsViewBranch {
ctx.Data["DeleteFileTooltip"] = ctx.Tr("repo.editor.must_be_on_a_branch")
- } else if !ctx.Repo.IsWriter() {
+ } else if !ctx.Repo.CanWrite(models.UnitTypeCode) {
ctx.Data["DeleteFileTooltip"] = ctx.Tr("repo.editor.must_have_write_access")
}
}
// Home render repository home page
func Home(ctx *context.Context) {
- if len(ctx.Repo.Repository.Units) > 0 {
+ if len(ctx.Repo.Units) > 0 {
var firstUnit *models.Unit
- for _, repoUnit := range ctx.Repo.Repository.Units {
+ for _, repoUnit := range ctx.Repo.Units {
if repoUnit.Type == models.UnitTypeCode {
renderCode(ctx)
return
diff --git a/routers/repo/wiki.go b/routers/repo/wiki.go
index 3220ab134d..2349236358 100644
--- a/routers/repo/wiki.go
+++ b/routers/repo/wiki.go
@@ -1,4 +1,5 @@
// Copyright 2015 The Gogs Authors. All rights reserved.
+// Copyright 2018 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.
@@ -30,8 +31,8 @@ const (
// MustEnableWiki check if wiki is enabled, if external then redirect
func MustEnableWiki(ctx *context.Context) {
- if !ctx.Repo.Repository.UnitEnabled(models.UnitTypeWiki) &&
- !ctx.Repo.Repository.UnitEnabled(models.UnitTypeExternalWiki) {
+ if !ctx.Repo.CanRead(models.UnitTypeWiki) &&
+ !ctx.Repo.CanRead(models.UnitTypeExternalWiki) {
ctx.NotFound("MustEnableWiki", nil)
return
}
@@ -200,6 +201,7 @@ func renderWikiPage(ctx *context.Context, isViewPage bool) (*git.Repository, *gi
// Wiki renders single wiki page
func Wiki(ctx *context.Context) {
ctx.Data["PageIsWiki"] = true
+ ctx.Data["CanWriteWiki"] = ctx.Repo.CanWrite(models.UnitTypeWiki)
if !ctx.Repo.Repository.HasWiki() {
ctx.Data["Title"] = ctx.Tr("repo.wiki")
@@ -235,14 +237,15 @@ func Wiki(ctx *context.Context) {
// WikiPages render wiki pages list page
func WikiPages(ctx *context.Context) {
- ctx.Data["Title"] = ctx.Tr("repo.wiki.pages")
- ctx.Data["PageIsWiki"] = true
-
if !ctx.Repo.Repository.HasWiki() {
ctx.Redirect(ctx.Repo.RepoLink + "/wiki")
return
}
+ ctx.Data["Title"] = ctx.Tr("repo.wiki.pages")
+ ctx.Data["PageIsWiki"] = true
+ ctx.Data["CanWriteWiki"] = ctx.Repo.CanWrite(models.UnitTypeWiki)
+
wikiRepo, commit, err := findWikiRepoCommit(ctx)
if err != nil {
return
diff --git a/routers/routes/routes.go b/routers/routes/routes.go
index 1c1bcd8f95..eb5841f593 100644
--- a/routers/routes/routes.go
+++ b/routers/routes/routes.go
@@ -393,7 +393,16 @@ func RegisterRoutes(m *macaron.Macaron) {
}
reqRepoAdmin := context.RequireRepoAdmin()
- reqRepoWriter := context.RequireRepoWriter()
+ reqRepoCodeWriter := context.RequireRepoWriter(models.UnitTypeCode)
+ reqRepoCodeReader := context.RequireRepoReader(models.UnitTypeCode)
+ reqRepoReleaseWriter := context.RequireRepoWriter(models.UnitTypeReleases)
+ reqRepoReleaseReader := context.RequireRepoReader(models.UnitTypeReleases)
+ reqRepoWikiWriter := context.RequireRepoWriter(models.UnitTypeWiki)
+ reqRepoIssueReader := context.RequireRepoReader(models.UnitTypeIssues)
+ reqRepoPullsWriter := context.RequireRepoWriter(models.UnitTypePullRequests)
+ reqRepoPullsReader := context.RequireRepoReader(models.UnitTypePullRequests)
+ reqRepoIssuesOrPullsWriter := context.RequireRepoWriterOr(models.UnitTypeIssues, models.UnitTypePullRequests)
+ reqRepoIssuesOrPullsReader := context.RequireRepoReaderOr(models.UnitTypeIssues, models.UnitTypePullRequests)
// ***** START: Organization *****
m.Group("/org", func() {
@@ -463,7 +472,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Group("/fork", func() {
m.Combo("/:repoid").Get(repo.Fork).
Post(bindIgnErr(auth.CreateRepoForm{}), repo.ForkPost)
- }, context.RepoIDAssignment(), context.UnitTypes(), context.LoadRepoUnits(), context.CheckUnit(models.UnitTypeCode))
+ }, context.RepoIDAssignment(), context.UnitTypes(), reqRepoCodeReader)
}, reqSignIn)
m.Group("/:username/:reponame", func() {
@@ -514,7 +523,7 @@ func RegisterRoutes(m *macaron.Macaron) {
}, func(ctx *context.Context) {
ctx.Data["PageIsSettings"] = true
})
- }, reqSignIn, context.RepoAssignment(), reqRepoAdmin, context.UnitTypes(), context.LoadRepoUnits(), context.RepoRef())
+ }, reqSignIn, context.RepoAssignment(), reqRepoAdmin, context.UnitTypes(), context.RepoRef())
m.Get("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), repo.Action)
@@ -522,7 +531,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Group("/issues", func() {
m.Combo("/new").Get(context.RepoRef(), repo.NewIssue).
Post(bindIgnErr(auth.CreateIssueForm{}), repo.NewIssuePost)
- }, context.CheckUnit(models.UnitTypeIssues))
+ }, reqRepoIssueReader)
// FIXME: should use different URLs but mostly same logic for comments of issue and pull reuqest.
// So they can apply their own enable/disable logic on routers.
m.Group("/issues", func() {
@@ -545,22 +554,22 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Post("/reactions/:action", bindIgnErr(auth.ReactionForm{}), repo.ChangeIssueReaction)
})
- m.Post("/labels", reqRepoWriter, repo.UpdateIssueLabel)
- m.Post("/milestone", reqRepoWriter, repo.UpdateIssueMilestone)
- m.Post("/assignee", reqRepoWriter, repo.UpdateIssueAssignee)
- m.Post("/status", reqRepoWriter, repo.UpdateIssueStatus)
+ m.Post("/labels", reqRepoIssuesOrPullsWriter, repo.UpdateIssueLabel)
+ m.Post("/milestone", reqRepoIssuesOrPullsWriter, repo.UpdateIssueMilestone)
+ m.Post("/assignee", reqRepoIssuesOrPullsWriter, repo.UpdateIssueAssignee)
+ m.Post("/status", reqRepoIssuesOrPullsWriter, repo.UpdateIssueStatus)
})
m.Group("/comments/:id", func() {
m.Post("", repo.UpdateCommentContent)
m.Post("/delete", repo.DeleteComment)
m.Post("/reactions/:action", bindIgnErr(auth.ReactionForm{}), repo.ChangeCommentReaction)
- }, context.CheckAnyUnit(models.UnitTypeIssues, models.UnitTypePullRequests))
+ })
m.Group("/labels", func() {
m.Post("/new", bindIgnErr(auth.CreateLabelForm{}), repo.NewLabel)
m.Post("/edit", bindIgnErr(auth.CreateLabelForm{}), repo.UpdateLabel)
m.Post("/delete", repo.DeleteLabel)
m.Post("/initialize", bindIgnErr(auth.InitializeLabelsForm{}), repo.InitializeLabels)
- }, reqRepoWriter, context.RepoRef(), context.CheckAnyUnit(models.UnitTypeIssues, models.UnitTypePullRequests))
+ }, reqRepoIssuesOrPullsWriter, context.RepoRef())
m.Group("/milestones", func() {
m.Combo("/new").Get(repo.NewMilestone).
Post(bindIgnErr(auth.CreateMilestoneForm{}), repo.NewMilestonePost)
@@ -568,9 +577,9 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Post("/:id/edit", bindIgnErr(auth.CreateMilestoneForm{}), repo.EditMilestonePost)
m.Get("/:id/:action", repo.ChangeMilestonStatus)
m.Post("/delete", repo.DeleteMilestone)
- }, reqRepoWriter, context.RepoRef(), context.CheckAnyUnit(models.UnitTypeIssues, models.UnitTypePullRequests))
+ }, reqRepoIssuesOrPullsWriter, context.RepoRef())
- m.Combo("/compare/*", repo.MustAllowPulls, repo.SetEditorconfigIfExists).
+ m.Combo("/compare/*", reqRepoCodeReader, reqRepoPullsReader, repo.MustAllowPulls, repo.SetEditorconfigIfExists).
Get(repo.SetDiffViewStyle, repo.CompareAndPullRequest).
Post(bindIgnErr(auth.CreateIssueForm{}), repo.CompareAndPullRequestPost)
@@ -591,7 +600,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Post("/upload-file", repo.UploadFileToServer)
m.Post("/upload-remove", bindIgnErr(auth.RemoveUploadFileForm{}), repo.RemoveUploadFileFromServer)
}, context.RepoRef(), repo.MustBeEditable, repo.MustBeAbleToUpload)
- }, repo.MustBeNotBare, reqRepoWriter)
+ }, reqRepoCodeWriter, repo.MustBeNotBare)
m.Group("/branches", func() {
m.Group("/_new/", func() {
@@ -601,9 +610,9 @@ func RegisterRoutes(m *macaron.Macaron) {
}, bindIgnErr(auth.NewBranchForm{}))
m.Post("/delete", repo.DeleteBranchPost)
m.Post("/restore", repo.RestoreBranchPost)
- }, reqRepoWriter, repo.MustBeNotBare, context.CheckUnit(models.UnitTypeCode))
+ }, reqRepoCodeWriter, repo.MustBeNotBare)
- }, reqSignIn, context.RepoAssignment(), context.UnitTypes(), context.LoadRepoUnits())
+ }, reqSignIn, context.RepoAssignment(), context.UnitTypes())
// Releases
m.Group("/:username/:reponame", func() {
@@ -614,11 +623,11 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/new", repo.NewRelease)
m.Post("/new", bindIgnErr(auth.NewReleaseForm{}), repo.NewReleasePost)
m.Post("/delete", repo.DeleteRelease)
- }, reqSignIn, repo.MustBeNotBare, reqRepoWriter, context.RepoRef())
+ }, reqSignIn, repo.MustBeNotBare, reqRepoReleaseWriter, context.RepoRef())
m.Group("/releases", func() {
m.Get("/edit/*", repo.EditRelease)
m.Post("/edit/*", bindIgnErr(auth.EditReleaseForm{}), repo.EditReleasePost)
- }, reqSignIn, repo.MustBeNotBare, reqRepoWriter, func(ctx *context.Context) {
+ }, reqSignIn, repo.MustBeNotBare, reqRepoReleaseWriter, func(ctx *context.Context) {
var err error
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch)
if err != nil {
@@ -632,7 +641,7 @@ func RegisterRoutes(m *macaron.Macaron) {
}
ctx.Data["CommitsCount"] = ctx.Repo.CommitsCount
})
- }, context.RepoAssignment(), context.UnitTypes(), context.LoadRepoUnits(), context.CheckUnit(models.UnitTypeReleases))
+ }, context.RepoAssignment(), context.UnitTypes(), reqRepoReleaseReader)
m.Group("/:username/:reponame", func() {
m.Post("/topics", repo.TopicsPost)
@@ -642,8 +651,8 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Group("", func() {
m.Get("/^:type(issues|pulls)$", repo.RetrieveLabels, repo.Issues)
m.Get("/^:type(issues|pulls)$/:index", repo.ViewIssue)
- m.Get("/labels/", context.CheckAnyUnit(models.UnitTypeIssues, models.UnitTypePullRequests), repo.RetrieveLabels, repo.Labels)
- m.Get("/milestones", context.CheckAnyUnit(models.UnitTypeIssues, models.UnitTypePullRequests), repo.Milestones)
+ m.Get("/labels/", reqRepoIssuesOrPullsReader, repo.RetrieveLabels, repo.Labels)
+ m.Get("/milestones", reqRepoIssuesOrPullsReader, repo.Milestones)
}, context.RepoRef())
m.Group("/wiki", func() {
@@ -656,7 +665,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Combo("/:page/_edit").Get(repo.EditWiki).
Post(bindIgnErr(auth.NewWikiForm{}), repo.EditWikiPost)
m.Post("/:page/delete", repo.DeleteWikiPagePost)
- }, reqSignIn, reqRepoWriter)
+ }, reqSignIn, reqRepoWikiWriter)
}, repo.MustEnableWiki, context.RepoRef())
m.Group("/wiki", func() {
@@ -666,19 +675,19 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Group("/activity", func() {
m.Get("", repo.Activity)
m.Get("/:period", repo.Activity)
- }, context.RepoRef(), repo.MustBeNotBare, context.CheckAnyUnit(models.UnitTypePullRequests, models.UnitTypeIssues, models.UnitTypeReleases))
+ }, context.RepoRef(), repo.MustBeNotBare, context.RequireRepoReaderOr(models.UnitTypePullRequests, models.UnitTypeIssues, models.UnitTypeReleases))
- m.Get("/archive/*", repo.MustBeNotBare, context.CheckUnit(models.UnitTypeCode), repo.Download)
+ m.Get("/archive/*", repo.MustBeNotBare, reqRepoCodeReader, repo.Download)
m.Group("/branches", func() {
m.Get("", repo.Branches)
- }, repo.MustBeNotBare, context.RepoRef(), context.CheckUnit(models.UnitTypeCode))
+ }, repo.MustBeNotBare, context.RepoRef(), reqRepoCodeReader)
m.Group("/pulls/:index", func() {
m.Get(".diff", repo.DownloadPullDiff)
m.Get(".patch", repo.DownloadPullPatch)
m.Get("/commits", context.RepoRef(), repo.ViewPullCommits)
- m.Post("/merge", reqRepoWriter, bindIgnErr(auth.MergePullRequestForm{}), repo.MergePullRequest)
+ m.Post("/merge", reqRepoPullsWriter, bindIgnErr(auth.MergePullRequestForm{}), repo.MergePullRequest)
m.Post("/cleanup", context.RepoRef(), repo.CleanUpPullRequest)
m.Group("/files", func() {
m.Get("", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.ViewPullFiles)
@@ -696,7 +705,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/blob/:sha", context.RepoRefByType(context.RepoRefBlob), repo.DownloadByID)
// "/*" route is deprecated, and kept for backward compatibility
m.Get("/*", context.RepoRefByType(context.RepoRefLegacy), repo.SingleDownload)
- }, repo.MustBeNotBare, context.CheckUnit(models.UnitTypeCode))
+ }, repo.MustBeNotBare, reqRepoCodeReader)
m.Group("/commits", func() {
m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.RefCommits)
@@ -704,12 +713,12 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.RefCommits)
// "/*" route is deprecated, and kept for backward compatibility
m.Get("/*", context.RepoRefByType(context.RepoRefLegacy), repo.RefCommits)
- }, repo.MustBeNotBare, context.CheckUnit(models.UnitTypeCode))
+ }, repo.MustBeNotBare, reqRepoCodeReader)
m.Group("", func() {
m.Get("/graph", repo.Graph)
m.Get("/commit/:sha([a-f0-9]{7,40})$", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.Diff)
- }, repo.MustBeNotBare, context.RepoRef(), context.CheckUnit(models.UnitTypeCode))
+ }, repo.MustBeNotBare, context.RepoRef(), reqRepoCodeReader)
m.Group("/src", func() {
m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.Home)
@@ -721,24 +730,24 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Group("", func() {
m.Get("/forks", repo.Forks)
- }, context.RepoRef(), context.CheckUnit(models.UnitTypeCode))
+ }, context.RepoRef(), reqRepoCodeReader)
m.Get("/commit/:sha([a-f0-9]{7,40})\\.:ext(patch|diff)",
- repo.MustBeNotBare, context.CheckUnit(models.UnitTypeCode), repo.RawDiff)
+ repo.MustBeNotBare, reqRepoCodeReader, repo.RawDiff)
m.Get("/compare/:before([a-z0-9]{40})\\.\\.\\.:after([a-z0-9]{40})", repo.SetEditorconfigIfExists,
- repo.SetDiffViewStyle, repo.MustBeNotBare, context.CheckUnit(models.UnitTypeCode), repo.CompareDiff)
- }, ignSignIn, context.RepoAssignment(), context.UnitTypes(), context.LoadRepoUnits())
+ repo.SetDiffViewStyle, repo.MustBeNotBare, reqRepoCodeReader, repo.CompareDiff)
+ }, ignSignIn, context.RepoAssignment(), context.UnitTypes())
m.Group("/:username/:reponame", func() {
m.Get("/stars", repo.Stars)
m.Get("/watchers", repo.Watchers)
- m.Get("/search", context.CheckUnit(models.UnitTypeCode), repo.Search)
- }, ignSignIn, context.RepoAssignment(), context.RepoRef(), context.UnitTypes(), context.LoadRepoUnits())
+ m.Get("/search", reqRepoCodeReader, repo.Search)
+ }, ignSignIn, context.RepoAssignment(), context.RepoRef(), context.UnitTypes())
m.Group("/:username", func() {
m.Group("/:reponame", func() {
m.Get("", repo.SetEditorconfigIfExists, repo.Home)
m.Get("\\.git$", repo.SetEditorconfigIfExists, repo.Home)
- }, ignSignIn, context.RepoAssignment(), context.RepoRef(), context.UnitTypes(), context.LoadRepoUnits())
+ }, ignSignIn, context.RepoAssignment(), context.RepoRef(), context.UnitTypes())
m.Group("/:reponame", func() {
m.Group("\\.git/info/lfs", func() {
diff --git a/routers/user/home.go b/routers/user/home.go
index 49c6579556..4c6a9f6cd0 100644
--- a/routers/user/home.go
+++ b/routers/user/home.go
@@ -286,7 +286,12 @@ func Issues(ctx *context.Context) {
repo := showReposMap[repoID]
// Check if user has access to given repository.
- if !repo.IsOwnedBy(ctxUser.ID) && !repo.HasAccess(ctxUser) {
+ perm, err := models.GetUserRepoPermission(repo, ctxUser)
+ if err != nil {
+ ctx.ServerError("GetUserRepoPermission", fmt.Errorf("[%d]%v", repoID, err))
+ return
+ }
+ if !perm.CanRead(models.UnitTypeIssues) {
ctx.Status(404)
return
}