Skip to content

Commit cf29ee6

Browse files
authored
Add missing tabs to org projects page (#22705)
Fixes #22676 Context Data `IsOrganizationMember` and `IsOrganizationOwner` is used to control the visibility of `people` and `team` tab. https://github.com/go-gitea/gitea/blob/2871ea08096cba15546f357d0ec473734ee9d8be/templates/org/menu.tmpl#L19-L40 And because of the reuse of user projects page, User Context is changed to Organization Context. But the value of `IsOrganizationMember` and `IsOrganizationOwner` are not being given. I reused func `HandleOrgAssignment` to add them to the ctx, but may have some unnecessary variables, idk whether it is ok. I found there is a missing `PageIsViewProjects` at create project page.
1 parent 2173f14 commit cf29ee6

File tree

12 files changed

+115
-63
lines changed

12 files changed

+115
-63
lines changed

Diff for: models/organization/org.go

+26
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,32 @@ func (org *Organization) CustomAvatarRelativePath() string {
239239
return org.Avatar
240240
}
241241

242+
// UnitPermission returns unit permission
243+
func (org *Organization) UnitPermission(ctx context.Context, doer *user_model.User, unitType unit.Type) perm.AccessMode {
244+
if doer != nil {
245+
teams, err := GetUserOrgTeams(ctx, org.ID, doer.ID)
246+
if err != nil {
247+
log.Error("GetUserOrgTeams: %v", err)
248+
return perm.AccessModeNone
249+
}
250+
251+
if err := teams.LoadUnits(ctx); err != nil {
252+
log.Error("LoadUnits: %v", err)
253+
return perm.AccessModeNone
254+
}
255+
256+
if len(teams) > 0 {
257+
return teams.UnitMaxAccess(unitType)
258+
}
259+
}
260+
261+
if org.Visibility.IsPublic() {
262+
return perm.AccessModeRead
263+
}
264+
265+
return perm.AccessModeNone
266+
}
267+
242268
// CreateOrganization creates record of a new organization.
243269
func CreateOrganization(org *Organization, owner *user_model.User) (err error) {
244270
if !owner.CanCreateOrganization() {

Diff for: models/user/user.go

+5
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,11 @@ func (u *User) IsOrganization() bool {
393393
return u.Type == UserTypeOrganization
394394
}
395395

396+
// IsIndividual returns true if user is actually a individual user.
397+
func (u *User) IsIndividual() bool {
398+
return u.Type == UserTypeIndividual
399+
}
400+
396401
// DisplayName returns full name if it's not empty,
397402
// returns username otherwise.
398403
func (u *User) DisplayName() string {

Diff for: modules/context/org.go

+44-34
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
"code.gitea.io/gitea/models/perm"
1212
"code.gitea.io/gitea/models/unit"
1313
user_model "code.gitea.io/gitea/models/user"
14-
"code.gitea.io/gitea/modules/log"
1514
"code.gitea.io/gitea/modules/setting"
1615
"code.gitea.io/gitea/modules/structs"
1716
)
@@ -31,29 +30,34 @@ type Organization struct {
3130
}
3231

3332
func (org *Organization) CanWriteUnit(ctx *Context, unitType unit.Type) bool {
34-
if ctx.Doer == nil {
35-
return false
36-
}
37-
return org.UnitPermission(ctx, ctx.Doer.ID, unitType) >= perm.AccessModeWrite
33+
return org.Organization.UnitPermission(ctx, ctx.Doer, unitType) >= perm.AccessModeWrite
3834
}
3935

40-
func (org *Organization) UnitPermission(ctx *Context, doerID int64, unitType unit.Type) perm.AccessMode {
41-
if doerID > 0 {
42-
teams, err := organization.GetUserOrgTeams(ctx, org.Organization.ID, doerID)
43-
if err != nil {
44-
log.Error("GetUserOrgTeams: %v", err)
45-
return perm.AccessModeNone
46-
}
47-
if len(teams) > 0 {
48-
return teams.UnitMaxAccess(unitType)
49-
}
50-
}
36+
func (org *Organization) CanReadUnit(ctx *Context, unitType unit.Type) bool {
37+
return org.Organization.UnitPermission(ctx, ctx.Doer, unitType) >= perm.AccessModeRead
38+
}
5139

52-
if org.Organization.Visibility == structs.VisibleTypePublic {
53-
return perm.AccessModeRead
54-
}
40+
func GetOrganizationByParams(ctx *Context) {
41+
orgName := ctx.Params(":org")
42+
43+
var err error
5544

56-
return perm.AccessModeNone
45+
ctx.Org.Organization, err = organization.GetOrgByName(ctx, orgName)
46+
if err != nil {
47+
if organization.IsErrOrgNotExist(err) {
48+
redirectUserID, err := user_model.LookupUserRedirect(orgName)
49+
if err == nil {
50+
RedirectToUser(ctx, orgName, redirectUserID)
51+
} else if user_model.IsErrUserRedirectNotExist(err) {
52+
ctx.NotFound("GetUserByName", err)
53+
} else {
54+
ctx.ServerError("LookupUserRedirect", err)
55+
}
56+
} else {
57+
ctx.ServerError("GetUserByName", err)
58+
}
59+
return
60+
}
5761
}
5862

5963
// HandleOrgAssignment handles organization assignment
@@ -77,25 +81,26 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
7781
requireTeamAdmin = args[3]
7882
}
7983

80-
orgName := ctx.Params(":org")
81-
8284
var err error
83-
ctx.Org.Organization, err = organization.GetOrgByName(ctx, orgName)
84-
if err != nil {
85-
if organization.IsErrOrgNotExist(err) {
86-
redirectUserID, err := user_model.LookupUserRedirect(orgName)
87-
if err == nil {
88-
RedirectToUser(ctx, orgName, redirectUserID)
89-
} else if user_model.IsErrUserRedirectNotExist(err) {
90-
ctx.NotFound("GetUserByName", err)
91-
} else {
92-
ctx.ServerError("LookupUserRedirect", err)
85+
86+
if ctx.ContextUser == nil {
87+
// if Organization is not defined, get it from params
88+
if ctx.Org.Organization == nil {
89+
GetOrganizationByParams(ctx)
90+
if ctx.Written() {
91+
return
9392
}
94-
} else {
95-
ctx.ServerError("GetUserByName", err)
9693
}
94+
} else if ctx.ContextUser.IsOrganization() {
95+
if ctx.Org == nil {
96+
ctx.Org = &Organization{}
97+
}
98+
ctx.Org.Organization = (*organization.Organization)(ctx.ContextUser)
99+
} else {
100+
// ContextUser is an individual User
97101
return
98102
}
103+
99104
org := ctx.Org.Organization
100105

101106
// Handle Visibility
@@ -156,6 +161,7 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
156161
}
157162
ctx.Data["IsOrganizationOwner"] = ctx.Org.IsOwner
158163
ctx.Data["IsOrganizationMember"] = ctx.Org.IsMember
164+
ctx.Data["IsProjectEnabled"] = true
159165
ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled
160166
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
161167
ctx.Data["IsPublicMember"] = func(uid int64) bool {
@@ -231,6 +237,10 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
231237
return
232238
}
233239
}
240+
241+
ctx.Data["CanReadProjects"] = ctx.Org.CanReadUnit(ctx, unit.TypeProjects)
242+
ctx.Data["CanReadPackages"] = ctx.Org.CanReadUnit(ctx, unit.TypePackages)
243+
ctx.Data["CanReadCode"] = ctx.Org.CanReadUnit(ctx, unit.TypeCode)
234244
}
235245

236246
// OrgAssignment returns a middleware to handle organization assignment

Diff for: routers/web/org/home.go

+1
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ func Home(ctx *context.Context) {
156156
pager.SetDefaultParams(ctx)
157157
pager.AddParam(ctx, "language", "Language")
158158
ctx.Data["Page"] = pager
159+
ctx.Data["ContextUser"] = ctx.ContextUser
159160

160161
ctx.HTML(http.StatusOK, tplOrgHome)
161162
}

Diff for: routers/web/org/projects.go

+1
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ func NewProject(ctx *context.Context) {
123123
ctx.Data["Title"] = ctx.Tr("repo.projects.new")
124124
ctx.Data["BoardTypes"] = project_model.GetBoardConfig()
125125
ctx.Data["CanWriteProjects"] = canWriteProjects(ctx)
126+
ctx.Data["PageIsViewProjects"] = true
126127
ctx.Data["HomeLink"] = ctx.ContextUser.HomeLink()
127128
shared_user.RenderUserHeader(ctx)
128129
ctx.HTML(http.StatusOK, tplProjectsNew)

Diff for: routers/web/shared/user/header.go

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import (
99
)
1010

1111
func RenderUserHeader(ctx *context.Context) {
12+
ctx.Data["IsProjectEnabled"] = true
13+
ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled
1214
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
1315
ctx.Data["ContextUser"] = ctx.ContextUser
1416
}

Diff for: routers/web/user/code.go

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ func CodeSearch(ctx *context.Context) {
2424
return
2525
}
2626

27+
ctx.Data["IsProjectEnabled"] = true
2728
ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled
2829
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
2930
ctx.Data["Title"] = ctx.Tr("explore.code")

Diff for: routers/web/user/profile.go

+1
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ func Profile(ctx *context.Context) {
304304
pager.AddParam(ctx, "date", "Date")
305305
}
306306
ctx.Data["Page"] = pager
307+
ctx.Data["IsProjectEnabled"] = true
307308
ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled
308309
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
309310

Diff for: routers/web/web.go

+25-15
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,21 @@ func RegisterRoutes(m *web.Route) {
711711
}
712712
}
713713

714+
reqUnitAccess := func(unitType unit.Type, accessMode perm.AccessMode) func(ctx *context.Context) {
715+
return func(ctx *context.Context) {
716+
if ctx.ContextUser == nil {
717+
ctx.NotFound(unitType.String(), nil)
718+
return
719+
}
720+
if ctx.ContextUser.IsOrganization() {
721+
if ctx.Org.Organization.UnitPermission(ctx, ctx.Doer, unitType) < accessMode {
722+
ctx.NotFound(unitType.String(), nil)
723+
return
724+
}
725+
}
726+
}
727+
}
728+
714729
// ***** START: Organization *****
715730
m.Group("/org", func() {
716731
m.Group("/{org}", func() {
@@ -873,8 +888,10 @@ func RegisterRoutes(m *web.Route) {
873888
}
874889

875890
m.Group("/projects", func() {
876-
m.Get("", org.Projects)
877-
m.Get("/{id}", org.ViewProject)
891+
m.Group("", func() {
892+
m.Get("", org.Projects)
893+
m.Get("/{id}", org.ViewProject)
894+
}, reqUnitAccess(unit.TypeProjects, perm.AccessModeRead))
878895
m.Group("", func() { //nolint:dupl
879896
m.Get("/new", org.NewProject)
880897
m.Post("/new", web.Bind(forms.CreateProjectForm{}), org.NewProjectPost)
@@ -894,25 +911,18 @@ func RegisterRoutes(m *web.Route) {
894911
m.Post("/move", org.MoveIssues)
895912
})
896913
})
897-
}, reqSignIn, func(ctx *context.Context) {
898-
if ctx.ContextUser == nil {
899-
ctx.NotFound("NewProject", nil)
900-
return
901-
}
902-
if ctx.ContextUser.IsOrganization() {
903-
if !ctx.Org.CanWriteUnit(ctx, unit.TypeProjects) {
904-
ctx.NotFound("NewProject", nil)
905-
return
906-
}
907-
} else if ctx.ContextUser.ID != ctx.Doer.ID {
914+
}, reqSignIn, reqUnitAccess(unit.TypeProjects, perm.AccessModeWrite), func(ctx *context.Context) {
915+
if ctx.ContextUser.IsIndividual() && ctx.ContextUser.ID != ctx.Doer.ID {
908916
ctx.NotFound("NewProject", nil)
909917
return
910918
}
911919
})
912920
}, repo.MustEnableProjects)
913921

914-
m.Get("/code", user.CodeSearch)
915-
}, context_service.UserAssignmentWeb())
922+
m.Group("", func() {
923+
m.Get("/code", user.CodeSearch)
924+
}, reqUnitAccess(unit.TypeCode, perm.AccessModeRead))
925+
}, context_service.UserAssignmentWeb(), context.OrgAssignment())
916926

917927
// ***** Release Attachment Download without Signin
918928
m.Get("/{username}/{reponame}/releases/download/{vTag}/{fileName}", ignSignIn, context.RepoAssignment, repo.MustBeNotEmpty, repo.RedirectDownload)

Diff for: services/context/user.go

-9
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"net/http"
99
"strings"
1010

11-
org_model "code.gitea.io/gitea/models/organization"
1211
user_model "code.gitea.io/gitea/models/user"
1312
"code.gitea.io/gitea/modules/context"
1413
)
@@ -57,14 +56,6 @@ func userAssignment(ctx *context.Context, errCb func(int, string, interface{}))
5756
} else {
5857
errCb(http.StatusInternalServerError, "GetUserByName", err)
5958
}
60-
} else {
61-
if ctx.ContextUser.IsOrganization() {
62-
if ctx.Org == nil {
63-
ctx.Org = &context.Organization{}
64-
}
65-
ctx.Org.Organization = (*org_model.Organization)(ctx.ContextUser)
66-
ctx.Data["Org"] = ctx.Org.Organization
67-
}
6859
}
6960
}
7061
}

Diff for: templates/org/menu.tmpl

+5-3
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,18 @@
33
<a class="{{if .PageIsViewRepositories}}active {{end}}item" href="{{$.Org.HomeLink}}">
44
{{svg "octicon-repo"}} {{.locale.Tr "user.repositories"}}
55
</a>
6+
{{if and .IsProjectEnabled .CanReadProjects}}
67
<a class="{{if .PageIsViewProjects}}active {{end}}item" href="{{$.Org.HomeLink}}/-/projects">
78
{{svg "octicon-project-symlink"}} {{.locale.Tr "user.projects"}}
89
</a>
9-
{{if .IsPackageEnabled}}
10+
{{end}}
11+
{{if and .IsPackageEnabled .CanReadPackages}}
1012
<a class="item" href="{{$.Org.HomeLink}}/-/packages">
1113
{{svg "octicon-package"}} {{.locale.Tr "packages.title"}}
1214
</a>
1315
{{end}}
14-
{{if .IsRepoIndexerEnabled}}
15-
<a class="{{if $.PageIsOrgCode}}active {{end}}item" href="{{$.Org.HomeLink}}/-/code">
16+
{{if and .IsRepoIndexerEnabled .CanReadCode}}
17+
<a class="item" href="{{$.Org.HomeLink}}/-/code">
1618
{{svg "octicon-code"}}&nbsp;{{$.locale.Tr "org.code"}}
1719
</a>
1820
{{end}}

Diff for: templates/user/overview/header.tmpl

+4-2
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,17 @@
2222
<a class="item" href="{{.ContextUser.HomeLink}}">
2323
{{svg "octicon-repo"}} {{.locale.Tr "user.repositories"}}
2424
</a>
25+
{{if and .IsProjectEnabled (or .ContextUser.IsIndividual (and .ContextUser.IsOrganization .CanReadProjects))}}
2526
<a href="{{.ContextUser.HomeLink}}/-/projects" class="{{if .PageIsViewProjects}}active {{end}}item">
2627
{{svg "octicon-project-symlink"}} {{.locale.Tr "user.projects"}}
2728
</a>
28-
{{if (not .UnitPackagesGlobalDisabled)}}
29+
{{end}}
30+
{{if and .IsPackageEnabled (or .ContextUser.IsIndividual (and .ContextUser.IsOrganization .CanReadPackages))}}
2931
<a href="{{.ContextUser.HomeLink}}/-/packages" class="{{if .IsPackagesPage}}active {{end}}item">
3032
{{svg "octicon-package"}} {{.locale.Tr "packages.title"}}
3133
</a>
3234
{{end}}
33-
{{if .IsRepoIndexerEnabled}}
35+
{{if and .IsRepoIndexerEnabled (or .ContextUser.IsIndividual (and .ContextUser.IsOrganization .CanReadCode))}}
3436
<a href="{{.ContextUser.HomeLink}}/-/code" class="{{if .IsCodePage}}active {{end}}item">
3537
{{svg "octicon-code"}} {{.locale.Tr "user.code"}}
3638
</a>

0 commit comments

Comments
 (0)