Skip to content

Commit 9defddb

Browse files
lunny6543wxiaoguang
authored
Move more model into models/user (#17826)
* Move more model into models/user * Remove unnecessary comment Co-authored-by: 6543 <6543@obermui.de> Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
1 parent b1df890 commit 9defddb

23 files changed

+547
-603
lines changed

models/error.go

-40
Original file line numberDiff line numberDiff line change
@@ -1624,46 +1624,6 @@ func (err ErrUploadNotExist) Error() string {
16241624
return fmt.Sprintf("attachment does not exist [id: %d, uuid: %s]", err.ID, err.UUID)
16251625
}
16261626

1627-
// ___________ __ .__ .____ .__ ____ ___
1628-
// \_ _____/__ ____/ |_ ___________ ____ _____ | | | | ____ ____ |__| ____ | | \______ ___________
1629-
// | __)_\ \/ /\ __\/ __ \_ __ \/ \\__ \ | | | | / _ \ / ___\| |/ \ | | / ___// __ \_ __ \
1630-
// | \> < | | \ ___/| | \/ | \/ __ \| |__ | |__( <_> ) /_/ > | | \ | | /\___ \\ ___/| | \/
1631-
// /_______ /__/\_ \ |__| \___ >__| |___| (____ /____/ |_______ \____/\___ /|__|___| / |______//____ >\___ >__|
1632-
// \/ \/ \/ \/ \/ \/ /_____/ \/ \/ \/
1633-
1634-
// ErrExternalLoginUserAlreadyExist represents a "ExternalLoginUserAlreadyExist" kind of error.
1635-
type ErrExternalLoginUserAlreadyExist struct {
1636-
ExternalID string
1637-
UserID int64
1638-
LoginSourceID int64
1639-
}
1640-
1641-
// IsErrExternalLoginUserAlreadyExist checks if an error is a ExternalLoginUserAlreadyExist.
1642-
func IsErrExternalLoginUserAlreadyExist(err error) bool {
1643-
_, ok := err.(ErrExternalLoginUserAlreadyExist)
1644-
return ok
1645-
}
1646-
1647-
func (err ErrExternalLoginUserAlreadyExist) Error() string {
1648-
return fmt.Sprintf("external login user already exists [externalID: %s, userID: %d, loginSourceID: %d]", err.ExternalID, err.UserID, err.LoginSourceID)
1649-
}
1650-
1651-
// ErrExternalLoginUserNotExist represents a "ExternalLoginUserNotExist" kind of error.
1652-
type ErrExternalLoginUserNotExist struct {
1653-
UserID int64
1654-
LoginSourceID int64
1655-
}
1656-
1657-
// IsErrExternalLoginUserNotExist checks if an error is a ExternalLoginUserNotExist.
1658-
func IsErrExternalLoginUserNotExist(err error) bool {
1659-
_, ok := err.(ErrExternalLoginUserNotExist)
1660-
return ok
1661-
}
1662-
1663-
func (err ErrExternalLoginUserNotExist) Error() string {
1664-
return fmt.Sprintf("external login user link does not exists [userID: %d, loginSourceID: %d]", err.UserID, err.LoginSourceID)
1665-
}
1666-
16671627
// .___ ________ .___ .__
16681628
// | | ______ ________ __ ____ \______ \ ____ ______ ____ ____ __| _/____ ____ ____ |__| ____ ______
16691629
// | |/ ___// ___/ | \_/ __ \ | | \_/ __ \\____ \_/ __ \ / \ / __ |/ __ \ / \_/ ___\| |/ __ \ / ___/

models/migrate.go

+20
Original file line numberDiff line numberDiff line change
@@ -245,3 +245,23 @@ func UpdateReviewsMigrationsByType(tp structs.GitServiceType, originalAuthorID s
245245
})
246246
return err
247247
}
248+
249+
// UpdateMigrationsByType updates all migrated repositories' posterid from gitServiceType to replace originalAuthorID to posterID
250+
func UpdateMigrationsByType(tp structs.GitServiceType, externalUserID string, userID int64) error {
251+
if err := UpdateIssuesMigrationsByType(tp, externalUserID, userID); err != nil {
252+
return err
253+
}
254+
255+
if err := UpdateCommentsMigrationsByType(tp, externalUserID, userID); err != nil {
256+
return err
257+
}
258+
259+
if err := UpdateReleasesMigrationsByType(tp, externalUserID, userID); err != nil {
260+
return err
261+
}
262+
263+
if err := UpdateReactionsMigrationsByType(tp, externalUserID, userID); err != nil {
264+
return err
265+
}
266+
return UpdateReviewsMigrationsByType(tp, externalUserID, userID)
267+
}

models/org.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ func (org *Organization) LoadTeams() ([]*Team, error) {
8181
}
8282

8383
// GetMembers returns all members of organization.
84-
func (org *Organization) GetMembers() (UserList, map[int64]bool, error) {
84+
func (org *Organization) GetMembers() (user_model.UserList, map[int64]bool, error) {
8585
return FindOrgMembers(&FindOrgMembersOpts{
8686
OrgID: org.ID,
8787
})
@@ -149,7 +149,7 @@ func CountOrgMembers(opts *FindOrgMembersOpts) (int64, error) {
149149
}
150150

151151
// FindOrgMembers loads organization members according conditions
152-
func FindOrgMembers(opts *FindOrgMembersOpts) (UserList, map[int64]bool, error) {
152+
func FindOrgMembers(opts *FindOrgMembersOpts) (user_model.UserList, map[int64]bool, error) {
153153
ous, err := GetOrgUsersByOrgID(opts)
154154
if err != nil {
155155
return nil, nil, err
@@ -162,7 +162,7 @@ func FindOrgMembers(opts *FindOrgMembersOpts) (UserList, map[int64]bool, error)
162162
idsIsPublic[ou.UID] = ou.IsPublic
163163
}
164164

165-
users, err := GetUsersByIDs(ids)
165+
users, err := user_model.GetUsersByIDs(ids)
166166
if err != nil {
167167
return nil, nil, err
168168
}

models/user.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,7 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) {
260260
}
261261

262262
// ***** START: ExternalLoginUser *****
263-
if err = removeAllAccountLinks(e, u); err != nil {
263+
if err = user_model.RemoveAllAccountLinks(ctx, u); err != nil {
264264
return fmt.Errorf("ExternalLoginUser: %v", err)
265265
}
266266
// ***** END: ExternalLoginUser *****

models/user/email_address.go

+246
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@ import (
1313
"strings"
1414

1515
"code.gitea.io/gitea/models/db"
16+
"code.gitea.io/gitea/modules/base"
1617
"code.gitea.io/gitea/modules/log"
1718
"code.gitea.io/gitea/modules/setting"
19+
"code.gitea.io/gitea/modules/util"
1820

1921
"xorm.io/builder"
2022
)
@@ -275,3 +277,247 @@ func DeleteInactiveEmailAddresses(ctx context.Context) error {
275277
Delete(new(EmailAddress))
276278
return err
277279
}
280+
281+
// ActivateEmail activates the email address to given user.
282+
func ActivateEmail(email *EmailAddress) error {
283+
ctx, committer, err := db.TxContext()
284+
if err != nil {
285+
return err
286+
}
287+
defer committer.Close()
288+
if err := updateActivation(db.GetEngine(ctx), email, true); err != nil {
289+
return err
290+
}
291+
return committer.Commit()
292+
}
293+
294+
func updateActivation(e db.Engine, email *EmailAddress, activate bool) error {
295+
user, err := GetUserByIDEngine(e, email.UID)
296+
if err != nil {
297+
return err
298+
}
299+
if user.Rands, err = GetUserSalt(); err != nil {
300+
return err
301+
}
302+
email.IsActivated = activate
303+
if _, err := e.ID(email.ID).Cols("is_activated").Update(email); err != nil {
304+
return err
305+
}
306+
return UpdateUserColsEngine(e, user, "rands")
307+
}
308+
309+
// MakeEmailPrimary sets primary email address of given user.
310+
func MakeEmailPrimary(email *EmailAddress) error {
311+
has, err := db.GetEngine(db.DefaultContext).Get(email)
312+
if err != nil {
313+
return err
314+
} else if !has {
315+
return ErrEmailAddressNotExist{Email: email.Email}
316+
}
317+
318+
if !email.IsActivated {
319+
return ErrEmailNotActivated
320+
}
321+
322+
user := &User{}
323+
has, err = db.GetEngine(db.DefaultContext).ID(email.UID).Get(user)
324+
if err != nil {
325+
return err
326+
} else if !has {
327+
return ErrUserNotExist{
328+
UID: email.UID,
329+
Name: "",
330+
KeyID: 0,
331+
}
332+
}
333+
334+
ctx, committer, err := db.TxContext()
335+
if err != nil {
336+
return err
337+
}
338+
defer committer.Close()
339+
sess := db.GetEngine(ctx)
340+
341+
// 1. Update user table
342+
user.Email = email.Email
343+
if _, err = sess.ID(user.ID).Cols("email").Update(user); err != nil {
344+
return err
345+
}
346+
347+
// 2. Update old primary email
348+
if _, err = sess.Where("uid=? AND is_primary=?", email.UID, true).Cols("is_primary").Update(&EmailAddress{
349+
IsPrimary: false,
350+
}); err != nil {
351+
return err
352+
}
353+
354+
// 3. update new primary email
355+
email.IsPrimary = true
356+
if _, err = sess.ID(email.ID).Cols("is_primary").Update(email); err != nil {
357+
return err
358+
}
359+
360+
return committer.Commit()
361+
}
362+
363+
// VerifyActiveEmailCode verifies active email code when active account
364+
func VerifyActiveEmailCode(code, email string) *EmailAddress {
365+
minutes := setting.Service.ActiveCodeLives
366+
367+
if user := GetVerifyUser(code); user != nil {
368+
// time limit code
369+
prefix := code[:base.TimeLimitCodeLength]
370+
data := fmt.Sprintf("%d%s%s%s%s", user.ID, email, user.LowerName, user.Passwd, user.Rands)
371+
372+
if base.VerifyTimeLimitCode(data, minutes, prefix) {
373+
emailAddress := &EmailAddress{UID: user.ID, Email: email}
374+
if has, _ := db.GetEngine(db.DefaultContext).Get(emailAddress); has {
375+
return emailAddress
376+
}
377+
}
378+
}
379+
return nil
380+
}
381+
382+
// SearchEmailOrderBy is used to sort the results from SearchEmails()
383+
type SearchEmailOrderBy string
384+
385+
func (s SearchEmailOrderBy) String() string {
386+
return string(s)
387+
}
388+
389+
// Strings for sorting result
390+
const (
391+
SearchEmailOrderByEmail SearchEmailOrderBy = "email_address.lower_email ASC, email_address.is_primary DESC, email_address.id ASC"
392+
SearchEmailOrderByEmailReverse SearchEmailOrderBy = "email_address.lower_email DESC, email_address.is_primary ASC, email_address.id DESC"
393+
SearchEmailOrderByName SearchEmailOrderBy = "`user`.lower_name ASC, email_address.is_primary DESC, email_address.id ASC"
394+
SearchEmailOrderByNameReverse SearchEmailOrderBy = "`user`.lower_name DESC, email_address.is_primary ASC, email_address.id DESC"
395+
)
396+
397+
// SearchEmailOptions are options to search e-mail addresses for the admin panel
398+
type SearchEmailOptions struct {
399+
db.ListOptions
400+
Keyword string
401+
SortType SearchEmailOrderBy
402+
IsPrimary util.OptionalBool
403+
IsActivated util.OptionalBool
404+
}
405+
406+
// SearchEmailResult is an e-mail address found in the user or email_address table
407+
type SearchEmailResult struct {
408+
UID int64
409+
Email string
410+
IsActivated bool
411+
IsPrimary bool
412+
// From User
413+
Name string
414+
FullName string
415+
}
416+
417+
// SearchEmails takes options i.e. keyword and part of email name to search,
418+
// it returns results in given range and number of total results.
419+
func SearchEmails(opts *SearchEmailOptions) ([]*SearchEmailResult, int64, error) {
420+
var cond builder.Cond = builder.Eq{"`user`.`type`": UserTypeIndividual}
421+
if len(opts.Keyword) > 0 {
422+
likeStr := "%" + strings.ToLower(opts.Keyword) + "%"
423+
cond = cond.And(builder.Or(
424+
builder.Like{"lower(`user`.full_name)", likeStr},
425+
builder.Like{"`user`.lower_name", likeStr},
426+
builder.Like{"email_address.lower_email", likeStr},
427+
))
428+
}
429+
430+
switch {
431+
case opts.IsPrimary.IsTrue():
432+
cond = cond.And(builder.Eq{"email_address.is_primary": true})
433+
case opts.IsPrimary.IsFalse():
434+
cond = cond.And(builder.Eq{"email_address.is_primary": false})
435+
}
436+
437+
switch {
438+
case opts.IsActivated.IsTrue():
439+
cond = cond.And(builder.Eq{"email_address.is_activated": true})
440+
case opts.IsActivated.IsFalse():
441+
cond = cond.And(builder.Eq{"email_address.is_activated": false})
442+
}
443+
444+
count, err := db.GetEngine(db.DefaultContext).Join("INNER", "`user`", "`user`.ID = email_address.uid").
445+
Where(cond).Count(new(EmailAddress))
446+
if err != nil {
447+
return nil, 0, fmt.Errorf("Count: %v", err)
448+
}
449+
450+
orderby := opts.SortType.String()
451+
if orderby == "" {
452+
orderby = SearchEmailOrderByEmail.String()
453+
}
454+
455+
opts.SetDefaultValues()
456+
457+
emails := make([]*SearchEmailResult, 0, opts.PageSize)
458+
err = db.GetEngine(db.DefaultContext).Table("email_address").
459+
Select("email_address.*, `user`.name, `user`.full_name").
460+
Join("INNER", "`user`", "`user`.ID = email_address.uid").
461+
Where(cond).
462+
OrderBy(orderby).
463+
Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).
464+
Find(&emails)
465+
466+
return emails, count, err
467+
}
468+
469+
// ActivateUserEmail will change the activated state of an email address,
470+
// either primary or secondary (all in the email_address table)
471+
func ActivateUserEmail(userID int64, email string, activate bool) (err error) {
472+
ctx, committer, err := db.TxContext()
473+
if err != nil {
474+
return err
475+
}
476+
defer committer.Close()
477+
sess := db.GetEngine(ctx)
478+
479+
// Activate/deactivate a user's secondary email address
480+
// First check if there's another user active with the same address
481+
addr := EmailAddress{UID: userID, LowerEmail: strings.ToLower(email)}
482+
if has, err := sess.Get(&addr); err != nil {
483+
return err
484+
} else if !has {
485+
return fmt.Errorf("no such email: %d (%s)", userID, email)
486+
}
487+
if addr.IsActivated == activate {
488+
// Already in the desired state; no action
489+
return nil
490+
}
491+
if activate {
492+
if used, err := IsEmailActive(ctx, email, addr.ID); err != nil {
493+
return fmt.Errorf("unable to check isEmailActive() for %s: %v", email, err)
494+
} else if used {
495+
return ErrEmailAlreadyUsed{Email: email}
496+
}
497+
}
498+
if err = updateActivation(sess, &addr, activate); err != nil {
499+
return fmt.Errorf("unable to updateActivation() for %d:%s: %w", addr.ID, addr.Email, err)
500+
}
501+
502+
// Activate/deactivate a user's primary email address and account
503+
if addr.IsPrimary {
504+
user := User{ID: userID, Email: email}
505+
if has, err := sess.Get(&user); err != nil {
506+
return err
507+
} else if !has {
508+
return fmt.Errorf("no user with ID: %d and Email: %s", userID, email)
509+
}
510+
// The user's activation state should be synchronized with the primary email
511+
if user.IsActive != activate {
512+
user.IsActive = activate
513+
if user.Rands, err = GetUserSalt(); err != nil {
514+
return fmt.Errorf("unable to generate salt: %v", err)
515+
}
516+
if err = UpdateUserColsEngine(sess, &user, "is_active", "rands"); err != nil {
517+
return fmt.Errorf("unable to updateUserCols() for user ID: %d: %v", userID, err)
518+
}
519+
}
520+
}
521+
522+
return committer.Commit()
523+
}

0 commit comments

Comments
 (0)