mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-12-23 14:53:34 +01:00
Merge pull request '[gitea] week 2024-48 cherry pick (gitea/main -> forgejo)' (#6062) from earl-warren/wcp/2024-48 into forgejo
Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/6062 Reviewed-by: Gusted <gusted@noreply.codeberg.org>
This commit is contained in:
commit
e5417fdede
18 changed files with 287 additions and 146 deletions
|
@ -29,7 +29,6 @@
|
|||
poetry
|
||||
|
||||
# backend
|
||||
go_1_22
|
||||
gofumpt
|
||||
sqlite
|
||||
];
|
||||
|
|
|
@ -1,3 +1,22 @@
|
|||
-
|
||||
id: 46
|
||||
attempt: 3
|
||||
runner_id: 1
|
||||
status: 3 # 3 is the status code for "cancelled"
|
||||
started: 1683636528
|
||||
stopped: 1683636626
|
||||
repo_id: 4
|
||||
owner_id: 1
|
||||
commit_sha: c2d72f548424103f01ee1dc02889c1e2bff816b0
|
||||
is_fork_pull_request: 0
|
||||
token_hash: 6d8ef48297195edcc8e22c70b3020eaa06c52976db67d39b4260c64a69a2cc1508825121b7b8394e48e00b1bf8718b2aaaaa
|
||||
token_salt: eeeeeeee
|
||||
token_last_eight: eeeeeeee
|
||||
log_filename: artifact-test2/2f/47.log
|
||||
log_in_storage: 1
|
||||
log_length: 707
|
||||
log_size: 90179
|
||||
log_expired: 0
|
||||
-
|
||||
id: 47
|
||||
job_id: 192
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
-
|
||||
id: 1
|
||||
setting_key: 'picture.disable_gravatar'
|
||||
setting_value: 'false'
|
||||
setting_value: 'true'
|
||||
version: 1
|
||||
created: 1653533198
|
||||
updated: 1653533198
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar1
|
||||
avatar: ""
|
||||
avatar_email: user1@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -60,8 +60,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar2
|
||||
avatar: ""
|
||||
avatar_email: user2@example.com
|
||||
# cause a random avatar to be generated when referenced for test purposes
|
||||
use_custom_avatar: false
|
||||
num_followers: 2
|
||||
num_following: 1
|
||||
|
@ -97,9 +98,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar3
|
||||
avatar: ""
|
||||
avatar_email: org3@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -134,9 +135,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar4
|
||||
avatar: ""
|
||||
avatar_email: user4@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 1
|
||||
num_stars: 0
|
||||
|
@ -171,9 +172,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: false
|
||||
prohibit_login: false
|
||||
avatar: avatar5
|
||||
avatar: ""
|
||||
avatar_email: user5@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -208,9 +209,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar6
|
||||
avatar: ""
|
||||
avatar_email: org6@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -245,9 +246,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar7
|
||||
avatar: ""
|
||||
avatar_email: org7@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -282,9 +283,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar8
|
||||
avatar: ""
|
||||
avatar_email: user8@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 1
|
||||
num_following: 1
|
||||
num_stars: 0
|
||||
|
@ -319,9 +320,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar9
|
||||
avatar: ""
|
||||
avatar_email: user9@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -332,6 +333,7 @@
|
|||
repo_admin_change_team_access: false
|
||||
theme: ""
|
||||
keep_activity_private: false
|
||||
created_unix: 1730468968
|
||||
|
||||
-
|
||||
id: 10
|
||||
|
@ -356,9 +358,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar10
|
||||
avatar: ""
|
||||
avatar_email: user10@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -393,9 +395,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar11
|
||||
avatar: ""
|
||||
avatar_email: user11@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -430,9 +432,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar12
|
||||
avatar: ""
|
||||
avatar_email: user12@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -467,9 +469,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar13
|
||||
avatar: ""
|
||||
avatar_email: user13@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -504,9 +506,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar14
|
||||
avatar: ""
|
||||
avatar_email: user13@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -541,9 +543,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar15
|
||||
avatar: ""
|
||||
avatar_email: user15@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -578,9 +580,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar16
|
||||
avatar: ""
|
||||
avatar_email: user16@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -615,9 +617,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar17
|
||||
avatar: ""
|
||||
avatar_email: org17@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -652,9 +654,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar18
|
||||
avatar: ""
|
||||
avatar_email: user18@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -689,9 +691,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar19
|
||||
avatar: ""
|
||||
avatar_email: org19@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -726,9 +728,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar20
|
||||
avatar: ""
|
||||
avatar_email: user20@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -763,9 +765,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar21
|
||||
avatar: ""
|
||||
avatar_email: user21@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -800,9 +802,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar22
|
||||
avatar: ""
|
||||
avatar_email: limited_org@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -837,9 +839,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar23
|
||||
avatar: ""
|
||||
avatar_email: privated_org@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -874,9 +876,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar24
|
||||
avatar: ""
|
||||
avatar_email: user24@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -911,9 +913,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar25
|
||||
avatar: ""
|
||||
avatar_email: org25@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -948,9 +950,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar26
|
||||
avatar: ""
|
||||
avatar_email: org26@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -985,9 +987,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar27
|
||||
avatar: ""
|
||||
avatar_email: user27@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -1022,9 +1024,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar28
|
||||
avatar: ""
|
||||
avatar_email: user28@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -1059,9 +1061,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar29
|
||||
avatar: ""
|
||||
avatar_email: user29@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -1096,9 +1098,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar29
|
||||
avatar: ""
|
||||
avatar_email: user30@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -1133,9 +1135,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar31
|
||||
avatar: ""
|
||||
avatar_email: user31@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 1
|
||||
num_stars: 0
|
||||
|
@ -1170,9 +1172,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar32
|
||||
avatar: ""
|
||||
avatar_email: user30@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -1207,9 +1209,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar33
|
||||
avatar: ""
|
||||
avatar_email: user33@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 1
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -1245,7 +1247,7 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: false
|
||||
prohibit_login: false
|
||||
avatar: avatar34
|
||||
avatar: ""
|
||||
avatar_email: user34@example.com
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
|
@ -1282,9 +1284,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar35
|
||||
avatar: ""
|
||||
avatar_email: private_org35@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -1319,9 +1321,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar22
|
||||
avatar: ""
|
||||
avatar_email: abcde@gitea.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -1356,9 +1358,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: true
|
||||
avatar: avatar29
|
||||
avatar: ""
|
||||
avatar_email: user37@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -1393,9 +1395,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar38
|
||||
avatar: ""
|
||||
avatar_email: user38@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -1430,9 +1432,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar39
|
||||
avatar: ""
|
||||
avatar_email: user39@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -1467,9 +1469,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar40
|
||||
avatar: ""
|
||||
avatar_email: user40@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
@ -1504,9 +1506,9 @@
|
|||
allow_import_local: false
|
||||
allow_create_organization: true
|
||||
prohibit_login: false
|
||||
avatar: avatar41
|
||||
avatar: ""
|
||||
avatar_email: org41@example.com
|
||||
use_custom_avatar: false
|
||||
use_custom_avatar: true
|
||||
num_followers: 0
|
||||
num_following: 0
|
||||
num_stars: 0
|
||||
|
|
|
@ -50,19 +50,19 @@ const (
|
|||
UserTypeIndividual UserType = iota // Historic reason to make it starts at 0.
|
||||
|
||||
// UserTypeOrganization defines an organization
|
||||
UserTypeOrganization
|
||||
UserTypeOrganization // 1
|
||||
|
||||
// UserTypeUserReserved reserves a (non-existing) user, i.e. to prevent a spam user from re-registering after being deleted, or to reserve the name until the user is actually created later on
|
||||
UserTypeUserReserved
|
||||
UserTypeUserReserved // 2
|
||||
|
||||
// UserTypeOrganizationReserved reserves a (non-existing) organization, to be used in combination with UserTypeUserReserved
|
||||
UserTypeOrganizationReserved
|
||||
UserTypeOrganizationReserved // 3
|
||||
|
||||
// UserTypeBot defines a bot user
|
||||
UserTypeBot
|
||||
UserTypeBot // 4
|
||||
|
||||
// UserTypeRemoteUser defines a remote user for federated users
|
||||
UserTypeRemoteUser
|
||||
UserTypeRemoteUser // 5
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -919,7 +919,13 @@ func UpdateUserCols(ctx context.Context, u *User, cols ...string) error {
|
|||
|
||||
// GetInactiveUsers gets all inactive users
|
||||
func GetInactiveUsers(ctx context.Context, olderThan time.Duration) ([]*User, error) {
|
||||
var cond builder.Cond = builder.Eq{"is_active": false}
|
||||
cond := builder.And(
|
||||
builder.Eq{"is_active": false},
|
||||
builder.Or( // only plain user
|
||||
builder.Eq{"`type`": UserTypeIndividual},
|
||||
builder.Eq{"`type`": UserTypeUserReserved},
|
||||
),
|
||||
)
|
||||
|
||||
if olderThan > 0 {
|
||||
cond = cond.And(builder.Lt{"created_unix": time.Now().Add(-olderThan).Unix()})
|
||||
|
|
|
@ -766,3 +766,17 @@ func TestVerifyUserAuthorizationToken(t *testing.T) {
|
|||
assert.Nil(t, authToken)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetInactiveUsers(t *testing.T) {
|
||||
require.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
// all inactive users
|
||||
// user1's createdunix is 1730468968
|
||||
users, err := user_model.GetInactiveUsers(db.DefaultContext, 0)
|
||||
require.NoError(t, err)
|
||||
assert.Len(t, users, 1)
|
||||
interval := time.Now().Unix() - 1730468968 + 3600*24
|
||||
users, err = user_model.GetInactiveUsers(db.DefaultContext, time.Duration(interval*int64(time.Second)))
|
||||
require.NoError(t, err)
|
||||
require.Empty(t, users)
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@ import (
|
|||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"github.com/go-git/go-git/v5/config"
|
||||
)
|
||||
|
||||
// Commit represents a git commit.
|
||||
|
@ -365,37 +367,32 @@ func (c *Commit) GetSubModules() (*ObjectCache, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
rd, err := entry.Blob().DataAsync()
|
||||
content, err := entry.Blob().GetBlobContent(10 * 1024)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer rd.Close()
|
||||
scanner := bufio.NewScanner(rd)
|
||||
c.submoduleCache = newObjectCache()
|
||||
var ismodule bool
|
||||
var path string
|
||||
for scanner.Scan() {
|
||||
if strings.HasPrefix(scanner.Text(), "[submodule") {
|
||||
ismodule = true
|
||||
continue
|
||||
}
|
||||
if ismodule {
|
||||
fields := strings.Split(scanner.Text(), "=")
|
||||
k := strings.TrimSpace(fields[0])
|
||||
if k == "path" {
|
||||
path = strings.TrimSpace(fields[1])
|
||||
} else if k == "url" {
|
||||
c.submoduleCache.Set(path, &SubModule{path, strings.TrimSpace(fields[1])})
|
||||
ismodule = false
|
||||
}
|
||||
}
|
||||
c.submoduleCache, err = parseSubmoduleContent([]byte(content))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = scanner.Err(); err != nil {
|
||||
return nil, fmt.Errorf("GetSubModules scan: %w", err)
|
||||
return c.submoduleCache, nil
|
||||
}
|
||||
|
||||
func parseSubmoduleContent(bs []byte) (*ObjectCache, error) {
|
||||
cfg := config.NewModules()
|
||||
if err := cfg.Unmarshal(bs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
submoduleCache := newObjectCache()
|
||||
if len(cfg.Submodules) == 0 {
|
||||
return nil, fmt.Errorf("no submodules found")
|
||||
}
|
||||
for _, subModule := range cfg.Submodules {
|
||||
submoduleCache.Set(subModule.Path, subModule.URL)
|
||||
}
|
||||
|
||||
return c.submoduleCache, nil
|
||||
return submoduleCache, nil
|
||||
}
|
||||
|
||||
// GetSubModule get the sub module according entryname
|
||||
|
|
|
@ -369,3 +369,33 @@ func TestParseCommitRenames(t *testing.T) {
|
|||
assert.Equal(t, testcase.renames, renames)
|
||||
}
|
||||
}
|
||||
|
||||
func Test_parseSubmoduleContent(t *testing.T) {
|
||||
submoduleFiles := []struct {
|
||||
fileContent string
|
||||
expectedPath string
|
||||
expectedURL string
|
||||
}{
|
||||
{
|
||||
fileContent: `[submodule "jakarta-servlet"]
|
||||
url = ../../ALP-pool/jakarta-servlet
|
||||
path = jakarta-servlet`,
|
||||
expectedPath: "jakarta-servlet",
|
||||
expectedURL: "../../ALP-pool/jakarta-servlet",
|
||||
},
|
||||
{
|
||||
fileContent: `[submodule "jakarta-servlet"]
|
||||
path = jakarta-servlet
|
||||
url = ../../ALP-pool/jakarta-servlet`,
|
||||
expectedPath: "jakarta-servlet",
|
||||
expectedURL: "../../ALP-pool/jakarta-servlet",
|
||||
},
|
||||
}
|
||||
for _, kase := range submoduleFiles {
|
||||
submodule, err := parseSubmoduleContent([]byte(kase.fileContent))
|
||||
require.NoError(t, err)
|
||||
v, ok := submodule.Get(kase.expectedPath)
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, kase.expectedURL, v)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,8 +4,6 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -126,15 +124,12 @@ func TestPushCommits_AvatarLink(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
setting.GravatarSource = "https://secure.gravatar.com/avatar"
|
||||
setting.OfflineMode = true
|
||||
|
||||
assert.Equal(t,
|
||||
"/avatars/avatar2?size="+strconv.Itoa(28*setting.Avatar.RenderedSizeFactor),
|
||||
"/avatars/ab53a2911ddf9b4817ac01ddcd3d975f?size="+strconv.Itoa(28*setting.Avatar.RenderedSizeFactor),
|
||||
pushCommits.AvatarLink(db.DefaultContext, "user2@example.com"))
|
||||
|
||||
assert.Equal(t,
|
||||
fmt.Sprintf("https://secure.gravatar.com/avatar/%x?d=identicon&s=%d", md5.Sum([]byte("nonexistent@example.com")), 28*setting.Avatar.RenderedSizeFactor),
|
||||
"/assets/img/avatar_default.png",
|
||||
pushCommits.AvatarLink(db.DefaultContext, "nonexistent@example.com"))
|
||||
}
|
||||
|
||||
|
|
4
release-notes/6062.md
Normal file
4
release-notes/6062.md
Normal file
|
@ -0,0 +1,4 @@
|
|||
fix: [commit](https://codeberg.org/forgejo/forgejo/commit/32a91add34519ef7768ec907888ed837ad0dde2f) Fix GetInactiveUsers
|
||||
fix: [commit](https://codeberg.org/forgejo/forgejo/commit/64824290912b6300ede2b2f95ff77d55dde9859b) Fix submodule parsing
|
||||
fix: [commit](https://codeberg.org/forgejo/forgejo/commit/ddabba5f89c4b196daeeb2af17de9ec2cec14b63) allow the actions user to login via the jwt token
|
||||
feat: [commit](https://codeberg.org/forgejo/forgejo/commit/262c48409b1224e3f6dc63c8d1e04fef0e0cf2c0) Support HTTP POST requests to `/userinfo`, aligning to OpenID Core specification
|
|
@ -133,11 +133,6 @@ func DeleteBranch(ctx *context.APIContext) {
|
|||
|
||||
branchName := ctx.Params("*")
|
||||
|
||||
if ctx.Repo.Repository.IsEmpty {
|
||||
ctx.Error(http.StatusForbidden, "", "Git Repository is empty.")
|
||||
return
|
||||
}
|
||||
|
||||
// check whether branches of this repository has been synced
|
||||
totalNumOfBranches, err := db.Count[git_model.Branch](ctx, git_model.FindBranchOptions{
|
||||
RepoID: ctx.Repo.Repository.ID,
|
||||
|
|
|
@ -530,7 +530,7 @@ func registerRoutes(m *web.Route) {
|
|||
m.Post("/authorize", web.Bind(forms.AuthorizationForm{}), auth.AuthorizeOAuth)
|
||||
}, ignSignInAndCsrf, reqSignIn)
|
||||
|
||||
m.Methods("GET, OPTIONS", "/userinfo", optionsCorsHandler(), ignSignInAndCsrf, auth.InfoOAuth)
|
||||
m.Methods("GET, POST, OPTIONS", "/userinfo", optionsCorsHandler(), ignSignInAndCsrf, auth.InfoOAuth)
|
||||
m.Methods("POST, OPTIONS", "/access_token", optionsCorsHandler(), web.Bind(forms.AccessTokenForm{}), ignSignInAndCsrf, auth.AccessTokenOAuth)
|
||||
m.Methods("GET, OPTIONS", "/keys", optionsCorsHandler(), ignSignInAndCsrf, auth.OIDCKeys)
|
||||
m.Methods("POST, OPTIONS", "/introspect", optionsCorsHandler(), web.Bind(forms.IntrospectTokenForm{}), ignSignInAndCsrf, auth.IntrospectOAuth)
|
||||
|
|
|
@ -83,7 +83,12 @@ func ParseAuthorizationToken(req *http.Request) (int64, error) {
|
|||
return 0, fmt.Errorf("split token failed")
|
||||
}
|
||||
|
||||
token, err := jwt.ParseWithClaims(parts[1], &actionsClaims{}, func(t *jwt.Token) (any, error) {
|
||||
return TokenToTaskID(parts[1])
|
||||
}
|
||||
|
||||
// TokenToTaskID returns the TaskID associated with the provided JWT token
|
||||
func TokenToTaskID(token string) (int64, error) {
|
||||
parsedToken, err := jwt.ParseWithClaims(token, &actionsClaims{}, func(t *jwt.Token) (any, error) {
|
||||
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||
return nil, fmt.Errorf("unexpected signing method: %v", t.Header["alg"])
|
||||
}
|
||||
|
@ -93,8 +98,8 @@ func ParseAuthorizationToken(req *http.Request) (int64, error) {
|
|||
return 0, err
|
||||
}
|
||||
|
||||
c, ok := token.Claims.(*actionsClaims)
|
||||
if !token.Valid || !ok {
|
||||
c, ok := parsedToken.Claims.(*actionsClaims)
|
||||
if !parsedToken.Valid || !ok {
|
||||
return 0, fmt.Errorf("invalid token claim")
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/web/middleware"
|
||||
"code.gitea.io/gitea/services/actions"
|
||||
"code.gitea.io/gitea/services/auth/source/oauth2"
|
||||
)
|
||||
|
||||
|
@ -94,6 +95,18 @@ func CheckOAuthAccessToken(ctx context.Context, accessToken string) (int64, stri
|
|||
return grant.UserID, grantScopes
|
||||
}
|
||||
|
||||
// CheckTaskIsRunning verifies that the TaskID corresponds to a running task
|
||||
func CheckTaskIsRunning(ctx context.Context, taskID int64) bool {
|
||||
// Verify the task exists
|
||||
task, err := actions_model.GetTaskByID(ctx, taskID)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// Verify that it's running
|
||||
return task.Status == actions_model.StatusRunning
|
||||
}
|
||||
|
||||
// OAuth2 implements the Auth interface and authenticates requests
|
||||
// (API requests only) by looking for an OAuth token in query parameters or the
|
||||
// "Authorization" header.
|
||||
|
@ -137,8 +150,17 @@ func parseToken(req *http.Request) (string, bool) {
|
|||
func (o *OAuth2) userIDFromToken(ctx context.Context, tokenSHA string, store DataStore) int64 {
|
||||
// Let's see if token is valid.
|
||||
if strings.Contains(tokenSHA, ".") {
|
||||
uid, grantScopes := CheckOAuthAccessToken(ctx, tokenSHA)
|
||||
// First attempt to decode an actions JWT, returning the actions user
|
||||
if taskID, err := actions.TokenToTaskID(tokenSHA); err == nil {
|
||||
if CheckTaskIsRunning(ctx, taskID) {
|
||||
store.GetData()["IsActionsToken"] = true
|
||||
store.GetData()["ActionsTaskID"] = taskID
|
||||
return user_model.ActionsUserID
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, check if this is an OAuth access token
|
||||
uid, grantScopes := CheckOAuthAccessToken(ctx, tokenSHA)
|
||||
if uid != 0 {
|
||||
store.GetData()["IsApiToken"] = true
|
||||
if grantScopes != "" {
|
||||
|
|
55
services/auth/oauth2_test.go
Normal file
55
services/auth/oauth2_test.go
Normal file
|
@ -0,0 +1,55 @@
|
|||
// Copyright 2024 The Gitea Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/web/middleware"
|
||||
"code.gitea.io/gitea/services/actions"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestUserIDFromToken(t *testing.T) {
|
||||
require.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
t.Run("Actions JWT", func(t *testing.T) {
|
||||
const RunningTaskID = 47
|
||||
token, err := actions.CreateAuthorizationToken(RunningTaskID, 1, 2)
|
||||
require.NoError(t, err)
|
||||
|
||||
ds := make(middleware.ContextData)
|
||||
|
||||
o := OAuth2{}
|
||||
uid := o.userIDFromToken(context.Background(), token, ds)
|
||||
assert.Equal(t, int64(user_model.ActionsUserID), uid)
|
||||
assert.Equal(t, true, ds["IsActionsToken"])
|
||||
assert.Equal(t, ds["ActionsTaskID"], int64(RunningTaskID))
|
||||
})
|
||||
}
|
||||
|
||||
func TestCheckTaskIsRunning(t *testing.T) {
|
||||
require.NoError(t, unittest.PrepareTestDatabase())
|
||||
cases := map[string]struct {
|
||||
TaskID int64
|
||||
Expected bool
|
||||
}{
|
||||
"Running": {TaskID: 47, Expected: true},
|
||||
"Missing": {TaskID: 1, Expected: false},
|
||||
"Cancelled": {TaskID: 46, Expected: false},
|
||||
}
|
||||
|
||||
for name := range cases {
|
||||
c := cases[name]
|
||||
t.Run(name, func(t *testing.T) {
|
||||
actual := CheckTaskIsRunning(context.Background(), c.TaskID)
|
||||
assert.Equal(t, c.Expected, actual)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -413,14 +413,7 @@ func repoAssignment(ctx *Context, repo *repo_model.Repository) {
|
|||
}
|
||||
}
|
||||
|
||||
pushMirrors, _, err := repo_model.GetPushMirrorsByRepoID(ctx, repo.ID, db.ListOptions{})
|
||||
if err != nil {
|
||||
ctx.ServerError("GetPushMirrorsByRepoID", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Repo.Repository = repo
|
||||
ctx.Data["PushMirrors"] = pushMirrors
|
||||
ctx.Data["RepoName"] = ctx.Repo.Repository.Name
|
||||
ctx.Data["IsEmptyRepo"] = ctx.Repo.Repository.IsEmpty
|
||||
ctx.Data["DefaultWikiBranchName"] = setting.Repository.DefaultBranch
|
||||
|
|
|
@ -43,7 +43,7 @@ func TestRepository_ContributorsGraph(t *testing.T) {
|
|||
dataString, isData := mockCache.Get("key2").(string)
|
||||
assert.True(t, isData)
|
||||
// Verify that JSON is actually stored in the cache.
|
||||
assert.JSONEq(t, `{"ethantkoenig@gmail.com":{"name":"Ethan Koenig","login":"","avatar_link":"https://secure.gravatar.com/avatar/b42fb195faa8c61b8d88abfefe30e9e3?d=identicon","home_link":"","total_commits":1,"weeks":{"1511654400000":{"week":1511654400000,"additions":3,"deletions":0,"commits":1}}},"jimmy.praet@telenet.be":{"name":"Jimmy Praet","login":"","avatar_link":"https://secure.gravatar.com/avatar/93c49b7c89eb156971d11161c9b52795?d=identicon","home_link":"","total_commits":1,"weeks":{"1624752000000":{"week":1624752000000,"additions":2,"deletions":0,"commits":1}}},"jon@allspice.io":{"name":"Jon","login":"","avatar_link":"https://secure.gravatar.com/avatar/00388ce725e6886f3e07c3733007289b?d=identicon","home_link":"","total_commits":1,"weeks":{"1607817600000":{"week":1607817600000,"additions":10,"deletions":0,"commits":1}}},"total":{"name":"Total","login":"","avatar_link":"","home_link":"","total_commits":3,"weeks":{"1511654400000":{"week":1511654400000,"additions":3,"deletions":0,"commits":1},"1607817600000":{"week":1607817600000,"additions":10,"deletions":0,"commits":1},"1624752000000":{"week":1624752000000,"additions":2,"deletions":0,"commits":1}}}}`, dataString)
|
||||
assert.JSONEq(t, `{"ethantkoenig@gmail.com":{"name":"Ethan Koenig","login":"","avatar_link":"/assets/img/avatar_default.png","home_link":"","total_commits":1,"weeks":{"1511654400000":{"week":1511654400000,"additions":3,"deletions":0,"commits":1}}},"jimmy.praet@telenet.be":{"name":"Jimmy Praet","login":"","avatar_link":"/assets/img/avatar_default.png","home_link":"","total_commits":1,"weeks":{"1624752000000":{"week":1624752000000,"additions":2,"deletions":0,"commits":1}}},"jon@allspice.io":{"name":"Jon","login":"","avatar_link":"/assets/img/avatar_default.png","home_link":"","total_commits":1,"weeks":{"1607817600000":{"week":1607817600000,"additions":10,"deletions":0,"commits":1}}},"total":{"name":"Total","login":"","avatar_link":"","home_link":"","total_commits":3,"weeks":{"1511654400000":{"week":1511654400000,"additions":3,"deletions":0,"commits":1},"1607817600000":{"week":1607817600000,"additions":10,"deletions":0,"commits":1},"1624752000000":{"week":1624752000000,"additions":2,"deletions":0,"commits":1}}}}`, dataString)
|
||||
|
||||
var data map[string]*ContributorData
|
||||
require.NoError(t, json.Unmarshal([]byte(dataString), &data))
|
||||
|
@ -62,7 +62,7 @@ func TestRepository_ContributorsGraph(t *testing.T) {
|
|||
|
||||
assert.EqualValues(t, &ContributorData{
|
||||
Name: "Ethan Koenig",
|
||||
AvatarLink: "https://secure.gravatar.com/avatar/b42fb195faa8c61b8d88abfefe30e9e3?d=identicon",
|
||||
AvatarLink: "/assets/img/avatar_default.png",
|
||||
TotalCommits: 1,
|
||||
Weeks: map[int64]*WeekData{
|
||||
1511654400000: {
|
||||
|
|
|
@ -5,6 +5,7 @@ package integration
|
|||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
@ -42,7 +43,7 @@ func TestOpenGraphProperties(t *testing.T) {
|
|||
"og:title": "User Thirty",
|
||||
"og:url": setting.AppURL + "user30",
|
||||
"og:type": "profile",
|
||||
"og:image": "https://secure.gravatar.com/avatar/eae1f44b34ff27284cb0792c7601c89c?d=identicon",
|
||||
"og:image": "http://localhost:3003/assets/img/avatar_default.png",
|
||||
"og:site_name": siteName,
|
||||
},
|
||||
},
|
||||
|
@ -54,7 +55,7 @@ func TestOpenGraphProperties(t *testing.T) {
|
|||
"og:url": setting.AppURL + "the_34-user.with.all.allowedChars",
|
||||
"og:description": "some [commonmark](https://commonmark.org/)!",
|
||||
"og:type": "profile",
|
||||
"og:image": setting.AppURL + "avatars/avatar34",
|
||||
"og:image": "http://localhost:3003/assets/img/avatar_default.png",
|
||||
"og:site_name": siteName,
|
||||
},
|
||||
},
|
||||
|
@ -66,7 +67,7 @@ func TestOpenGraphProperties(t *testing.T) {
|
|||
"og:url": setting.AppURL + "user2/repo1/issues/1",
|
||||
"og:description": "content for the first issue",
|
||||
"og:type": "object",
|
||||
"og:image": "https://secure.gravatar.com/avatar/ab53a2911ddf9b4817ac01ddcd3d975f?d=identicon",
|
||||
"og:image": "http://localhost:3003/avatars/ab53a2911ddf9b4817ac01ddcd3d975f",
|
||||
"og:site_name": siteName,
|
||||
},
|
||||
},
|
||||
|
@ -78,7 +79,7 @@ func TestOpenGraphProperties(t *testing.T) {
|
|||
"og:url": setting.AppURL + "user2/repo1/pulls/2",
|
||||
"og:description": "content for the second issue",
|
||||
"og:type": "object",
|
||||
"og:image": "https://secure.gravatar.com/avatar/ab53a2911ddf9b4817ac01ddcd3d975f?d=identicon",
|
||||
"og:image": "http://localhost:3003/avatars/ab53a2911ddf9b4817ac01ddcd3d975f",
|
||||
"og:site_name": siteName,
|
||||
},
|
||||
},
|
||||
|
@ -89,7 +90,7 @@ func TestOpenGraphProperties(t *testing.T) {
|
|||
"og:title": "repo49/test/test.txt at master",
|
||||
"og:url": setting.AppURL + "/user27/repo49/src/branch/master/test/test.txt",
|
||||
"og:type": "object",
|
||||
"og:image": "https://secure.gravatar.com/avatar/7095710e927665f1bdd1ced94152f232?d=identicon",
|
||||
"og:image": "http://localhost:3003/assets/img/avatar_default.png",
|
||||
"og:site_name": siteName,
|
||||
},
|
||||
},
|
||||
|
@ -100,7 +101,7 @@ func TestOpenGraphProperties(t *testing.T) {
|
|||
"og:title": "Page With Spaced Name",
|
||||
"og:url": setting.AppURL + "/user2/repo1/wiki/Page-With-Spaced-Name",
|
||||
"og:type": "object",
|
||||
"og:image": "https://secure.gravatar.com/avatar/ab53a2911ddf9b4817ac01ddcd3d975f?d=identicon",
|
||||
"og:image": "http://localhost:3003/avatars/ab53a2911ddf9b4817ac01ddcd3d975f",
|
||||
"og:site_name": siteName,
|
||||
},
|
||||
},
|
||||
|
@ -111,7 +112,7 @@ func TestOpenGraphProperties(t *testing.T) {
|
|||
"og:title": "repo1",
|
||||
"og:url": setting.AppURL + "user2/repo1",
|
||||
"og:type": "object",
|
||||
"og:image": "https://secure.gravatar.com/avatar/ab53a2911ddf9b4817ac01ddcd3d975f?d=identicon",
|
||||
"og:image": "http://localhost:3003/avatars/ab53a2911ddf9b4817ac01ddcd3d975f",
|
||||
"og:site_name": siteName,
|
||||
},
|
||||
},
|
||||
|
@ -123,7 +124,7 @@ func TestOpenGraphProperties(t *testing.T) {
|
|||
"og:url": setting.AppURL + "user27/repo49",
|
||||
"og:description": "A wonderful repository with more than just a README.md",
|
||||
"og:type": "object",
|
||||
"og:image": "https://secure.gravatar.com/avatar/7095710e927665f1bdd1ced94152f232?d=identicon",
|
||||
"og:image": "http://localhost:3003/assets/img/avatar_default.png",
|
||||
"og:site_name": siteName,
|
||||
},
|
||||
},
|
||||
|
@ -141,6 +142,10 @@ func TestOpenGraphProperties(t *testing.T) {
|
|||
assert.True(t, foundProp)
|
||||
content, foundContent := selection.Attr("content")
|
||||
assert.True(t, foundContent, "opengraph meta tag without a content property")
|
||||
if prop == "og:image" {
|
||||
content = strings.ReplaceAll(content, "http://localhost:3001", "http://localhost:3003")
|
||||
content = strings.ReplaceAll(content, "http://localhost:3002", "http://localhost:3003")
|
||||
}
|
||||
foundProps[prop] = content
|
||||
})
|
||||
|
||||
|
|
Loading…
Reference in a new issue