Skip to content

Commit cd0ae8a

Browse files
committed
Merge branch 'main' into lunny/refactor_changestatus
2 parents 6fe3517 + 4c924bf commit cd0ae8a

Some content is hidden

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

57 files changed

+4362
-3808
lines changed

cmd/serv.go

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,10 @@ func fail(ctx context.Context, userMessage, logMsgFmt string, args ...any) error
111111
if !setting.IsProd {
112112
_, _ = fmt.Fprintln(os.Stderr, "Gitea:", logMsg)
113113
}
114-
if userMessage != "" {
115-
if unicode.IsPunct(rune(userMessage[len(userMessage)-1])) {
116-
logMsg = userMessage + " " + logMsg
117-
} else {
118-
logMsg = userMessage + ". " + logMsg
119-
}
114+
if unicode.IsPunct(rune(userMessage[len(userMessage)-1])) {
115+
logMsg = userMessage + " " + logMsg
116+
} else {
117+
logMsg = userMessage + ". " + logMsg
120118
}
121119
_ = private.SSHLog(ctx, true, logMsg)
122120
}
@@ -288,10 +286,10 @@ func runServ(c *cli.Context) error {
288286
if allowedCommands.Contains(verb) {
289287
if allowedCommandsLfs.Contains(verb) {
290288
if !setting.LFS.StartServer {
291-
return fail(ctx, "Unknown git command", "LFS authentication request over SSH denied, LFS support is disabled")
289+
return fail(ctx, "LFS Server is not enabled", "")
292290
}
293291
if verb == verbLfsTransfer && !setting.LFS.AllowPureSSH {
294-
return fail(ctx, "Unknown git command", "LFS SSH transfer connection denied, pure SSH protocol is disabled")
292+
return fail(ctx, "LFS SSH transfer is not enabled", "")
295293
}
296294
if len(words) > 2 {
297295
lfsVerb = words[2]

custom/conf/app.example.ini

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,6 +1007,14 @@ LEVEL = Info
10071007
;; The set of allowed values and rules are the same as DEFAULT_REPO_UNITS.
10081008
;DEFAULT_FORK_REPO_UNITS = repo.code,repo.pulls
10091009
;;
1010+
;; Comma separated list of default mirror repo units.
1011+
;; The set of allowed values and rules are the same as DEFAULT_REPO_UNITS.
1012+
;DEFAULT_MIRROR_REPO_UNITS = repo.code,repo.releases,repo.issues,repo.wiki,repo.projects,repo.packages
1013+
;;
1014+
;; Comma separated list of default template repo units.
1015+
;; The set of allowed values and rules are the same as DEFAULT_REPO_UNITS.
1016+
;DEFAULT_TEMPLATE_REPO_UNITS = repo.code,repo.releases,repo.issues,repo.pulls,repo.wiki,repo.projects,repo.packages
1017+
;;
10101018
;; Prefix archive files by placing them in a directory named after the repository
10111019
;PREFIX_ARCHIVE_FILES = true
10121020
;;

models/actions/task.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,7 +341,7 @@ func UpdateTask(ctx context.Context, task *ActionTask, cols ...string) error {
341341
// UpdateTaskByState updates the task by the state.
342342
// It will always update the task if the state is not final, even there is no change.
343343
// So it will update ActionTask.Updated to avoid the task being judged as a zombie task.
344-
func UpdateTaskByState(ctx context.Context, state *runnerv1.TaskState) (*ActionTask, error) {
344+
func UpdateTaskByState(ctx context.Context, runnerID int64, state *runnerv1.TaskState) (*ActionTask, error) {
345345
stepStates := map[int64]*runnerv1.StepState{}
346346
for _, v := range state.Steps {
347347
stepStates[v.Id] = v
@@ -360,6 +360,8 @@ func UpdateTaskByState(ctx context.Context, state *runnerv1.TaskState) (*ActionT
360360
return nil, err
361361
} else if !has {
362362
return nil, util.ErrNotExist
363+
} else if runnerID != task.RunnerID {
364+
return nil, fmt.Errorf("invalid runner for task")
363365
}
364366

365367
if task.Status.IsDone() {

models/fixtures/lfs_meta_object.yml

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
# These are the LFS objects in user2/lfs.git
2+
# user2/lfs is an INVALID repository
3+
#
4+
# commit e9c32647bab825977942598c0efa415de300304b (HEAD -> master)
5+
# Author: Rowan Bohde <[email protected]>
6+
# Date: Thu Aug 1 14:38:23 2024 -0500
7+
#
8+
# add invalid lfs file
29
-
310

411
id: 1
@@ -11,7 +18,7 @@
1118

1219
id: 2
1320
oid: 2eccdb43825d2a49d99d542daa20075cff1d97d9d2349a8977efe9c03661737c
14-
size: 107
21+
size: 107 # real size is 2048
1522
repository_id: 54
1623
created_unix: 1671607299
1724

@@ -30,3 +37,12 @@
3037
size: 25
3138
repository_id: 54
3239
created_unix: 1671607299
40+
41+
# this file is missing
42+
# -
43+
#
44+
# id: 5
45+
# oid: 9d178b5f15046343fd32f451df93acc2bdd9e6373be478b968e4cad6b6647351
46+
# size: 25
47+
# repository_id: 54
48+
# created_unix: 1671607299

models/fixtures/org_user.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,3 +129,9 @@
129129
uid: 2
130130
org_id: 35
131131
is_public: true
132+
133+
-
134+
id: 23
135+
uid: 20
136+
org_id: 17
137+
is_public: false

models/fixtures/user.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -623,7 +623,7 @@
623623
num_stars: 0
624624
num_repos: 2
625625
num_teams: 3
626-
num_members: 4
626+
num_members: 5
627627
visibility: 0
628628
repo_admin_change_team_access: false
629629
theme: ""

models/migrations/v1_21/v276.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"code.gitea.io/gitea/modules/git"
1313
giturl "code.gitea.io/gitea/modules/git/url"
1414
"code.gitea.io/gitea/modules/setting"
15+
"code.gitea.io/gitea/modules/util"
1516

1617
"xorm.io/xorm"
1718
)
@@ -163,7 +164,9 @@ func migratePushMirrors(x *xorm.Engine) error {
163164

164165
func getRemoteAddress(ownerName, repoName, remoteName string) (string, error) {
165166
repoPath := filepath.Join(setting.RepoRootPath, strings.ToLower(ownerName), strings.ToLower(repoName)+".git")
166-
167+
if exist, _ := util.IsExist(repoPath); !exist {
168+
return "", nil
169+
}
167170
remoteURL, err := git.GetRemoteAddress(context.Background(), repoPath, remoteName)
168171
if err != nil {
169172
return "", fmt.Errorf("get remote %s's address of %s/%s failed: %v", remoteName, ownerName, repoName, err)

models/organization/org.go

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
"code.gitea.io/gitea/modules/util"
2323

2424
"xorm.io/builder"
25+
"xorm.io/xorm"
2526
)
2627

2728
// ________ .__ __ .__
@@ -141,8 +142,9 @@ func (org *Organization) LoadTeams(ctx context.Context) ([]*Team, error) {
141142
}
142143

143144
// GetMembers returns all members of organization.
144-
func (org *Organization) GetMembers(ctx context.Context) (user_model.UserList, map[int64]bool, error) {
145+
func (org *Organization) GetMembers(ctx context.Context, doer *user_model.User) (user_model.UserList, map[int64]bool, error) {
145146
return FindOrgMembers(ctx, &FindOrgMembersOpts{
147+
Doer: doer,
146148
OrgID: org.ID,
147149
})
148150
}
@@ -195,16 +197,39 @@ func (org *Organization) CanCreateRepo() bool {
195197
// FindOrgMembersOpts represensts find org members conditions
196198
type FindOrgMembersOpts struct {
197199
db.ListOptions
198-
OrgID int64
199-
PublicOnly bool
200+
Doer *user_model.User
201+
IsDoerMember bool
202+
OrgID int64
203+
}
204+
205+
func (opts FindOrgMembersOpts) PublicOnly() bool {
206+
return opts.Doer == nil || !(opts.IsDoerMember || opts.Doer.IsAdmin)
207+
}
208+
209+
// applyTeamMatesOnlyFilter make sure restricted users only see public team members and there own team mates
210+
func (opts FindOrgMembersOpts) applyTeamMatesOnlyFilter(sess *xorm.Session) {
211+
if opts.Doer != nil && opts.IsDoerMember && opts.Doer.IsRestricted {
212+
teamMates := builder.Select("DISTINCT team_user.uid").
213+
From("team_user").
214+
Where(builder.In("team_user.team_id", getUserTeamIDsQueryBuilder(opts.OrgID, opts.Doer.ID))).
215+
And(builder.Eq{"team_user.org_id": opts.OrgID})
216+
217+
sess.And(
218+
builder.In("org_user.uid", teamMates).
219+
Or(builder.Eq{"org_user.is_public": true}),
220+
)
221+
}
200222
}
201223

202224
// CountOrgMembers counts the organization's members
203225
func CountOrgMembers(ctx context.Context, opts *FindOrgMembersOpts) (int64, error) {
204226
sess := db.GetEngine(ctx).Where("org_id=?", opts.OrgID)
205-
if opts.PublicOnly {
206-
sess.And("is_public = ?", true)
227+
if opts.PublicOnly() {
228+
sess = sess.And("is_public = ?", true)
229+
} else {
230+
opts.applyTeamMatesOnlyFilter(sess)
207231
}
232+
208233
return sess.Count(new(OrgUser))
209234
}
210235

@@ -525,9 +550,12 @@ func GetOrgsCanCreateRepoByUserID(ctx context.Context, userID int64) ([]*Organiz
525550
// GetOrgUsersByOrgID returns all organization-user relations by organization ID.
526551
func GetOrgUsersByOrgID(ctx context.Context, opts *FindOrgMembersOpts) ([]*OrgUser, error) {
527552
sess := db.GetEngine(ctx).Where("org_id=?", opts.OrgID)
528-
if opts.PublicOnly {
529-
sess.And("is_public = ?", true)
553+
if opts.PublicOnly() {
554+
sess = sess.And("is_public = ?", true)
555+
} else {
556+
opts.applyTeamMatesOnlyFilter(sess)
530557
}
558+
531559
if opts.ListOptions.PageSize > 0 {
532560
sess = db.SetSessionPagination(sess, opts)
533561

@@ -656,6 +684,15 @@ func (org *Organization) getUserTeamIDs(ctx context.Context, userID int64) ([]in
656684
Find(&teamIDs)
657685
}
658686

687+
func getUserTeamIDsQueryBuilder(orgID, userID int64) *builder.Builder {
688+
return builder.Select("team.id").From("team").
689+
InnerJoin("team_user", "team_user.team_id = team.id").
690+
Where(builder.Eq{
691+
"team_user.org_id": orgID,
692+
"team_user.uid": userID,
693+
})
694+
}
695+
659696
// TeamsWithAccessToRepo returns all teams that have given access level to the repository.
660697
func (org *Organization) TeamsWithAccessToRepo(ctx context.Context, repoID int64, mode perm.AccessMode) ([]*Team, error) {
661698
return GetTeamsWithAccessToRepo(ctx, org.ID, repoID, mode)

models/organization/org_test.go

Lines changed: 102 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
package organization_test
55

66
import (
7+
"slices"
8+
"sort"
79
"testing"
810

911
"code.gitea.io/gitea/models/db"
@@ -103,7 +105,7 @@ func TestUser_GetTeams(t *testing.T) {
103105
func TestUser_GetMembers(t *testing.T) {
104106
assert.NoError(t, unittest.PrepareTestDatabase())
105107
org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3})
106-
members, _, err := org.GetMembers(db.DefaultContext)
108+
members, _, err := org.GetMembers(db.DefaultContext, &user_model.User{IsAdmin: true})
107109
assert.NoError(t, err)
108110
if assert.Len(t, members, 3) {
109111
assert.Equal(t, int64(2), members[0].ID)
@@ -180,6 +182,75 @@ func TestIsPublicMembership(t *testing.T) {
180182
test(unittest.NonexistentID, unittest.NonexistentID, false)
181183
}
182184

185+
func TestRestrictedUserOrgMembers(t *testing.T) {
186+
assert.NoError(t, unittest.PrepareTestDatabase())
187+
188+
restrictedUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{
189+
ID: 29,
190+
IsRestricted: true,
191+
})
192+
if !assert.True(t, restrictedUser.IsRestricted) {
193+
return // ensure fixtures return restricted user
194+
}
195+
196+
testCases := []struct {
197+
name string
198+
opts *organization.FindOrgMembersOpts
199+
expectedUIDs []int64
200+
}{
201+
{
202+
name: "restricted user sees public members and teammates",
203+
opts: &organization.FindOrgMembersOpts{
204+
OrgID: 17, // org17 where user29 is in team9
205+
Doer: restrictedUser,
206+
IsDoerMember: true,
207+
},
208+
expectedUIDs: []int64{2, 15, 20, 29}, // Public members (2) + teammates in team9 (15, 20, 29)
209+
},
210+
{
211+
name: "restricted user sees only public members when not member",
212+
opts: &organization.FindOrgMembersOpts{
213+
OrgID: 3, // org3 where user29 is not a member
214+
Doer: restrictedUser,
215+
},
216+
expectedUIDs: []int64{2, 28}, // Only public members
217+
},
218+
{
219+
name: "non logged in only shows public members",
220+
opts: &organization.FindOrgMembersOpts{
221+
OrgID: 3,
222+
},
223+
expectedUIDs: []int64{2, 28}, // Only public members
224+
},
225+
{
226+
name: "non restricted user sees all members",
227+
opts: &organization.FindOrgMembersOpts{
228+
OrgID: 17,
229+
Doer: unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15}),
230+
IsDoerMember: true,
231+
},
232+
expectedUIDs: []int64{2, 15, 18, 20, 29}, // All members
233+
},
234+
}
235+
236+
for _, tc := range testCases {
237+
t.Run(tc.name, func(t *testing.T) {
238+
count, err := organization.CountOrgMembers(db.DefaultContext, tc.opts)
239+
assert.NoError(t, err)
240+
assert.EqualValues(t, len(tc.expectedUIDs), count)
241+
242+
members, err := organization.GetOrgUsersByOrgID(db.DefaultContext, tc.opts)
243+
assert.NoError(t, err)
244+
memberUIDs := make([]int64, 0, len(members))
245+
for _, member := range members {
246+
memberUIDs = append(memberUIDs, member.UID)
247+
}
248+
slices.Sort(memberUIDs)
249+
assert.EqualValues(t, tc.expectedUIDs, memberUIDs)
250+
})
251+
}
252+
}
253+
183254
func TestFindOrgs(t *testing.T) {
184255
assert.NoError(t, unittest.PrepareTestDatabase())
185256

@@ -210,37 +281,42 @@ func TestFindOrgs(t *testing.T) {
210281
func TestGetOrgUsersByOrgID(t *testing.T) {
211282
assert.NoError(t, unittest.PrepareTestDatabase())
212283

213-
orgUsers, err := organization.GetOrgUsersByOrgID(db.DefaultContext, &organization.FindOrgMembersOpts{
214-
ListOptions: db.ListOptions{},
215-
OrgID: 3,
216-
PublicOnly: false,
284+
opts := &organization.FindOrgMembersOpts{
285+
Doer: &user_model.User{IsAdmin: true},
286+
OrgID: 3,
287+
}
288+
assert.False(t, opts.PublicOnly())
289+
orgUsers, err := organization.GetOrgUsersByOrgID(db.DefaultContext, opts)
290+
assert.NoError(t, err)
291+
sort.Slice(orgUsers, func(i, j int) bool {
292+
return orgUsers[i].ID < orgUsers[j].ID
217293
})
294+
assert.EqualValues(t, []*organization.OrgUser{{
295+
ID: 1,
296+
OrgID: 3,
297+
UID: 2,
298+
IsPublic: true,
299+
}, {
300+
ID: 2,
301+
OrgID: 3,
302+
UID: 4,
303+
IsPublic: false,
304+
}, {
305+
ID: 9,
306+
OrgID: 3,
307+
UID: 28,
308+
IsPublic: true,
309+
}}, orgUsers)
310+
311+
opts = &organization.FindOrgMembersOpts{OrgID: 3}
312+
assert.True(t, opts.PublicOnly())
313+
orgUsers, err = organization.GetOrgUsersByOrgID(db.DefaultContext, opts)
218314
assert.NoError(t, err)
219-
if assert.Len(t, orgUsers, 3) {
220-
assert.Equal(t, organization.OrgUser{
221-
ID: orgUsers[0].ID,
222-
OrgID: 3,
223-
UID: 2,
224-
IsPublic: true,
225-
}, *orgUsers[0])
226-
assert.Equal(t, organization.OrgUser{
227-
ID: orgUsers[1].ID,
228-
OrgID: 3,
229-
UID: 4,
230-
IsPublic: false,
231-
}, *orgUsers[1])
232-
assert.Equal(t, organization.OrgUser{
233-
ID: orgUsers[2].ID,
234-
OrgID: 3,
235-
UID: 28,
236-
IsPublic: true,
237-
}, *orgUsers[2])
238-
}
315+
assert.Len(t, orgUsers, 2)
239316

240317
orgUsers, err = organization.GetOrgUsersByOrgID(db.DefaultContext, &organization.FindOrgMembersOpts{
241318
ListOptions: db.ListOptions{},
242319
OrgID: unittest.NonexistentID,
243-
PublicOnly: false,
244320
})
245321
assert.NoError(t, err)
246322
assert.Len(t, orgUsers, 0)

0 commit comments

Comments
 (0)