aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--models/perm/access/repo_permission.go47
-rw-r--r--models/perm/access/repo_permission_test.go12
-rw-r--r--options/locale/locale_en-US.ini2
-rw-r--r--routers/web/repo/issue_poster.go10
-rw-r--r--routers/web/repo/setting/setting.go17
-rw-r--r--routers/web/web.go183
-rw-r--r--services/context/permission.go74
-rw-r--r--services/forms/repo_form.go66
-rw-r--r--templates/repo/settings/options.tmpl20
9 files changed, 218 insertions, 213 deletions
diff --git a/models/perm/access/repo_permission.go b/models/perm/access/repo_permission.go
index 0ed116a132..e00b7c5320 100644
--- a/models/perm/access/repo_permission.go
+++ b/models/perm/access/repo_permission.go
@@ -175,10 +175,14 @@ func (p *Permission) LogString() string {
return fmt.Sprintf(format, args...)
}
-func applyEveryoneRepoPermission(user *user_model.User, perm *Permission) {
+func finalProcessRepoUnitPermission(user *user_model.User, perm *Permission) {
if user == nil || user.ID <= 0 {
+ // for anonymous access, it could be:
+ // AccessMode is None or Read, units has repo units, unitModes is nil
return
}
+
+ // apply everyone access permissions
for _, u := range perm.units {
if u.EveryoneAccessMode >= perm_model.AccessModeRead && u.EveryoneAccessMode > perm.everyoneAccessMode[u.Type] {
if perm.everyoneAccessMode == nil {
@@ -187,17 +191,40 @@ func applyEveryoneRepoPermission(user *user_model.User, perm *Permission) {
perm.everyoneAccessMode[u.Type] = u.EveryoneAccessMode
}
}
+
+ if perm.unitsMode == nil {
+ // if unitsMode is not set, then it means that the default p.AccessMode applies to all units
+ return
+ }
+
+ // remove no permission units
+ origPermUnits := perm.units
+ perm.units = make([]*repo_model.RepoUnit, 0, len(perm.units))
+ for _, u := range origPermUnits {
+ shouldKeep := false
+ for t := range perm.unitsMode {
+ if shouldKeep = u.Type == t; shouldKeep {
+ break
+ }
+ }
+ for t := range perm.everyoneAccessMode {
+ if shouldKeep = shouldKeep || u.Type == t; shouldKeep {
+ break
+ }
+ }
+ if shouldKeep {
+ perm.units = append(perm.units, u)
+ }
+ }
}
// GetUserRepoPermission returns the user permissions to the repository
func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, user *user_model.User) (perm Permission, err error) {
defer func() {
if err == nil {
- applyEveryoneRepoPermission(user, &perm)
- }
- if log.IsTrace() {
- log.Trace("Permission Loaded for user %-v in repo %-v, permissions: %-+v", user, repo, perm)
+ finalProcessRepoUnitPermission(user, &perm)
}
+ log.Trace("Permission Loaded for user %-v in repo %-v, permissions: %-+v", user, repo, perm)
}()
if err = repo.LoadUnits(ctx); err != nil {
@@ -294,16 +321,6 @@ func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, use
}
}
- // remove no permission units
- perm.units = make([]*repo_model.RepoUnit, 0, len(repo.Units))
- for t := range perm.unitsMode {
- for _, u := range repo.Units {
- if u.Type == t {
- perm.units = append(perm.units, u)
- }
- }
- }
-
return perm, err
}
diff --git a/models/perm/access/repo_permission_test.go b/models/perm/access/repo_permission_test.go
index 50070c4368..9862da0673 100644
--- a/models/perm/access/repo_permission_test.go
+++ b/models/perm/access/repo_permission_test.go
@@ -50,7 +50,7 @@ func TestApplyEveryoneRepoPermission(t *testing.T) {
{Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeRead},
},
}
- applyEveryoneRepoPermission(nil, &perm)
+ finalProcessRepoUnitPermission(nil, &perm)
assert.False(t, perm.CanRead(unit.TypeWiki))
perm = Permission{
@@ -59,7 +59,7 @@ func TestApplyEveryoneRepoPermission(t *testing.T) {
{Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeRead},
},
}
- applyEveryoneRepoPermission(&user_model.User{ID: 0}, &perm)
+ finalProcessRepoUnitPermission(&user_model.User{ID: 0}, &perm)
assert.False(t, perm.CanRead(unit.TypeWiki))
perm = Permission{
@@ -68,7 +68,7 @@ func TestApplyEveryoneRepoPermission(t *testing.T) {
{Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeRead},
},
}
- applyEveryoneRepoPermission(&user_model.User{ID: 1}, &perm)
+ finalProcessRepoUnitPermission(&user_model.User{ID: 1}, &perm)
assert.True(t, perm.CanRead(unit.TypeWiki))
perm = Permission{
@@ -77,20 +77,22 @@ func TestApplyEveryoneRepoPermission(t *testing.T) {
{Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeRead},
},
}
- applyEveryoneRepoPermission(&user_model.User{ID: 1}, &perm)
+ finalProcessRepoUnitPermission(&user_model.User{ID: 1}, &perm)
// it should work the same as "EveryoneAccessMode: none" because the default AccessMode should be applied to units
assert.True(t, perm.CanWrite(unit.TypeWiki))
perm = Permission{
units: []*repo_model.RepoUnit{
+ {Type: unit.TypeCode}, // will be removed
{Type: unit.TypeWiki, EveryoneAccessMode: perm_model.AccessModeRead},
},
unitsMode: map[unit.Type]perm_model.AccessMode{
unit.TypeWiki: perm_model.AccessModeWrite,
},
}
- applyEveryoneRepoPermission(&user_model.User{ID: 1}, &perm)
+ finalProcessRepoUnitPermission(&user_model.User{ID: 1}, &perm)
assert.True(t, perm.CanWrite(unit.TypeWiki))
+ assert.Len(t, perm.units, 1)
}
func TestUnitAccessMode(t *testing.T) {
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index 93155caa10..d336b6a700 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -2158,7 +2158,7 @@ settings.advanced_settings = Advanced Settings
settings.wiki_desc = Enable Repository Wiki
settings.use_internal_wiki = Use Built-In Wiki
settings.default_wiki_branch_name = Default Wiki Branch Name
-settings.default_wiki_everyone_access = Default Access Permission for signed-in users:
+settings.default_permission_everyone_access = Default access permission for all signed-in users:
settings.failed_to_change_default_wiki_branch = Failed to change the default wiki branch.
settings.use_external_wiki = Use External Wiki
settings.external_wiki_url = External Wiki URL
diff --git a/routers/web/repo/issue_poster.go b/routers/web/repo/issue_poster.go
index 91ef947cb4..07059b9b7b 100644
--- a/routers/web/repo/issue_poster.go
+++ b/routers/web/repo/issue_poster.go
@@ -26,13 +26,9 @@ type userSearchResponse struct {
Results []*userSearchInfo `json:"results"`
}
-// IssuePosters get posters for current repo's issues/pull requests
-func IssuePosters(ctx *context.Context) {
- issuePosters(ctx, false)
-}
-
-func PullPosters(ctx *context.Context) {
- issuePosters(ctx, true)
+func IssuePullPosters(ctx *context.Context) {
+ isPullList := ctx.PathParam("type") == "pulls"
+ issuePosters(ctx, isPullList)
}
func issuePosters(ctx *context.Context, isPullList bool) {
diff --git a/routers/web/repo/setting/setting.go b/routers/web/repo/setting/setting.go
index 7399c681e2..5b34fc60da 100644
--- a/routers/web/repo/setting/setting.go
+++ b/routers/web/repo/setting/setting.go
@@ -49,6 +49,15 @@ const (
tplDeployKeys templates.TplName = "repo/settings/deploy_keys"
)
+func parseEveryoneAccessMode(permission string, allowed ...perm.AccessMode) perm.AccessMode {
+ // if site admin forces repositories to be private, then do not allow any other access mode,
+ // otherwise the "force private" setting would be bypassed
+ if setting.Repository.ForcePrivate {
+ return perm.AccessModeNone
+ }
+ return perm.ParseAccessMode(permission, allowed...)
+}
+
// SettingsCtxData is a middleware that sets all the general context data for the
// settings template.
func SettingsCtxData(ctx *context.Context) {
@@ -447,8 +456,9 @@ func SettingsPost(ctx *context.Context) {
if form.EnableCode && !unit_model.TypeCode.UnitGlobalDisabled() {
units = append(units, repo_model.RepoUnit{
- RepoID: repo.ID,
- Type: unit_model.TypeCode,
+ RepoID: repo.ID,
+ Type: unit_model.TypeCode,
+ EveryoneAccessMode: parseEveryoneAccessMode(form.DefaultCodeEveryoneAccess, perm.AccessModeNone, perm.AccessModeRead),
})
} else if !unit_model.TypeCode.UnitGlobalDisabled() {
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeCode)
@@ -474,7 +484,7 @@ func SettingsPost(ctx *context.Context) {
RepoID: repo.ID,
Type: unit_model.TypeWiki,
Config: new(repo_model.UnitConfig),
- EveryoneAccessMode: perm.ParseAccessMode(form.DefaultWikiEveryoneAccess, perm.AccessModeNone, perm.AccessModeRead, perm.AccessModeWrite),
+ EveryoneAccessMode: parseEveryoneAccessMode(form.DefaultWikiEveryoneAccess, perm.AccessModeNone, perm.AccessModeRead, perm.AccessModeWrite),
})
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalWiki)
} else {
@@ -524,6 +534,7 @@ func SettingsPost(ctx *context.Context) {
AllowOnlyContributorsToTrackTime: form.AllowOnlyContributorsToTrackTime,
EnableDependencies: form.EnableIssueDependencies,
},
+ EveryoneAccessMode: parseEveryoneAccessMode(form.DefaultIssuesEveryoneAccess, perm.AccessModeNone, perm.AccessModeRead),
})
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeExternalTracker)
} else {
diff --git a/routers/web/web.go b/routers/web/web.go
index 2f7ee8ade7..d3d0360396 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -101,7 +101,7 @@ func buildAuthGroup() *auth_service.Group {
group.Add(&auth_service.Basic{}) // FIXME: this should be removed and only applied in download and git/lfs routers
if setting.Service.EnableReverseProxyAuth {
- group.Add(&auth_service.ReverseProxy{}) // reverseproxy should before Session, otherwise the header will be ignored if user has login
+ group.Add(&auth_service.ReverseProxy{}) // reverse-proxy should before Session, otherwise the header will be ignored if user has login
}
group.Add(&auth_service.Session{})
@@ -816,21 +816,24 @@ func registerRoutes(m *web.Router) {
m.Post("/{username}", reqSignIn, context.UserAssignmentWeb(), user.Action)
reqRepoAdmin := context.RequireRepoAdmin()
- reqRepoCodeWriter := context.RequireRepoWriter(unit.TypeCode)
+ reqRepoCodeWriter := context.RequireUnitWriter(unit.TypeCode)
canEnableEditor := context.CanEnableEditor()
- reqRepoCodeReader := context.RequireRepoReader(unit.TypeCode)
- reqRepoReleaseWriter := context.RequireRepoWriter(unit.TypeReleases)
- reqRepoReleaseReader := context.RequireRepoReader(unit.TypeReleases)
- reqRepoWikiReader := context.RequireRepoReader(unit.TypeWiki)
- reqRepoWikiWriter := context.RequireRepoWriter(unit.TypeWiki)
- reqRepoIssueReader := context.RequireRepoReader(unit.TypeIssues)
- reqRepoPullsReader := context.RequireRepoReader(unit.TypePullRequests)
- reqRepoIssuesOrPullsWriter := context.RequireRepoWriterOr(unit.TypeIssues, unit.TypePullRequests)
- reqRepoIssuesOrPullsReader := context.RequireRepoReaderOr(unit.TypeIssues, unit.TypePullRequests)
- reqRepoProjectsReader := context.RequireRepoReader(unit.TypeProjects)
- reqRepoProjectsWriter := context.RequireRepoWriter(unit.TypeProjects)
- reqRepoActionsReader := context.RequireRepoReader(unit.TypeActions)
- reqRepoActionsWriter := context.RequireRepoWriter(unit.TypeActions)
+ reqRepoReleaseWriter := context.RequireUnitWriter(unit.TypeReleases)
+ reqRepoReleaseReader := context.RequireUnitReader(unit.TypeReleases)
+ reqRepoIssuesOrPullsWriter := context.RequireUnitWriter(unit.TypeIssues, unit.TypePullRequests)
+ reqRepoIssuesOrPullsReader := context.RequireUnitReader(unit.TypeIssues, unit.TypePullRequests)
+ reqRepoProjectsReader := context.RequireUnitReader(unit.TypeProjects)
+ reqRepoProjectsWriter := context.RequireUnitWriter(unit.TypeProjects)
+ reqRepoActionsReader := context.RequireUnitReader(unit.TypeActions)
+ reqRepoActionsWriter := context.RequireUnitWriter(unit.TypeActions)
+
+ // the legacy names "reqRepoXxx" should be renamed to the correct name "reqUnitXxx", these permissions are for units, not repos
+ reqUnitsWithMarkdown := context.RequireUnitReader(unit.TypeCode, unit.TypeIssues, unit.TypePullRequests, unit.TypeReleases, unit.TypeWiki)
+ reqUnitCodeReader := context.RequireUnitReader(unit.TypeCode)
+ reqUnitIssuesReader := context.RequireUnitReader(unit.TypeIssues)
+ reqUnitPullsReader := context.RequireUnitReader(unit.TypePullRequests)
+ reqUnitWikiReader := context.RequireUnitReader(unit.TypeWiki)
+ reqUnitWikiWriter := context.RequireUnitWriter(unit.TypeWiki)
reqPackageAccess := func(accessMode perm.AccessMode) func(ctx *context.Context) {
return func(ctx *context.Context) {
@@ -1053,7 +1056,7 @@ func registerRoutes(m *web.Router) {
m.Group("/migrate", func() {
m.Get("/status", repo.MigrateStatus)
})
- }, optSignIn, context.RepoAssignment, reqRepoCodeReader)
+ }, optSignIn, context.RepoAssignment, reqUnitCodeReader)
// end "/{username}/{reponame}/-": migrate
m.Group("/{username}/{reponame}/settings", func() {
@@ -1151,8 +1154,7 @@ func registerRoutes(m *web.Router) {
// user/org home, including rss feeds
m.Get("/{username}/{reponame}", optSignIn, context.RepoAssignment, context.RepoRef(), repo.SetEditorconfigIfExists, repo.Home)
- // TODO: maybe it should relax the permission to allow "any access"
- m.Post("/{username}/{reponame}/markup", optSignIn, context.RepoAssignment, context.RequireRepoReaderOr(unit.TypeCode, unit.TypeIssues, unit.TypePullRequests, unit.TypeReleases, unit.TypeWiki), web.Bind(structs.MarkupOption{}), misc.Markup)
+ m.Post("/{username}/{reponame}/markup", optSignIn, context.RepoAssignment, reqUnitsWithMarkdown, web.Bind(structs.MarkupOption{}), misc.Markup)
m.Group("/{username}/{reponame}", func() {
m.Get("/find/*", repo.FindFiles)
@@ -1164,41 +1166,40 @@ func registerRoutes(m *web.Router) {
m.Get("/compare", repo.MustBeNotEmpty, repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.CompareDiff)
m.Combo("/compare/*", repo.MustBeNotEmpty, repo.SetEditorconfigIfExists).
Get(repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.CompareDiff).
- Post(reqSignIn, context.RepoMustNotBeArchived(), reqRepoPullsReader, repo.MustAllowPulls, web.Bind(forms.CreateIssueForm{}), repo.SetWhitespaceBehavior, repo.CompareAndPullRequestPost)
- }, optSignIn, context.RepoAssignment, reqRepoCodeReader)
+ Post(reqSignIn, context.RepoMustNotBeArchived(), reqUnitPullsReader, repo.MustAllowPulls, web.Bind(forms.CreateIssueForm{}), repo.SetWhitespaceBehavior, repo.CompareAndPullRequestPost)
+ }, optSignIn, context.RepoAssignment, reqUnitCodeReader)
// end "/{username}/{reponame}": repo code: find, compare, list
+ addIssuesPullsViewRoutes := func() {
+ // for /{username}/{reponame}/issues" or "/{username}/{reponame}/pulls"
+ m.Get("/posters", repo.IssuePullPosters)
+ m.Group("/{index}", func() {
+ m.Get("/info", repo.GetIssueInfo)
+ m.Get("/attachments", repo.GetIssueAttachments)
+ m.Get("/attachments/{uuid}", repo.GetAttachment)
+ m.Group("/content-history", func() {
+ m.Get("/overview", repo.GetContentHistoryOverview)
+ m.Get("/list", repo.GetContentHistoryList)
+ m.Get("/detail", repo.GetContentHistoryDetail)
+ })
+ })
+ }
m.Group("/{username}/{reponame}", func() {
- m.Get("/issues/posters", repo.IssuePosters) // it can't use {type:issues|pulls} because it would conflict with other routes like "/pulls/{index}"
- m.Get("/pulls/posters", repo.PullPosters)
m.Get("/comments/{id}/attachments", repo.GetCommentAttachments)
m.Get("/labels", repo.RetrieveLabelsForList, repo.Labels)
m.Get("/milestones", repo.Milestones)
m.Get("/milestone/{id}", context.RepoRef(), repo.MilestoneIssuesAndPulls)
- m.Group("/{type:issues|pulls}", func() {
- m.Group("/{index}", func() {
- m.Get("/info", repo.GetIssueInfo)
- m.Get("/attachments", repo.GetIssueAttachments)
- m.Get("/attachments/{uuid}", repo.GetAttachment)
- m.Group("/content-history", func() {
- m.Get("/overview", repo.GetContentHistoryOverview)
- m.Get("/list", repo.GetContentHistoryList)
- m.Get("/detail", repo.GetContentHistoryDetail)
- })
- })
- }, context.RepoRef())
m.Get("/issues/suggestions", repo.IssueSuggestions)
- }, optSignIn, context.RepoAssignment, reqRepoIssuesOrPullsReader)
+ }, optSignIn, context.RepoAssignment, reqRepoIssuesOrPullsReader) // issue/pull attachments, labels, milestones
+
+ m.Group("/{username}/{reponame}/{type:issues}", addIssuesPullsViewRoutes, optSignIn, context.RepoAssignment, reqUnitIssuesReader)
+ m.Group("/{username}/{reponame}/{type:pulls}", addIssuesPullsViewRoutes, optSignIn, context.RepoAssignment, reqUnitPullsReader)
// end "/{username}/{reponame}": view milestone, label, issue, pull, etc
- m.Group("/{username}/{reponame}", func() {
- m.Group("/{type:issues|pulls}", func() {
- m.Get("", repo.Issues)
- m.Group("/{index}", func() {
- m.Get("", repo.ViewIssue)
- })
- })
- }, optSignIn, context.RepoAssignment, context.RequireRepoReaderOr(unit.TypeIssues, unit.TypePullRequests, unit.TypeExternalTracker))
+ m.Group("/{username}/{reponame}/{type:issues}", func() {
+ m.Get("", repo.Issues)
+ m.Get("/{index}", repo.ViewIssue)
+ }, optSignIn, context.RepoAssignment, context.RequireUnitReader(unit.TypeIssues, unit.TypeExternalTracker))
// end "/{username}/{reponame}": issue/pull list, issue/pull view, external tracker
m.Group("/{username}/{reponame}", func() { // edit issues, pulls, labels, milestones, etc
@@ -1209,11 +1210,10 @@ func registerRoutes(m *web.Router) {
m.Get("/choose", context.RepoRef(), repo.NewIssueChooseTemplate)
})
m.Get("/search", repo.SearchRepoIssuesJSON)
- }, context.RepoMustNotBeArchived(), reqRepoIssueReader)
+ }, reqUnitIssuesReader)
- // FIXME: should use different URLs but mostly same logic for comments of issue and pull request.
- // So they can apply their own enable/disable logic on routers.
- m.Group("/{type:issues|pulls}", func() {
+ addIssuesPullsRoutes := func() {
+ // for "/{username}/{reponame}/issues" or "/{username}/{reponame}/pulls"
m.Group("/{index}", func() {
m.Post("/title", repo.UpdateIssueTitle)
m.Post("/content", repo.UpdateIssueContent)
@@ -1240,39 +1240,37 @@ func registerRoutes(m *web.Router) {
m.Post("/lock", reqRepoIssuesOrPullsWriter, web.Bind(forms.IssueLockForm{}), repo.LockIssue)
m.Post("/unlock", reqRepoIssuesOrPullsWriter, repo.UnlockIssue)
m.Post("/delete", reqRepoAdmin, repo.DeleteIssue)
- }, context.RepoMustNotBeArchived())
-
- m.Group("/{index}", func() {
m.Post("/content-history/soft-delete", repo.SoftDeleteContentHistory)
})
- m.Post("/labels", reqRepoIssuesOrPullsWriter, repo.UpdateIssueLabel)
- m.Post("/milestone", reqRepoIssuesOrPullsWriter, repo.UpdateIssueMilestone)
+ m.Post("/attachments", repo.UploadIssueAttachment)
+ m.Post("/attachments/remove", repo.DeleteAttachment)
+
m.Post("/projects", reqRepoIssuesOrPullsWriter, reqRepoProjectsReader, repo.UpdateIssueProject)
m.Post("/assignee", reqRepoIssuesOrPullsWriter, repo.UpdateIssueAssignee)
- m.Post("/request_review", repo.UpdatePullReviewRequest)
- m.Post("/dismiss_review", reqRepoAdmin, web.Bind(forms.DismissReviewForm{}), repo.DismissReview)
m.Post("/status", reqRepoIssuesOrPullsWriter, repo.UpdateIssueStatus)
m.Post("/delete", reqRepoAdmin, repo.BatchDeleteIssues)
- m.Post("/resolve_conversation", repo.SetShowOutdatedComments, repo.UpdateResolveConversation)
- m.Post("/attachments", repo.UploadIssueAttachment)
- m.Post("/attachments/remove", repo.DeleteAttachment)
m.Delete("/unpin/{index}", reqRepoAdmin, repo.IssueUnpin)
m.Post("/move_pin", reqRepoAdmin, repo.IssuePinMove)
- }, context.RepoMustNotBeArchived())
+ }
+ m.Group("/{type:issues}", addIssuesPullsRoutes, reqUnitIssuesReader, context.RepoMustNotBeArchived())
+ m.Group("/{type:pulls}", addIssuesPullsRoutes, reqUnitPullsReader, context.RepoMustNotBeArchived())
m.Group("/comments/{id}", func() {
m.Post("", repo.UpdateCommentContent)
m.Post("/delete", repo.DeleteComment)
m.Post("/reactions/{action}", web.Bind(forms.ReactionForm{}), repo.ChangeCommentReaction)
- }, context.RepoMustNotBeArchived())
+ }, reqRepoIssuesOrPullsReader) // edit issue/pull comment
+ m.Post("/labels", reqRepoIssuesOrPullsWriter, repo.UpdateIssueLabel)
m.Group("/labels", func() {
m.Post("/new", web.Bind(forms.CreateLabelForm{}), repo.NewLabel)
m.Post("/edit", web.Bind(forms.CreateLabelForm{}), repo.UpdateLabel)
m.Post("/delete", repo.DeleteLabel)
m.Post("/initialize", web.Bind(forms.InitializeLabelsForm{}), repo.InitializeLabels)
- }, context.RepoMustNotBeArchived(), reqRepoIssuesOrPullsWriter, context.RepoRef())
+ }, reqRepoIssuesOrPullsWriter, context.RepoRef())
+
+ m.Post("/milestone", reqRepoIssuesOrPullsWriter, repo.UpdateIssueMilestone)
m.Group("/milestones", func() {
m.Combo("/new").Get(repo.NewMilestone).
Post(web.Bind(forms.CreateMilestoneForm{}), repo.NewMilestonePost)
@@ -1280,11 +1278,15 @@ func registerRoutes(m *web.Router) {
m.Post("/{id}/edit", web.Bind(forms.CreateMilestoneForm{}), repo.EditMilestonePost)
m.Post("/{id}/{action}", repo.ChangeMilestoneStatus)
m.Post("/delete", repo.DeleteMilestone)
- }, context.RepoMustNotBeArchived(), reqRepoIssuesOrPullsWriter, context.RepoRef())
- m.Group("/pull", func() {
- m.Post("/{index}/target_branch", repo.UpdatePullRequestTarget)
- }, context.RepoMustNotBeArchived())
- }, reqSignIn, context.RepoAssignment, reqRepoIssuesOrPullsReader)
+ }, reqRepoIssuesOrPullsWriter, context.RepoRef())
+
+ m.Group("", func() {
+ m.Post("/request_review", repo.UpdatePullReviewRequest)
+ m.Post("/dismiss_review", reqRepoAdmin, web.Bind(forms.DismissReviewForm{}), repo.DismissReview)
+ m.Post("/resolve_conversation", repo.SetShowOutdatedComments, repo.UpdateResolveConversation)
+ m.Post("/pull/{index}/target_branch", repo.UpdatePullRequestTarget)
+ }, reqUnitPullsReader)
+ }, reqSignIn, context.RepoAssignment, context.RepoMustNotBeArchived())
// end "/{username}/{reponame}": create or edit issues, pulls, labels, milestones
m.Group("/{username}/{reponame}", func() { // repo code
@@ -1324,7 +1326,7 @@ func registerRoutes(m *web.Router) {
}, context.RepoMustNotBeArchived(), reqRepoCodeWriter, repo.MustBeNotEmpty)
m.Combo("/fork").Get(repo.Fork).Post(web.Bind(forms.CreateRepoForm{}), repo.ForkPost)
- }, reqSignIn, context.RepoAssignment, reqRepoCodeReader)
+ }, reqSignIn, context.RepoAssignment, reqUnitCodeReader)
// end "/{username}/{reponame}": repo code
m.Group("/{username}/{reponame}", func() { // repo tags
@@ -1337,7 +1339,7 @@ func registerRoutes(m *web.Router) {
repo.MustBeNotEmpty, context.RepoRefByType(context.RepoRefTag, context.RepoRefByTypeOptions{IgnoreNotExistErr: true}))
m.Post("/tags/delete", repo.DeleteTag, reqSignIn,
repo.MustBeNotEmpty, context.RepoMustNotBeArchived(), reqRepoCodeWriter, context.RepoRef())
- }, optSignIn, context.RepoAssignment, reqRepoCodeReader)
+ }, optSignIn, context.RepoAssignment, reqUnitCodeReader)
// end "/{username}/{reponame}": repo tags
m.Group("/{username}/{reponame}", func() { // repo releases
@@ -1440,43 +1442,48 @@ func registerRoutes(m *web.Router) {
m.Group("/{username}/{reponame}/wiki", func() {
m.Combo("").
Get(repo.Wiki).
- Post(context.RepoMustNotBeArchived(), reqSignIn, reqRepoWikiWriter, web.Bind(forms.NewWikiForm{}), repo.WikiPost)
+ Post(context.RepoMustNotBeArchived(), reqSignIn, reqUnitWikiWriter, web.Bind(forms.NewWikiForm{}), repo.WikiPost)
m.Combo("/*").
Get(repo.Wiki).
- Post(context.RepoMustNotBeArchived(), reqSignIn, reqRepoWikiWriter, web.Bind(forms.NewWikiForm{}), repo.WikiPost)
+ Post(context.RepoMustNotBeArchived(), reqSignIn, reqUnitWikiWriter, web.Bind(forms.NewWikiForm{}), repo.WikiPost)
m.Get("/blob_excerpt/{sha}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.ExcerptBlob)
m.Get("/commit/{sha:[a-f0-9]{7,64}}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff)
m.Get("/commit/{sha:[a-f0-9]{7,64}}.{ext:patch|diff}", repo.RawDiff)
m.Get("/raw/*", repo.WikiRaw)
- }, optSignIn, context.RepoAssignment, repo.MustEnableWiki, reqRepoWikiReader, func(ctx *context.Context) {
+ }, optSignIn, context.RepoAssignment, repo.MustEnableWiki, reqUnitWikiReader, func(ctx *context.Context) {
ctx.Data["PageIsWiki"] = true
ctx.Data["CloneButtonOriginLink"] = ctx.Repo.Repository.WikiCloneLink(ctx, ctx.Doer)
})
// end "/{username}/{reponame}/wiki"
m.Group("/{username}/{reponame}/activity", func() {
+ // activity has its own permission checks
m.Get("", repo.Activity)
m.Get("/{period}", repo.Activity)
- m.Group("/contributors", func() {
- m.Get("", repo.Contributors)
- m.Get("/data", repo.ContributorsData)
- })
- m.Group("/code-frequency", func() {
- m.Get("", repo.CodeFrequency)
- m.Get("/data", repo.CodeFrequencyData)
- })
- m.Group("/recent-commits", func() {
- m.Get("", repo.RecentCommits)
- m.Get("/data", repo.RecentCommitsData)
- })
+
+ m.Group("", func() {
+ m.Group("/contributors", func() {
+ m.Get("", repo.Contributors)
+ m.Get("/data", repo.ContributorsData)
+ })
+ m.Group("/code-frequency", func() {
+ m.Get("", repo.CodeFrequency)
+ m.Get("/data", repo.CodeFrequencyData)
+ })
+ m.Group("/recent-commits", func() {
+ m.Get("", repo.RecentCommits)
+ m.Get("/data", repo.RecentCommitsData)
+ })
+ }, reqUnitCodeReader)
},
- optSignIn, context.RepoAssignment, context.RequireRepoReaderOr(unit.TypePullRequests, unit.TypeIssues, unit.TypeReleases),
- context.RepoRef(), repo.MustBeNotEmpty,
+ optSignIn, context.RepoAssignment, repo.MustBeNotEmpty,
+ context.RequireUnitReader(unit.TypeCode, unit.TypeIssues, unit.TypePullRequests, unit.TypeReleases),
)
// end "/{username}/{reponame}/activity"
m.Group("/{username}/{reponame}", func() {
- m.Group("/pulls/{index}", func() {
+ m.Get("/{type:pulls}", repo.Issues)
+ m.Group("/{type:pulls}/{index}", func() {
m.Get("", repo.SetWhitespaceBehavior, repo.GetPullDiffStats, repo.ViewIssue)
m.Get(".diff", repo.DownloadPullDiff)
m.Get(".patch", repo.DownloadPullPatch)
@@ -1501,7 +1508,7 @@ func registerRoutes(m *web.Router) {
}, context.RepoMustNotBeArchived())
})
})
- }, optSignIn, context.RepoAssignment, repo.MustAllowPulls, reqRepoPullsReader)
+ }, optSignIn, context.RepoAssignment, repo.MustAllowPulls, reqUnitPullsReader)
// end "/{username}/{reponame}/pulls/{index}": repo pull request
m.Group("/{username}/{reponame}", func() {
@@ -1582,13 +1589,13 @@ func registerRoutes(m *web.Router) {
m.Get("/forks", context.RepoRef(), repo.Forks)
m.Get("/commit/{sha:([a-f0-9]{7,64})}.{ext:patch|diff}", repo.MustBeNotEmpty, repo.RawDiff)
m.Post("/lastcommit/*", context.RepoRefByType(context.RepoRefCommit), repo.LastCommit)
- }, optSignIn, context.RepoAssignment, reqRepoCodeReader)
+ }, optSignIn, context.RepoAssignment, reqUnitCodeReader)
// end "/{username}/{reponame}": repo code
m.Group("/{username}/{reponame}", func() {
m.Get("/stars", repo.Stars)
m.Get("/watchers", repo.Watchers)
- m.Get("/search", reqRepoCodeReader, repo.Search)
+ m.Get("/search", reqUnitCodeReader, repo.Search)
m.Post("/action/{action}", reqSignIn, repo.Action)
}, optSignIn, context.RepoAssignment, context.RepoRef())
diff --git a/services/context/permission.go b/services/context/permission.go
index 9338587257..359d51c272 100644
--- a/services/context/permission.go
+++ b/services/context/permission.go
@@ -9,24 +9,13 @@ import (
auth_model "code.gitea.io/gitea/models/auth"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unit"
- "code.gitea.io/gitea/modules/log"
)
// RequireRepoAdmin returns a middleware for requiring repository admin permission
func RequireRepoAdmin() func(ctx *Context) {
return func(ctx *Context) {
if !ctx.IsSigned || !ctx.Repo.IsAdmin() {
- ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
- return
- }
- }
-}
-
-// RequireRepoWriter returns a middleware for requiring repository write to the specify unitType
-func RequireRepoWriter(unitType unit.Type) func(ctx *Context) {
- return func(ctx *Context) {
- if !ctx.Repo.CanWrite(unitType) {
- ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
+ ctx.NotFound("RequireRepoAdmin denies the request", nil)
return
}
}
@@ -42,75 +31,30 @@ func CanEnableEditor() func(ctx *Context) {
}
}
-// RequireRepoWriterOr returns a middleware for requiring repository write to one of the unit permission
-func RequireRepoWriterOr(unitTypes ...unit.Type) func(ctx *Context) {
+// RequireUnitWriter returns a middleware for requiring repository write to one of the unit permission
+func RequireUnitWriter(unitTypes ...unit.Type) func(ctx *Context) {
return func(ctx *Context) {
for _, unitType := range unitTypes {
if ctx.Repo.CanWrite(unitType) {
return
}
}
- ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
+ ctx.NotFound("RequireUnitWriter denies the request", nil)
}
}
-// RequireRepoReader returns a middleware for requiring repository read to the specify unitType
-func RequireRepoReader(unitType unit.Type) func(ctx *Context) {
- return func(ctx *Context) {
- if !ctx.Repo.CanRead(unitType) {
- if unitType == unit.TypeCode && canWriteAsMaintainer(ctx) {
- return
- }
- if log.IsTrace() {
- if ctx.IsSigned {
- log.Trace("Permission Denied: User %-v cannot read %-v in Repo %-v\n"+
- "User in Repo has Permissions: %-+v",
- ctx.Doer,
- unitType,
- ctx.Repo.Repository,
- ctx.Repo.Permission)
- } else {
- log.Trace("Permission Denied: Anonymous user cannot read %-v in Repo %-v\n"+
- "Anonymous user in Repo has Permissions: %-+v",
- unitType,
- ctx.Repo.Repository,
- ctx.Repo.Permission)
- }
- }
- ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
- return
- }
- }
-}
-
-// RequireRepoReaderOr returns a middleware for requiring repository write to one of the unit permission
-func RequireRepoReaderOr(unitTypes ...unit.Type) func(ctx *Context) {
+// RequireUnitReader returns a middleware for requiring repository write to one of the unit permission
+func RequireUnitReader(unitTypes ...unit.Type) func(ctx *Context) {
return func(ctx *Context) {
for _, unitType := range unitTypes {
if ctx.Repo.CanRead(unitType) {
return
}
- }
- if log.IsTrace() {
- var format string
- var args []any
- if ctx.IsSigned {
- format = "Permission Denied: User %-v cannot read ["
- args = append(args, ctx.Doer)
- } else {
- format = "Permission Denied: Anonymous user cannot read ["
- }
- for _, unit := range unitTypes {
- format += "%-v, "
- args = append(args, unit)
+ if unitType == unit.TypeCode && canWriteAsMaintainer(ctx) {
+ return
}
-
- format = format[:len(format)-2] + "] in Repo %-v\n" +
- "User in Repo has Permissions: %-+v"
- args = append(args, ctx.Repo.Repository, ctx.Repo.Permission)
- log.Trace(format, args...)
}
- ctx.NotFound(ctx.Req.URL.RequestURI(), nil)
+ ctx.NotFound("RequireUnitReader denies the request", nil)
}
}
diff --git a/services/forms/repo_form.go b/services/forms/repo_form.go
index 35ea5378d3..4f9806dc93 100644
--- a/services/forms/repo_form.go
+++ b/services/forms/repo_form.go
@@ -110,41 +110,51 @@ type RepoSettingForm struct {
EnablePrune bool
// Advanced settings
- EnableCode bool
- EnableWiki bool
- EnableExternalWiki bool
- DefaultWikiBranch string
- DefaultWikiEveryoneAccess string
- ExternalWikiURL string
+ EnableCode bool
+ DefaultCodeEveryoneAccess string
+
+ EnableWiki bool
+ EnableExternalWiki bool
+ DefaultWikiBranch string
+ DefaultWikiEveryoneAccess string
+ ExternalWikiURL string
+
EnableIssues bool
+ DefaultIssuesEveryoneAccess string
EnableExternalTracker bool
ExternalTrackerURL string
TrackerURLFormat string
TrackerIssueStyle string
ExternalTrackerRegexpPattern string
EnableCloseIssuesViaCommitInAnyBranch bool
- EnableProjects bool
- ProjectsMode string
- EnableReleases bool
- EnablePackages bool
- EnablePulls bool
- EnableActions bool
- PullsIgnoreWhitespace bool
- PullsAllowMerge bool
- PullsAllowRebase bool
- PullsAllowRebaseMerge bool
- PullsAllowSquash bool
- PullsAllowFastForwardOnly bool
- PullsAllowManualMerge bool
- PullsDefaultMergeStyle string
- EnableAutodetectManualMerge bool
- PullsAllowRebaseUpdate bool
- DefaultDeleteBranchAfterMerge bool
- DefaultAllowMaintainerEdit bool
- EnableTimetracker bool
- AllowOnlyContributorsToTrackTime bool
- EnableIssueDependencies bool
- IsArchived bool
+
+ EnableProjects bool
+ ProjectsMode string
+
+ EnableReleases bool
+
+ EnablePackages bool
+
+ EnablePulls bool
+ PullsIgnoreWhitespace bool
+ PullsAllowMerge bool
+ PullsAllowRebase bool
+ PullsAllowRebaseMerge bool
+ PullsAllowSquash bool
+ PullsAllowFastForwardOnly bool
+ PullsAllowManualMerge bool
+ PullsDefaultMergeStyle string
+ EnableAutodetectManualMerge bool
+ PullsAllowRebaseUpdate bool
+ DefaultDeleteBranchAfterMerge bool
+ DefaultAllowMaintainerEdit bool
+ EnableTimetracker bool
+ AllowOnlyContributorsToTrackTime bool
+ EnableIssueDependencies bool
+
+ EnableActions bool
+
+ IsArchived bool
// Signing Settings
TrustModel string
diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl
index 21eaf6a651..cb596f013b 100644
--- a/templates/repo/settings/options.tmpl
+++ b/templates/repo/settings/options.tmpl
@@ -302,6 +302,15 @@
<input class="enable-system" name="enable_code" type="checkbox"{{if $isCodeEnabled}} checked{{end}}>
<label>{{ctx.Locale.Tr "repo.code.desc"}}</label>
</div>
+ <div class="inline field tw-pl-4">
+ {{$unitCode := .Repository.MustGetUnit ctx ctx.Consts.RepoUnitTypeCode}}
+ <label>{{ctx.Locale.Tr "repo.settings.default_permission_everyone_access"}}</label>
+ <select name="default_code_everyone_access" class="ui selection dropdown">
+ {{/* everyone access mode is different from others, none means it is unset and won't be applied */}}
+ <option value="none" {{Iif (eq $unitCode.EveryoneAccessMode 0) "selected"}}>{{ctx.Locale.Tr "settings.permission_not_set"}}</option>
+ <option value="read" {{Iif (eq $unitCode.EveryoneAccessMode 1) "selected"}}>{{ctx.Locale.Tr "settings.permission_read"}}</option>
+ </select>
+ </div>
</div>
{{$isInternalWikiEnabled := .Repository.UnitEnabled ctx ctx.Consts.RepoUnitTypeWiki}}
@@ -331,7 +340,7 @@
</div>
<div class="inline field">
{{$unitInternalWiki := .Repository.MustGetUnit ctx ctx.Consts.RepoUnitTypeWiki}}
- <label>{{ctx.Locale.Tr "repo.settings.default_wiki_everyone_access"}}</label>
+ <label>{{ctx.Locale.Tr "repo.settings.default_permission_everyone_access"}}</label>
<select name="default_wiki_everyone_access" class="ui selection dropdown">
{{/* everyone access mode is different from others, none means it is unset and won't be applied */}}
<option value="none" {{Iif (eq $unitInternalWiki.EveryoneAccessMode 0) "selected"}}>{{ctx.Locale.Tr "settings.permission_not_set"}}</option>
@@ -374,6 +383,15 @@
</div>
</div>
<div class="field tw-pl-4 {{if (.Repository.UnitEnabled ctx ctx.Consts.RepoUnitTypeExternalTracker)}}disabled{{end}}" id="internal_issue_box">
+ <div class="inline field">
+ {{$unitIssue := .Repository.MustGetUnit ctx ctx.Consts.RepoUnitTypeIssues}}
+ <label>{{ctx.Locale.Tr "repo.settings.default_permission_everyone_access"}}</label>
+ <select name="default_issues_everyone_access" class="ui selection dropdown">
+ {{/* everyone access mode is different from others, none means it is unset and won't be applied */}}
+ <option value="none" {{Iif (eq $unitIssue.EveryoneAccessMode 0) "selected"}}>{{ctx.Locale.Tr "settings.permission_not_set"}}</option>
+ <option value="read" {{Iif (eq $unitIssue.EveryoneAccessMode 1) "selected"}}>{{ctx.Locale.Tr "settings.permission_read"}}</option>
+ </select>
+ </div>
{{if .Repository.CanEnableTimetracker}}
<div class="field">
<div class="ui checkbox">