Fix GetUsersByEmails (#34643)

pull/34605/head
wxiaoguang 2025-06-08 02:30:36 +08:00 committed by GitHub
parent 7fa5a88831
commit cc942e2a86
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 47 additions and 21 deletions

View File

@ -81,7 +81,7 @@
- -
id: 11 id: 11
uid: 4 uid: 4
email: user4@example.com email: User4@Example.Com
lower_email: user4@example.com lower_email: user4@example.com
is_activated: true is_activated: true
is_primary: true is_primary: true

View File

@ -1151,8 +1151,8 @@ func ValidateCommitsWithEmails(ctx context.Context, oldCommits []*git.Commit) ([
} }
for _, c := range oldCommits { for _, c := range oldCommits {
user, ok := emailUserMap[c.Author.Email] user := emailUserMap.GetByEmail(c.Author.Email) // FIXME: why ValidateCommitsWithEmails uses "Author", but ParseCommitsWithSignature uses "Committer"?
if !ok { if user == nil {
user = &User{ user = &User{
Name: c.Author.Name, Name: c.Author.Name,
Email: c.Author.Email, Email: c.Author.Email,
@ -1166,7 +1166,15 @@ func ValidateCommitsWithEmails(ctx context.Context, oldCommits []*git.Commit) ([
return newCommits, nil return newCommits, nil
} }
func GetUsersByEmails(ctx context.Context, emails []string) (map[string]*User, error) { type EmailUserMap struct {
m map[string]*User
}
func (eum *EmailUserMap) GetByEmail(email string) *User {
return eum.m[strings.ToLower(email)]
}
func GetUsersByEmails(ctx context.Context, emails []string) (*EmailUserMap, error) {
if len(emails) == 0 { if len(emails) == 0 {
return nil, nil return nil, nil
} }
@ -1176,7 +1184,7 @@ func GetUsersByEmails(ctx context.Context, emails []string) (map[string]*User, e
for _, email := range emails { for _, email := range emails {
if strings.HasSuffix(email, "@"+setting.Service.NoReplyAddress) { if strings.HasSuffix(email, "@"+setting.Service.NoReplyAddress) {
username := strings.TrimSuffix(email, "@"+setting.Service.NoReplyAddress) username := strings.TrimSuffix(email, "@"+setting.Service.NoReplyAddress)
needCheckUserNames.Add(username) needCheckUserNames.Add(strings.ToLower(username))
} else { } else {
needCheckEmails.Add(strings.ToLower(email)) needCheckEmails.Add(strings.ToLower(email))
} }
@ -1203,8 +1211,7 @@ func GetUsersByEmails(ctx context.Context, emails []string) (map[string]*User, e
for _, email := range emailAddresses { for _, email := range emailAddresses {
user := users[email.UID] user := users[email.UID]
if user != nil { if user != nil {
results[user.Email] = user results[email.LowerEmail] = user
results[user.GetPlaceholderEmail()] = user
} }
} }
} }
@ -1214,10 +1221,9 @@ func GetUsersByEmails(ctx context.Context, emails []string) (map[string]*User, e
return nil, err return nil, err
} }
for _, user := range users { for _, user := range users {
results[user.Email] = user results[strings.ToLower(user.GetPlaceholderEmail())] = user
results[user.GetPlaceholderEmail()] = user
} }
return results, nil return &EmailUserMap{results}, nil
} }
// GetUserByEmail returns the user object by given e-mail if exists. // GetUserByEmail returns the user object by given e-mail if exists.

View File

@ -58,13 +58,33 @@ func TestUserEmails(t *testing.T) {
assert.ElementsMatch(t, []string{"user8@example.com"}, user_model.GetUserEmailsByNames(db.DefaultContext, []string{"user8", "org7"})) assert.ElementsMatch(t, []string{"user8@example.com"}, user_model.GetUserEmailsByNames(db.DefaultContext, []string{"user8", "org7"}))
}) })
t.Run("GetUsersByEmails", func(t *testing.T) { t.Run("GetUsersByEmails", func(t *testing.T) {
m, err := user_model.GetUsersByEmails(db.DefaultContext, []string{"user1@example.com", "user2@" + setting.Service.NoReplyAddress}) defer test.MockVariableValue(&setting.Service.NoReplyAddress, "NoReply.gitea.internal")()
require.NoError(t, err) testGetUserByEmail := func(t *testing.T, email string, uid int64) {
require.Len(t, m, 4) m, err := user_model.GetUsersByEmails(db.DefaultContext, []string{email})
assert.EqualValues(t, 1, m["user1@example.com"].ID) require.NoError(t, err)
assert.EqualValues(t, 1, m["user1@"+setting.Service.NoReplyAddress].ID) user := m.GetByEmail(email)
assert.EqualValues(t, 2, m["user2@example.com"].ID) if uid == 0 {
assert.EqualValues(t, 2, m["user2@"+setting.Service.NoReplyAddress].ID) require.Nil(t, user)
return
}
require.NotNil(t, user)
assert.Equal(t, uid, user.ID)
}
cases := []struct {
Email string
UID int64
}{
{"UseR1@example.com", 1},
{"user1-2@example.COM", 1},
{"USER2@" + setting.Service.NoReplyAddress, 2},
{"user4@example.com", 4},
{"no-such", 0},
}
for _, c := range cases {
t.Run(c.Email, func(t *testing.T) {
testGetUserByEmail(t, c.Email, c.UID)
})
}
}) })
} }

View File

@ -34,9 +34,9 @@ func ParseCommitsWithSignature(ctx context.Context, repo *repo_model.Repository,
} }
for _, c := range oldCommits { for _, c := range oldCommits {
committer, ok := emailUsers[c.Committer.Email] committerUser := emailUsers.GetByEmail(c.Committer.Email) // FIXME: why ValidateCommitsWithEmails uses "Author", but ParseCommitsWithSignature uses "Committer"?
if !ok && c.Committer != nil { if committerUser == nil {
committer = &user_model.User{ committerUser = &user_model.User{
Name: c.Committer.Name, Name: c.Committer.Name,
Email: c.Committer.Email, Email: c.Committer.Email,
} }
@ -44,7 +44,7 @@ func ParseCommitsWithSignature(ctx context.Context, repo *repo_model.Repository,
signCommit := &asymkey_model.SignCommit{ signCommit := &asymkey_model.SignCommit{
UserCommit: c, UserCommit: c,
Verification: asymkey_service.ParseCommitWithSignatureCommitter(ctx, c.Commit, committer), Verification: asymkey_service.ParseCommitWithSignatureCommitter(ctx, c.Commit, committerUser),
} }
isOwnerMemberCollaborator := func(user *user_model.User) (bool, error) { isOwnerMemberCollaborator := func(user *user_model.User) (bool, error) {