Skip to content

Commit b6555d5

Browse files
committed
Merge remote-tracking branch 'giteaofficial/main'
* giteaofficial/main: Move org functions (go-gitea#19753) [doctor] pq: syntax error at or near "." quote user table name (go-gitea#19765) [doctor] update the help with fix capabilities (go-gitea#19762) Remove fomantic progress module (go-gitea#19760) Make Ctrl+Enter (quick submit) work for issue comment and wiki editor (go-gitea#19729) Enable packages by default again (as described by docs) (go-gitea#19746) Replace blue button and label classes with primary (go-gitea#19763) Fix org package owner permissions (go-gitea#19742)
2 parents 748ae8f + d81e31a commit b6555d5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+345
-2317
lines changed

cmd/doctor.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ import (
2424
// CmdDoctor represents the available doctor sub-command.
2525
var CmdDoctor = cli.Command{
2626
Name: "doctor",
27-
Usage: "Diagnose problems",
28-
Description: "A command to diagnose problems with the current Gitea instance according to the given configuration.",
27+
Usage: "Diagnose and optionally fix problems",
28+
Description: "A command to diagnose problems with the current Gitea instance according to the given configuration. Some problems can optionally be fixed by modifying the database or data storage.",
2929
Action: runDoctor,
3030
Flags: []cli.Flag{
3131
cli.BoolFlag{

models/organization/org_user.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package organization
66

77
import (
88
"context"
9+
"fmt"
910

1011
"code.gitea.io/gitea/models/db"
1112
user_model "code.gitea.io/gitea/models/user"
@@ -81,3 +82,43 @@ func CanCreateOrgRepo(orgID, uid int64) (bool, error) {
8182
And("team_user.org_id = ?", orgID).
8283
Exist(new(Team))
8384
}
85+
86+
// IsUserOrgOwner returns true if user is in the owner team of given organization.
87+
func IsUserOrgOwner(users user_model.UserList, orgID int64) map[int64]bool {
88+
results := make(map[int64]bool, len(users))
89+
for _, user := range users {
90+
results[user.ID] = false // Set default to false
91+
}
92+
ownerMaps, err := loadOrganizationOwners(db.DefaultContext, users, orgID)
93+
if err == nil {
94+
for _, owner := range ownerMaps {
95+
results[owner.UID] = true
96+
}
97+
}
98+
return results
99+
}
100+
101+
func loadOrganizationOwners(ctx context.Context, users user_model.UserList, orgID int64) (map[int64]*TeamUser, error) {
102+
if len(users) == 0 {
103+
return nil, nil
104+
}
105+
ownerTeam, err := GetOwnerTeam(ctx, orgID)
106+
if err != nil {
107+
if IsErrTeamNotExist(err) {
108+
log.Error("Organization does not have owner team: %d", orgID)
109+
return nil, nil
110+
}
111+
return nil, err
112+
}
113+
114+
userIDs := users.GetUserIDs()
115+
ownerMaps := make(map[int64]*TeamUser)
116+
err = db.GetEngine(ctx).In("uid", userIDs).
117+
And("org_id=?", orgID).
118+
And("team_id=?", ownerTeam.ID).
119+
Find(&ownerMaps)
120+
if err != nil {
121+
return nil, fmt.Errorf("find team users: %v", err)
122+
}
123+
return ownerMaps, nil
124+
}

models/organization/org_user_test.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,57 @@ func testIsUserOrgOwner(t *testing.T, uid, orgID int64, expected bool) {
7070
assert.NoError(t, err)
7171
assert.Equal(t, expected, is)
7272
}
73+
74+
func TestUserListIsPublicMember(t *testing.T) {
75+
assert.NoError(t, unittest.PrepareTestDatabase())
76+
tt := []struct {
77+
orgid int64
78+
expected map[int64]bool
79+
}{
80+
{3, map[int64]bool{2: true, 4: false, 28: true}},
81+
{6, map[int64]bool{5: true, 28: true}},
82+
{7, map[int64]bool{5: false}},
83+
{25, map[int64]bool{24: true}},
84+
{22, map[int64]bool{}},
85+
}
86+
for _, v := range tt {
87+
t.Run(fmt.Sprintf("IsPublicMemberOfOrdIg%d", v.orgid), func(t *testing.T) {
88+
testUserListIsPublicMember(t, v.orgid, v.expected)
89+
})
90+
}
91+
}
92+
93+
func testUserListIsPublicMember(t *testing.T, orgID int64, expected map[int64]bool) {
94+
org, err := GetOrgByID(orgID)
95+
assert.NoError(t, err)
96+
_, membersIsPublic, err := org.GetMembers()
97+
assert.NoError(t, err)
98+
assert.Equal(t, expected, membersIsPublic)
99+
}
100+
101+
func TestUserListIsUserOrgOwner(t *testing.T) {
102+
assert.NoError(t, unittest.PrepareTestDatabase())
103+
tt := []struct {
104+
orgid int64
105+
expected map[int64]bool
106+
}{
107+
{3, map[int64]bool{2: true, 4: false, 28: false}},
108+
{6, map[int64]bool{5: true, 28: false}},
109+
{7, map[int64]bool{5: true}},
110+
{25, map[int64]bool{24: false}}, // ErrTeamNotExist
111+
{22, map[int64]bool{}}, // No member
112+
}
113+
for _, v := range tt {
114+
t.Run(fmt.Sprintf("IsUserOrgOwnerOfOrdIg%d", v.orgid), func(t *testing.T) {
115+
testUserListIsUserOrgOwner(t, v.orgid, v.expected)
116+
})
117+
}
118+
}
119+
120+
func testUserListIsUserOrgOwner(t *testing.T, orgID int64, expected map[int64]bool) {
121+
org, err := GetOrgByID(orgID)
122+
assert.NoError(t, err)
123+
members, _, err := org.GetMembers()
124+
assert.NoError(t, err)
125+
assert.Equal(t, expected, IsUserOrgOwner(members, orgID))
126+
}

models/userlist.go

Lines changed: 0 additions & 55 deletions
This file was deleted.

models/userlist_test.go

Lines changed: 0 additions & 69 deletions
This file was deleted.

modules/context/package.go

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
packages_model "code.gitea.io/gitea/models/packages"
1313
"code.gitea.io/gitea/models/perm"
1414
user_model "code.gitea.io/gitea/models/user"
15+
"code.gitea.io/gitea/modules/structs"
1516
)
1617

1718
// Package contains owner, access mode and optional the package descriptor
@@ -50,22 +51,29 @@ func packageAssignment(ctx *Context, errCb func(int, string, interface{})) {
5051
Owner: ctx.ContextUser,
5152
}
5253

53-
if ctx.Doer != nil && ctx.Doer.ID == ctx.ContextUser.ID {
54-
ctx.Package.AccessMode = perm.AccessModeOwner
54+
if ctx.Package.Owner.IsOrganization() {
55+
// 1. Get user max authorize level for the org (may be none, if user is not member of the org)
56+
if ctx.Doer != nil {
57+
var err error
58+
ctx.Package.AccessMode, err = organization.OrgFromUser(ctx.Package.Owner).GetOrgUserMaxAuthorizeLevel(ctx.Doer.ID)
59+
if err != nil {
60+
errCb(http.StatusInternalServerError, "GetOrgUserMaxAuthorizeLevel", err)
61+
return
62+
}
63+
}
64+
// 2. If authorize level is none, check if org is visible to user
65+
if ctx.Package.AccessMode == perm.AccessModeNone && organization.HasOrgOrUserVisible(ctx, ctx.Package.Owner, ctx.Doer) {
66+
ctx.Package.AccessMode = perm.AccessModeRead
67+
}
5568
} else {
56-
if ctx.Package.Owner.IsOrganization() {
57-
if organization.HasOrgOrUserVisible(ctx, ctx.Package.Owner, ctx.Doer) {
69+
if ctx.Doer != nil && !ctx.Doer.IsGhost() {
70+
// 1. Check if user is package owner
71+
if ctx.Doer.ID == ctx.Package.Owner.ID {
72+
ctx.Package.AccessMode = perm.AccessModeOwner
73+
} else if ctx.Package.Owner.Visibility == structs.VisibleTypePublic || ctx.Package.Owner.Visibility == structs.VisibleTypeLimited { // 2. Check if package owner is public or limited
5874
ctx.Package.AccessMode = perm.AccessModeRead
59-
if ctx.Doer != nil {
60-
var err error
61-
ctx.Package.AccessMode, err = organization.OrgFromUser(ctx.Package.Owner).GetOrgUserMaxAuthorizeLevel(ctx.Doer.ID)
62-
if err != nil {
63-
errCb(http.StatusInternalServerError, "GetOrgUserMaxAuthorizeLevel", err)
64-
return
65-
}
66-
}
6775
}
68-
} else {
76+
} else if ctx.Package.Owner.Visibility == structs.VisibleTypePublic { // 3. Check if package owner is public
6977
ctx.Package.AccessMode = perm.AccessModeRead
7078
}
7179
}

modules/doctor/dbconsistency.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,10 +191,10 @@ func checkDBConsistency(ctx context.Context, logger log.Logger, autofix bool) er
191191
"action", "repository", "action.repo_id=repository.id"),
192192
// find OAuth2Grant without existing user
193193
genericOrphanCheck("Orphaned OAuth2Grant without existing User",
194-
"oauth2_grant", "user", "oauth2_grant.user_id=user.id"),
194+
"oauth2_grant", "user", "oauth2_grant.user_id=`user`.id"),
195195
// find OAuth2Application without existing user
196196
genericOrphanCheck("Orphaned OAuth2Application without existing User",
197-
"oauth2_application", "user", "oauth2_application.uid=user.id"),
197+
"oauth2_application", "user", "oauth2_application.uid=`user`.id"),
198198
// find OAuth2AuthorizationCode without existing OAuth2Grant
199199
genericOrphanCheck("Orphaned OAuth2AuthorizationCode without existing OAuth2Grant",
200200
"oauth2_authorization_code", "oauth2_grant", "oauth2_authorization_code.grant_id=oauth2_grant.id"),

modules/setting/repository.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ func newRepository() {
295295
log.Fatal("Failed to map Repository.PullRequest settings: %v", err)
296296
}
297297

298-
if !Cfg.Section("packages").Key("ENABLED").MustBool(false) {
298+
if !Cfg.Section("packages").Key("ENABLED").MustBool(true) {
299299
Repository.DisabledRepoUnits = append(Repository.DisabledRepoUnits, "repo.packages")
300300
}
301301

routers/web/org/members.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ func Members(ctx *context.Context) {
6363
ctx.Data["Page"] = pager
6464
ctx.Data["Members"] = members
6565
ctx.Data["MembersIsPublicMember"] = membersIsPublic
66-
ctx.Data["MembersIsUserOrgOwner"] = models.IsUserOrgOwner(members, org.ID)
66+
ctx.Data["MembersIsUserOrgOwner"] = organization.IsUserOrgOwner(members, org.ID)
6767
ctx.Data["MembersTwoFaStatus"] = members.GetTwoFaStatus()
6868

6969
ctx.HTML(http.StatusOK, tplMembers)

services/forms/repo_form.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -623,7 +623,7 @@ func (f *CodeCommentForm) Validate(req *http.Request, errs binding.Errors) bindi
623623
// SubmitReviewForm for submitting a finished code review
624624
type SubmitReviewForm struct {
625625
Content string
626-
Type string `binding:"Required;In(approve,comment,reject)"`
626+
Type string
627627
CommitID string
628628
Files []string
629629
}
@@ -634,7 +634,7 @@ func (f *SubmitReviewForm) Validate(req *http.Request, errs binding.Errors) bind
634634
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
635635
}
636636

637-
// ReviewType will return the corresponding reviewtype for type
637+
// ReviewType will return the corresponding ReviewType for type
638638
func (f SubmitReviewForm) ReviewType() models.ReviewType {
639639
switch f.Type {
640640
case "approve":
@@ -643,6 +643,8 @@ func (f SubmitReviewForm) ReviewType() models.ReviewType {
643643
return models.ReviewTypeComment
644644
case "reject":
645645
return models.ReviewTypeReject
646+
case "":
647+
return models.ReviewTypeComment // default to comment when doing quick-submit (Ctrl+Enter) on the review form
646648
default:
647649
return models.ReviewTypeUnknown
648650
}

templates/admin/auth/list.tmpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<h4 class="ui top attached header">
77
{{.i18n.Tr "admin.auths.auth_manage_panel"}} ({{.i18n.Tr "admin.total" .Total}})
88
<div class="ui right">
9-
<a class="ui blue tiny button" href="{{AppSubUrl}}/admin/auths/new">{{.i18n.Tr "admin.auths.new"}}</a>
9+
<a class="ui primary tiny button" href="{{AppSubUrl}}/admin/auths/new">{{.i18n.Tr "admin.auths.new"}}</a>
1010
</div>
1111
</h4>
1212
<div class="ui attached table segment">

templates/admin/base/search.tmpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,6 @@
1818
<form class="ui form ignore-dirty" style="max-width: 90%;">
1919
<div class="ui fluid action input">
2020
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..." autofocus>
21-
<button class="ui blue button">{{.i18n.Tr "explore.search"}}</button>
21+
<button class="ui primary button">{{.i18n.Tr "explore.search"}}</button>
2222
</div>
2323
</form>

templates/admin/emails/list.tmpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
<form class="ui form ignore-dirty" style="max-width: 90%">
2626
<div class="ui fluid action input">
2727
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..." autofocus>
28-
<button class="ui blue button">{{.i18n.Tr "explore.search"}}</button>
28+
<button class="ui primary button">{{.i18n.Tr "explore.search"}}</button>
2929
</div>
3030
</form>
3131
</div>

templates/admin/org/list.tmpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<h4 class="ui top attached header">
77
{{.i18n.Tr "admin.orgs.org_manage_panel"}} ({{.i18n.Tr "admin.total" .Total}})
88
<div class="ui right">
9-
<a class="ui blue tiny button" href="{{AppSubUrl}}/org/create">{{.i18n.Tr "admin.orgs.new_orga"}}</a>
9+
<a class="ui primary tiny button" href="{{AppSubUrl}}/org/create">{{.i18n.Tr "admin.orgs.new_orga"}}</a>
1010
</div>
1111
</h4>
1212
<div class="ui attached segment">

templates/admin/packages/list.tmpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
<option value="pypi" {{if eq .PackageType "pypi"}}selected="selected"{{end}}>PyPi</option>
2525
<option value="rubygems" {{if eq .PackageType "rubygems"}}selected="selected"{{end}}>RubyGems</option>
2626
</select>
27-
<button class="ui blue button">{{.i18n.Tr "explore.search"}}</button>
27+
<button class="ui primary button">{{.i18n.Tr "explore.search"}}</button>
2828
</div>
2929
</form>
3030
</div>

0 commit comments

Comments
 (0)