aboutsummaryrefslogtreecommitdiffstats
path: root/models
diff options
context:
space:
mode:
authorLunny Xiao <xiaolunwen@gmail.com>2021-11-11 15:03:30 +0800
committerGitHub <noreply@github.com>2021-11-11 15:03:30 +0800
commit90eb9fb889e5d3a5845576dbc63e3792f3da33f2 (patch)
tree4107df9dd446fe9a93e49cba1e59d0f721e70351 /models
parent492e1c2fbd1b646f4428207942a9f89b56f7b6a9 (diff)
downloadgitea-90eb9fb889e5d3a5845576dbc63e3792f3da33f2.tar.gz
gitea-90eb9fb889e5d3a5845576dbc63e3792f3da33f2.zip
Move EmailAddress & UserRedirect into models/user/ (#17607)
* Move EmailAddress into models/user/ * Fix test * rename user_mail to user_email * Fix test * Move UserRedirect into models/user/ * Fix lint & test * Fix lint * Fix lint * remove nolint comment * Fix lint
Diffstat (limited to 'models')
-rw-r--r--models/error.go75
-rw-r--r--models/gpg_key.go11
-rw-r--r--models/gpg_key_commit_verification.go3
-rw-r--r--models/org.go26
-rw-r--r--models/ssh_key_principals.go3
-rw-r--r--models/user.go54
-rw-r--r--models/user/email_address.go269
-rw-r--r--models/user/email_address_test.go131
-rw-r--r--models/user/main_test.go19
-rw-r--r--models/user/redirect.go79
-rw-r--r--models/user/redirect_test.go23
-rw-r--r--models/user_email.go (renamed from models/user_mail.go)232
-rw-r--r--models/user_email_test.go (renamed from models/user_mail_test.go)139
-rw-r--r--models/user_redirect.go60
-rw-r--r--models/user_redirect_test.go70
-rw-r--r--models/user_test.go50
16 files changed, 652 insertions, 592 deletions
diff --git a/models/error.go b/models/error.go
index b365a67b73..db0fce0ce1 100644
--- a/models/error.go
+++ b/models/error.go
@@ -123,21 +123,6 @@ func (err ErrUserNotExist) Error() string {
return fmt.Sprintf("user does not exist [uid: %d, name: %s, keyid: %d]", err.UID, err.Name, err.KeyID)
}
-// ErrUserRedirectNotExist represents a "UserRedirectNotExist" kind of error.
-type ErrUserRedirectNotExist struct {
- Name string
-}
-
-// IsErrUserRedirectNotExist check if an error is an ErrUserRedirectNotExist.
-func IsErrUserRedirectNotExist(err error) bool {
- _, ok := err.(ErrUserRedirectNotExist)
- return ok
-}
-
-func (err ErrUserRedirectNotExist) Error() string {
- return fmt.Sprintf("user redirect does not exist [name: %s]", err.Name)
-}
-
// ErrUserProhibitLogin represents a "ErrUserProhibitLogin" kind of error.
type ErrUserProhibitLogin struct {
UID int64
@@ -170,66 +155,6 @@ func (err ErrUserInactive) Error() string {
return fmt.Sprintf("user is inactive [uid: %d, name: %s]", err.UID, err.Name)
}
-// ErrEmailAlreadyUsed represents a "EmailAlreadyUsed" kind of error.
-type ErrEmailAlreadyUsed struct {
- Email string
-}
-
-// IsErrEmailAlreadyUsed checks if an error is a ErrEmailAlreadyUsed.
-func IsErrEmailAlreadyUsed(err error) bool {
- _, ok := err.(ErrEmailAlreadyUsed)
- return ok
-}
-
-func (err ErrEmailAlreadyUsed) Error() string {
- return fmt.Sprintf("e-mail already in use [email: %s]", err.Email)
-}
-
-// ErrEmailInvalid represents an error where the email address does not comply with RFC 5322
-type ErrEmailInvalid struct {
- Email string
-}
-
-// IsErrEmailInvalid checks if an error is an ErrEmailInvalid
-func IsErrEmailInvalid(err error) bool {
- _, ok := err.(ErrEmailInvalid)
- return ok
-}
-
-func (err ErrEmailInvalid) Error() string {
- return fmt.Sprintf("e-mail invalid [email: %s]", err.Email)
-}
-
-// ErrEmailAddressNotExist email address not exist
-type ErrEmailAddressNotExist struct {
- Email string
-}
-
-// IsErrEmailAddressNotExist checks if an error is an ErrEmailAddressNotExist
-func IsErrEmailAddressNotExist(err error) bool {
- _, ok := err.(ErrEmailAddressNotExist)
- return ok
-}
-
-func (err ErrEmailAddressNotExist) Error() string {
- return fmt.Sprintf("Email address does not exist [email: %s]", err.Email)
-}
-
-// ErrPrimaryEmailCannotDelete primary email address cannot be deleted
-type ErrPrimaryEmailCannotDelete struct {
- Email string
-}
-
-// IsErrPrimaryEmailCannotDelete checks if an error is an ErrPrimaryEmailCannotDelete
-func IsErrPrimaryEmailCannotDelete(err error) bool {
- _, ok := err.(ErrPrimaryEmailCannotDelete)
- return ok
-}
-
-func (err ErrPrimaryEmailCannotDelete) Error() string {
- return fmt.Sprintf("Primary email address cannot be deleted [email: %s]", err.Email)
-}
-
// ErrOpenIDAlreadyUsed represents a "OpenIDAlreadyUsed" kind of error.
type ErrOpenIDAlreadyUsed struct {
OpenID string
diff --git a/models/gpg_key.go b/models/gpg_key.go
index a62ed61966..357dc2b964 100644
--- a/models/gpg_key.go
+++ b/models/gpg_key.go
@@ -10,6 +10,7 @@ import (
"time"
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil"
@@ -36,7 +37,7 @@ type GPGKey struct {
ExpiredUnix timeutil.TimeStamp
AddedUnix timeutil.TimeStamp
SubsKey []*GPGKey `xorm:"-"`
- Emails []*EmailAddress
+ Emails []*user_model.EmailAddress
Verified bool `xorm:"NOT NULL DEFAULT false"`
CanSign bool
CanEncryptComms bool
@@ -148,12 +149,12 @@ func parseGPGKey(ownerID int64, e *openpgp.Entity, verified bool) (*GPGKey, erro
}
// Check emails
- userEmails, err := GetEmailAddresses(ownerID)
+ userEmails, err := user_model.GetEmailAddresses(ownerID)
if err != nil {
return nil, err
}
- emails := make([]*EmailAddress, 0, len(e.Identities))
+ emails := make([]*user_model.EmailAddress, 0, len(e.Identities))
for _, ident := range e.Identities {
if ident.Revocation != nil {
continue
@@ -242,7 +243,7 @@ func DeleteGPGKey(doer *User, id int64) (err error) {
func checkKeyEmails(email string, keys ...*GPGKey) (bool, string) {
uid := int64(0)
- var userEmails []*EmailAddress
+ var userEmails []*user_model.EmailAddress
var user *User
for _, key := range keys {
for _, e := range key.Emails {
@@ -252,7 +253,7 @@ func checkKeyEmails(email string, keys ...*GPGKey) (bool, string) {
}
if key.Verified && key.OwnerID != 0 {
if uid != key.OwnerID {
- userEmails, _ = GetEmailAddresses(key.OwnerID)
+ userEmails, _ = user_model.GetEmailAddresses(key.OwnerID)
uid = key.OwnerID
user = &User{ID: uid}
_, _ = GetUser(user)
diff --git a/models/gpg_key_commit_verification.go b/models/gpg_key_commit_verification.go
index f508303a09..6da65d3697 100644
--- a/models/gpg_key_commit_verification.go
+++ b/models/gpg_key_commit_verification.go
@@ -10,6 +10,7 @@ import (
"strings"
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
@@ -167,7 +168,7 @@ func ParseCommitWithSignature(c *git.Commit) *CommitVerification {
}
}
- committerEmailAddresses, _ := GetEmailAddresses(committer.ID)
+ committerEmailAddresses, _ := user_model.GetEmailAddresses(committer.ID)
activated := false
for _, e := range committerEmailAddresses {
if e.IsActivated && strings.EqualFold(e.Email, c.Committer.Email) {
diff --git a/models/org.go b/models/org.go
index c6d2562f15..1840cae9fa 100644
--- a/models/org.go
+++ b/models/org.go
@@ -11,6 +11,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unit"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
@@ -163,25 +164,25 @@ func CreateOrganization(org, owner *User) (err error) {
org.NumMembers = 1
org.Type = UserTypeOrganization
- sess := db.NewSession(db.DefaultContext)
- defer sess.Close()
- if err = sess.Begin(); err != nil {
+ ctx, committer, err := db.TxContext()
+ if err != nil {
return err
}
+ defer committer.Close()
- if err = deleteUserRedirect(sess, org.Name); err != nil {
+ if err = user_model.DeleteUserRedirect(ctx, org.Name); err != nil {
return err
}
- if _, err = sess.Insert(org); err != nil {
+ if err = db.Insert(ctx, org); err != nil {
return fmt.Errorf("insert organization: %v", err)
}
- if err = org.generateRandomAvatar(sess); err != nil {
+ if err = org.generateRandomAvatar(db.GetEngine(ctx)); err != nil {
return fmt.Errorf("generate random avatar: %v", err)
}
// Add initial creator to organization and owner team.
- if _, err = sess.Insert(&OrgUser{
+ if err = db.Insert(ctx, &OrgUser{
UID: owner.ID,
OrgID: org.ID,
}); err != nil {
@@ -198,7 +199,7 @@ func CreateOrganization(org, owner *User) (err error) {
IncludesAllRepositories: true,
CanCreateOrgRepo: true,
}
- if _, err = sess.Insert(t); err != nil {
+ if err = db.Insert(ctx, t); err != nil {
return fmt.Errorf("insert owner team: %v", err)
}
@@ -212,14 +213,11 @@ func CreateOrganization(org, owner *User) (err error) {
})
}
- if _, err = sess.Insert(&units); err != nil {
- if err := sess.Rollback(); err != nil {
- log.Error("CreateOrganization: sess.Rollback: %v", err)
- }
+ if err = db.Insert(ctx, &units); err != nil {
return err
}
- if _, err = sess.Insert(&TeamUser{
+ if err = db.Insert(ctx, &TeamUser{
UID: owner.ID,
OrgID: org.ID,
TeamID: t.ID,
@@ -227,7 +225,7 @@ func CreateOrganization(org, owner *User) (err error) {
return fmt.Errorf("insert team-user relation: %v", err)
}
- return sess.Commit()
+ return committer.Commit()
}
// GetOrgByName returns organization by given name.
diff --git a/models/ssh_key_principals.go b/models/ssh_key_principals.go
index 44b2ee0bb4..50456b72db 100644
--- a/models/ssh_key_principals.go
+++ b/models/ssh_key_principals.go
@@ -10,6 +10,7 @@ import (
"strings"
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
)
@@ -88,7 +89,7 @@ func CheckPrincipalKeyString(user *User, content string) (_ string, err error) {
case "anything":
return content, nil
case "email":
- emails, err := GetEmailAddresses(user.ID)
+ emails, err := user_model.GetEmailAddresses(user.ID)
if err != nil {
return "", err
}
diff --git a/models/user.go b/models/user.go
index 13347a46b7..12035dbe42 100644
--- a/models/user.go
+++ b/models/user.go
@@ -23,6 +23,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/login"
"code.gitea.io/gitea/models/unit"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
@@ -77,9 +78,6 @@ const (
)
var (
- // ErrEmailNotActivated e-mail address has not been activated error
- ErrEmailNotActivated = errors.New("E-mail address has not been activated")
-
// ErrUserNameIllegal user name contains illegal characters error
ErrUserNameIllegal = errors.New("User name contains illegal characters")
@@ -890,14 +888,15 @@ func CreateUser(u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err e
u.Visibility = overwriteDefault[0].Visibility
}
- sess := db.NewSession(db.DefaultContext)
- defer sess.Close()
- if err = sess.Begin(); err != nil {
+ ctx, committer, err := db.TxContext()
+ if err != nil {
return err
}
+ defer committer.Close()
- // validate data
+ sess := db.GetEngine(ctx)
+ // validate data
if err := validateUser(u); err != nil {
return err
}
@@ -909,11 +908,13 @@ func CreateUser(u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err e
return ErrUserAlreadyExist{u.Name}
}
- isExist, err = isEmailUsed(sess, u.Email)
+ isExist, err = user_model.IsEmailUsed(ctx, u.Email)
if err != nil {
return err
} else if isExist {
- return ErrEmailAlreadyUsed{u.Email}
+ return user_model.ErrEmailAlreadyUsed{
+ Email: u.Email,
+ }
}
// prepare for database
@@ -929,16 +930,16 @@ func CreateUser(u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err e
// save changes to database
- if err = deleteUserRedirect(sess, u.Name); err != nil {
+ if err = user_model.DeleteUserRedirect(ctx, u.Name); err != nil {
return err
}
- if _, err = sess.Insert(u); err != nil {
+ if err = db.Insert(ctx, u); err != nil {
return err
}
// insert email address
- if _, err := sess.Insert(&EmailAddress{
+ if err := db.Insert(ctx, &user_model.EmailAddress{
UID: u.ID,
Email: u.Email,
LowerEmail: strings.ToLower(u.Email),
@@ -948,7 +949,7 @@ func CreateUser(u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err e
return err
}
- return sess.Commit()
+ return committer.Commit()
}
func countUsers(e db.Engine) int64 {
@@ -998,7 +999,7 @@ func VerifyUserActiveCode(code string) (user *User) {
}
// VerifyActiveEmailCode verifies active email code when active account
-func VerifyActiveEmailCode(code, email string) *EmailAddress {
+func VerifyActiveEmailCode(code, email string) *user_model.EmailAddress {
minutes := setting.Service.ActiveCodeLives
if user := getVerifyUser(code); user != nil {
@@ -1007,7 +1008,7 @@ func VerifyActiveEmailCode(code, email string) *EmailAddress {
data := fmt.Sprintf("%d%s%s%s%s", user.ID, email, user.LowerName, user.Passwd, user.Rands)
if base.VerifyTimeLimitCode(data, minutes, prefix) {
- emailAddress := &EmailAddress{UID: user.ID, Email: email}
+ emailAddress := &user_model.EmailAddress{UID: user.ID, Email: email}
if has, _ := db.GetEngine(db.DefaultContext).Get(emailAddress); has {
return emailAddress
}
@@ -1023,11 +1024,12 @@ func ChangeUserName(u *User, newUserName string) (err error) {
return err
}
- sess := db.NewSession(db.DefaultContext)
- defer sess.Close()
- if err = sess.Begin(); err != nil {
+ ctx, committer, err := db.TxContext()
+ if err != nil {
return err
}
+ defer committer.Close()
+ sess := db.GetEngine(ctx)
isExist, err := isUserExist(sess, 0, newUserName)
if err != nil {
@@ -1045,11 +1047,11 @@ func ChangeUserName(u *User, newUserName string) (err error) {
return fmt.Errorf("Rename user directory: %v", err)
}
- if err = newUserRedirect(sess, u.ID, oldUserName, newUserName); err != nil {
+ if err = user_model.NewUserRedirect(ctx, u.ID, oldUserName, newUserName); err != nil {
return err
}
- if err = sess.Commit(); err != nil {
+ if err = committer.Commit(); err != nil {
if err2 := util.Rename(UserPath(newUserName), UserPath(oldUserName)); err2 != nil && !os.IsNotExist(err2) {
log.Critical("Unable to rollback directory change during failed username change from: %s to: %s. DB Error: %v. Filesystem Error: %v", oldUserName, newUserName, err, err2)
return fmt.Errorf("failed to rollback directory change during failed username change from: %s to: %s. DB Error: %w. Filesystem Error: %v", oldUserName, newUserName, err, err2)
@@ -1071,7 +1073,9 @@ func checkDupEmail(e db.Engine, u *User) error {
if err != nil {
return err
} else if has {
- return ErrEmailAlreadyUsed{u.Email}
+ return user_model.ErrEmailAlreadyUsed{
+ Email: u.Email,
+ }
}
return nil
}
@@ -1083,7 +1087,7 @@ func validateUser(u *User) error {
}
u.Email = strings.ToLower(u.Email)
- return ValidateEmail(u.Email)
+ return user_model.ValidateEmail(u.Email)
}
func updateUser(e db.Engine, u *User) error {
@@ -1211,7 +1215,7 @@ func deleteUser(e db.Engine, u *User) error {
&Follow{FollowID: u.ID},
&Action{UserID: u.ID},
&IssueUser{UID: u.ID},
- &EmailAddress{UID: u.ID},
+ &user_model.EmailAddress{UID: u.ID},
&UserOpenID{UID: u.ID},
&Reaction{UserID: u.ID},
&TeamUser{UID: u.ID},
@@ -1370,7 +1374,7 @@ func DeleteInactiveUsers(ctx context.Context, olderThan time.Duration) (err erro
_, err = db.GetEngine(db.DefaultContext).
Where("is_activated = ?", false).
- Delete(new(EmailAddress))
+ Delete(new(user_model.EmailAddress))
return err
}
@@ -1576,7 +1580,7 @@ func GetUserByEmailContext(ctx context.Context, email string) (*User, error) {
}
// Otherwise, check in alternative list for activated email addresses
- emailAddress := &EmailAddress{Email: email, IsActivated: true}
+ emailAddress := &user_model.EmailAddress{Email: email, IsActivated: true}
has, err = db.GetEngine(ctx).Get(emailAddress)
if err != nil {
return nil, err
diff --git a/models/user/email_address.go b/models/user/email_address.go
new file mode 100644
index 0000000000..74fb71d454
--- /dev/null
+++ b/models/user/email_address.go
@@ -0,0 +1,269 @@
+// Copyright 2016 The Gogs Authors. All rights reserved.
+// Copyright 2020 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package user
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "net/mail"
+ "strings"
+
+ "code.gitea.io/gitea/models/db"
+ "code.gitea.io/gitea/modules/log"
+ "code.gitea.io/gitea/modules/setting"
+
+ "xorm.io/builder"
+)
+
+var (
+ // ErrEmailNotActivated e-mail address has not been activated error
+ ErrEmailNotActivated = errors.New("E-mail address has not been activated")
+)
+
+// ErrEmailInvalid represents an error where the email address does not comply with RFC 5322
+type ErrEmailInvalid struct {
+ Email string
+}
+
+// IsErrEmailInvalid checks if an error is an ErrEmailInvalid
+func IsErrEmailInvalid(err error) bool {
+ _, ok := err.(ErrEmailInvalid)
+ return ok
+}
+
+func (err ErrEmailInvalid) Error() string {
+ return fmt.Sprintf("e-mail invalid [email: %s]", err.Email)
+}
+
+// ErrEmailAlreadyUsed represents a "EmailAlreadyUsed" kind of error.
+type ErrEmailAlreadyUsed struct {
+ Email string
+}
+
+// IsErrEmailAlreadyUsed checks if an error is a ErrEmailAlreadyUsed.
+func IsErrEmailAlreadyUsed(err error) bool {
+ _, ok := err.(ErrEmailAlreadyUsed)
+ return ok
+}
+
+func (err ErrEmailAlreadyUsed) Error() string {
+ return fmt.Sprintf("e-mail already in use [email: %s]", err.Email)
+}
+
+// ErrEmailAddressNotExist email address not exist
+type ErrEmailAddressNotExist struct {
+ Email string
+}
+
+// IsErrEmailAddressNotExist checks if an error is an ErrEmailAddressNotExist
+func IsErrEmailAddressNotExist(err error) bool {
+ _, ok := err.(ErrEmailAddressNotExist)
+ return ok
+}
+
+func (err ErrEmailAddressNotExist) Error() string {
+ return fmt.Sprintf("Email address does not exist [email: %s]", err.Email)
+}
+
+// ErrPrimaryEmailCannotDelete primary email address cannot be deleted
+type ErrPrimaryEmailCannotDelete struct {
+ Email string
+}
+
+// IsErrPrimaryEmailCannotDelete checks if an error is an ErrPrimaryEmailCannotDelete
+func IsErrPrimaryEmailCannotDelete(err error) bool {
+ _, ok := err.(ErrPrimaryEmailCannotDelete)
+ return ok
+}
+
+func (err ErrPrimaryEmailCannotDelete) Error() string {
+ return fmt.Sprintf("Primary email address cannot be deleted [email: %s]", err.Email)
+}
+
+// EmailAddress is the list of all email addresses of a user. It also contains the
+// primary email address which is saved in user table.
+type EmailAddress struct {
+ ID int64 `xorm:"pk autoincr"`
+ UID int64 `xorm:"INDEX NOT NULL"`
+ Email string `xorm:"UNIQUE NOT NULL"`
+ LowerEmail string `xorm:"UNIQUE NOT NULL"`
+ IsActivated bool
+ IsPrimary bool `xorm:"DEFAULT(false) NOT NULL"`
+}
+
+func init() {
+ db.RegisterModel(new(EmailAddress))
+}
+
+// BeforeInsert will be invoked by XORM before inserting a record
+func (email *EmailAddress) BeforeInsert() {
+ if email.LowerEmail == "" {
+ email.LowerEmail = strings.ToLower(email.Email)
+ }
+}
+
+// ValidateEmail check if email is a allowed address
+func ValidateEmail(email string) error {
+ if len(email) == 0 {
+ return nil
+ }
+
+ if _, err := mail.ParseAddress(email); err != nil {
+ return ErrEmailInvalid{email}
+ }
+
+ // TODO: add an email allow/block list
+
+ return nil
+}
+
+// GetEmailAddresses returns all email addresses belongs to given user.
+func GetEmailAddresses(uid int64) ([]*EmailAddress, error) {
+ emails := make([]*EmailAddress, 0, 5)
+ if err := db.GetEngine(db.DefaultContext).
+ Where("uid=?", uid).
+ Asc("id").
+ Find(&emails); err != nil {
+ return nil, err
+ }
+ return emails, nil
+}
+
+// GetEmailAddressByID gets a user's email address by ID
+func GetEmailAddressByID(uid, id int64) (*EmailAddress, error) {
+ // User ID is required for security reasons
+ email := &EmailAddress{UID: uid}
+ if has, err := db.GetEngine(db.DefaultContext).ID(id).Get(email); err != nil {
+ return nil, err
+ } else if !has {
+ return nil, nil
+ }
+ return email, nil
+}
+
+// IsEmailActive check if email is activated with a different emailID
+func IsEmailActive(ctx context.Context, email string, excludeEmailID int64) (bool, error) {
+ if len(email) == 0 {
+ return true, nil
+ }
+
+ // Can't filter by boolean field unless it's explicit
+ cond := builder.NewCond()
+ cond = cond.And(builder.Eq{"lower_email": strings.ToLower(email)}, builder.Neq{"id": excludeEmailID})
+ if setting.Service.RegisterEmailConfirm {
+ // Inactive (unvalidated) addresses don't count as active if email validation is required
+ cond = cond.And(builder.Eq{"is_activated": true})
+ }
+
+ var em EmailAddress
+ if has, err := db.GetEngine(ctx).Where(cond).Get(&em); has || err != nil {
+ if has {
+ log.Info("isEmailActive(%q, %d) found duplicate in email ID %d", email, excludeEmailID, em.ID)
+ }
+ return has, err
+ }
+
+ return false, nil
+}
+
+// IsEmailUsed returns true if the email has been used.
+func IsEmailUsed(ctx context.Context, email string) (bool, error) {
+ if len(email) == 0 {
+ return true, nil
+ }
+
+ return db.GetEngine(ctx).Where("lower_email=?", strings.ToLower(email)).Get(&EmailAddress{})
+}
+
+func addEmailAddress(ctx context.Context, email *EmailAddress) error {
+ email.Email = strings.TrimSpace(email.Email)
+ used, err := IsEmailUsed(ctx, email.Email)
+ if err != nil {
+ return err
+ } else if used {
+ return ErrEmailAlreadyUsed{email.Email}
+ }
+
+ if err = ValidateEmail(email.Email); err != nil {
+ return err
+ }
+
+ return db.Insert(ctx, email)
+}
+
+// AddEmailAddress adds an email address to given user.
+func AddEmailAddress(email *EmailAddress) error {
+ return addEmailAddress(db.DefaultContext, email)
+}
+
+// AddEmailAddresses adds an email address to given user.
+func AddEmailAddresses(emails []*EmailAddress) error {
+ if len(emails) == 0 {
+ return nil
+ }
+
+ // Check if any of them has been used
+ for i := range emails {
+ emails[i].Email = strings.TrimSpace(emails[i].Email)
+ used, err := IsEmailUsed(db.DefaultContext, emails[i].Email)
+ if err != nil {
+ return err
+ } else if used {
+ return ErrEmailAlreadyUsed{emails[i].Email}
+ }
+ if err = ValidateEmail(emails[i].Email); err != nil {
+ return err
+ }
+ }
+
+ if err := db.Insert(db.DefaultContext, emails); err != nil {
+ return fmt.Errorf("Insert: %v", err)
+ }
+
+ return nil
+}
+
+// DeleteEmailAddress deletes an email address of given user.
+func DeleteEmailAddress(email *EmailAddress) (err error) {
+ if email.IsPrimary {
+ return ErrPrimaryEmailCannotDelete{Email: email.Email}
+ }
+
+ var deleted int64
+ // ask to check UID
+ address := EmailAddress{
+ UID: email.UID,
+ }
+ if email.ID > 0 {
+ deleted, err = db.GetEngine(db.DefaultContext).ID(email.ID).Delete(&address)
+ } else {
+ if email.Email != "" && email.LowerEmail == "" {
+ email.LowerEmail = strings.ToLower(email.Email)
+ }
+ deleted, err = db.GetEngine(db.DefaultContext).
+ Where("lower_email=?", email.LowerEmail).
+ Delete(&address)
+ }
+
+ if err != nil {
+ return err
+ } else if deleted != 1 {
+ return ErrEmailAddressNotExist{Email: email.Email}
+ }
+ return nil
+}
+
+// DeleteEmailAddresses deletes multiple email addresses
+func DeleteEmailAddresses(emails []*EmailAddress) (err error) {
+ for i := range emails {
+ if err = DeleteEmailAddress(emails[i]); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
diff --git a/models/user/email_address_test.go b/models/user/email_address_test.go
new file mode 100644
index 0000000000..5ed0bf8884
--- /dev/null
+++ b/models/user/email_address_test.go
@@ -0,0 +1,131 @@
+// Copyright 2017 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package user
+
+import (
+ "testing"
+
+ "code.gitea.io/gitea/models/db"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestGetEmailAddresses(t *testing.T) {
+ assert.NoError(t, db.PrepareTestDatabase())
+
+ emails, _ := GetEmailAddresses(int64(1))
+ if assert.Len(t, emails, 3) {
+ assert.True(t, emails[0].IsPrimary)
+ assert.True(t, emails[2].IsActivated)
+ assert.False(t, emails[2].IsPrimary)
+ }
+
+ emails, _ = GetEmailAddresses(int64(2))
+ if assert.Len(t, emails, 2) {
+ assert.True(t, emails[0].IsPrimary)
+ assert.True(t, emails[0].IsActivated)
+ }
+}
+
+func TestIsEmailUsed(t *testing.T) {
+ assert.NoError(t, db.PrepareTestDatabase())
+
+ isExist, _ := IsEmailUsed(db.DefaultContext, "")
+ assert.True(t, isExist)
+ isExist, _ = IsEmailUsed(db.DefaultContext, "user11@example.com")
+ assert.True(t, isExist)
+ isExist, _ = IsEmailUsed(db.DefaultContext, "user1234567890@example.com")
+ assert.False(t, isExist)
+}
+
+func TestAddEmailAddress(t *testing.T) {
+ assert.NoError(t, db.PrepareTestDatabase())
+
+ assert.NoError(t, AddEmailAddress(&EmailAddress{
+ Email: "user1234567890@example.com",
+ LowerEmail: "user1234567890@example.com",
+ IsPrimary: true,
+ IsActivated: true,
+ }))
+
+ // ErrEmailAlreadyUsed
+ err := AddEmailAddress(&EmailAddress{
+ Email: "user1234567890@example.com",
+ LowerEmail: "user1234567890@example.com",
+ })
+ assert.Error(t, err)
+ assert.True(t, IsErrEmailAlreadyUsed(err))
+}
+
+func TestAddEmailAddresses(t *testing.T) {
+ assert.NoError(t, db.PrepareTestDatabase())
+
+ // insert multiple email address
+ emails := make([]*EmailAddress, 2)
+ emails[0] = &EmailAddress{
+ Email: "user1234@example.com",
+ LowerEmail: "user1234@example.com",
+ IsActivated: true,
+ }
+ emails[1] = &EmailAddress{
+ Email: "user5678@example.com",
+ LowerEmail: "user5678@example.com",
+ IsActivated: true,
+ }
+ assert.NoError(t, AddEmailAddresses(emails))
+
+ // ErrEmailAlreadyUsed
+ err := AddEmailAddresses(emails)
+ assert.Error(t, err)
+ assert.True(t, IsErrEmailAlreadyUsed(err))
+}
+
+func TestDeleteEmailAddress(t *testing.T) {
+ assert.NoError(t, db.PrepareTestDatabase())
+
+ assert.NoError(t, DeleteEmailAddress(&EmailAddress{
+ UID: int64(1),
+ ID: int64(33),
+ Email: "user1-2@example.com",
+ LowerEmail: "user1-2@example.com",
+ }))
+
+ assert.NoError(t, DeleteEmailAddress(&EmailAddress{
+ UID: int64(1),
+ Email: "user1-3@example.com",
+ LowerEmail: "user1-3@example.com",
+ }))
+
+ // Email address does not exist
+ err := DeleteEmailAddress(&EmailAddress{
+ UID: int64(1),
+ Email: "user1234567890@example.com",
+ LowerEmail: "user1234567890@example.com",
+ })
+ assert.Error(t, err)
+}
+
+func TestDeleteEmailAddresses(t *testing.T) {
+ assert.NoError(t, db.PrepareTestDatabase())
+
+ // delete multiple email address
+ emails := make([]*EmailAddress, 2)
+ emails[0] = &EmailAddress{
+ UID: int64(2),
+ ID: int64(3),
+ Email: "user2@example.com",
+ LowerEmail: "user2@example.com",
+ }
+ emails[1] = &EmailAddress{
+ UID: int64(2),
+ Email: "user2-2@example.com",
+ LowerEmail: "user2-2@example.com",
+ }
+ assert.NoError(t, DeleteEmailAddresses(emails))
+
+ // ErrEmailAlreadyUsed
+ err := DeleteEmailAddresses(emails)
+ assert.Error(t, err)
+}
diff --git a/models/user/main_test.go b/models/user/main_test.go
new file mode 100644
index 0000000000..2999c4c81d
--- /dev/null
+++ b/models/user/main_test.go
@@ -0,0 +1,19 @@
+// Copyright 2020 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package user
+
+import (
+ "path/filepath"
+ "testing"
+
+ "code.gitea.io/gitea/models/db"
+)
+
+func TestMain(m *testing.M) {
+ db.MainTest(m, filepath.Join("..", ".."),
+ "email_address.yml",
+ "user_redirect.yml",
+ )
+}
diff --git a/models/user/redirect.go b/models/user/redirect.go
new file mode 100644
index 0000000000..49370218db
--- /dev/null
+++ b/models/user/redirect.go
@@ -0,0 +1,79 @@
+// Copyright 2020 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package user
+
+import (
+ "context"
+ "fmt"
+ "strings"
+
+ "code.gitea.io/gitea/models/db"
+)
+
+// ErrUserRedirectNotExist represents a "UserRedirectNotExist" kind of error.
+type ErrUserRedirectNotExist struct {
+ Name string
+}
+
+// IsErrUserRedirectNotExist check if an error is an ErrUserRedirectNotExist.
+func IsErrUserRedirectNotExist(err error) bool {
+ _, ok := err.(ErrUserRedirectNotExist)
+ return ok
+}
+
+func (err ErrUserRedirectNotExist) Error() string {
+ return fmt.Sprintf("user redirect does not exist [name: %s]", err.Name)
+}
+
+// Redirect represents that a user name should be redirected to another
+type Redirect struct {
+ ID int64 `xorm:"pk autoincr"`
+ LowerName string `xorm:"UNIQUE(s) INDEX NOT NULL"`
+ RedirectUserID int64 // userID to redirect to
+}
+
+// TableName provides the real table name
+func (Redirect) TableName() string {
+ return "user_redirect"
+}
+
+func init() {
+ db.RegisterModel(new(Redirect))
+}
+
+// LookupUserRedirect look up userID if a user has a redirect name
+func LookupUserRedirect(userName string) (int64, error) {
+ userName = strings.ToLower(userName)
+ redirect := &Redirect{LowerName: userName}
+ if has, err := db.GetEngine(db.DefaultContext).Get(redirect); err != nil {
+ return 0, err
+ } else if !has {
+ return 0, ErrUserRedirectNotExist{Name: userName}
+ }
+ return redirect.RedirectUserID, nil
+}
+
+// NewUserRedirect create a new user redirect
+func NewUserRedirect(ctx context.Context, ID int64, oldUserName, newUserName string) error {
+ oldUserName = strings.ToLower(oldUserName)
+ newUserName = strings.ToLower(newUserName)
+
+ if err := DeleteUserRedirect(ctx, newUserName); err != nil {
+ return err
+ }
+
+ return db.Insert(ctx, &Redirect{
+ LowerName: oldUserName,
+ RedirectUserID: ID,
+ })
+}
+
+// DeleteUserRedirect delete any redirect from the specified user name to
+// anything else
+func DeleteUserRedirect(ctx context.Context, userName string) error {
+ userName = strings.ToLower(userName)
+ _, err := db.GetEngine(ctx).Delete(&Redirect{LowerName: userName})
+ return err
+}
diff --git a/models/user/redirect_test.go b/models/user/redirect_test.go
new file mode 100644
index 0000000000..b33c42cf3d
--- /dev/null
+++ b/models/user/redirect_test.go
@@ -0,0 +1,23 @@
+// Copyright 2020 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package user
+
+import (
+ "testing"
+
+ "code.gitea.io/gitea/models/db"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestLookupUserRedirect(t *testing.T) {
+ assert.NoError(t, db.PrepareTestDatabase())
+
+ userID, err := LookupUserRedirect("olduser1")
+ assert.NoError(t, err)
+ assert.EqualValues(t, 1, userID)
+
+ _, err = LookupUserRedirect("doesnotexist")
+ assert.True(t, IsErrUserRedirectNotExist(err))
+}
diff --git a/models/user_mail.go b/models/user_email.go
index caa931788d..7de577bc2c 100644
--- a/models/user_mail.go
+++ b/models/user_email.go
@@ -1,5 +1,4 @@
-// Copyright 2016 The Gogs Authors. All rights reserved.
-// Copyright 2020 The Gitea Authors. All rights reserved.
+// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
@@ -7,179 +6,28 @@ package models
import (
"fmt"
- "net/mail"
"strings"
"code.gitea.io/gitea/models/db"
- "code.gitea.io/gitea/modules/log"
- "code.gitea.io/gitea/modules/setting"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/util"
-
"xorm.io/builder"
)
-// EmailAddress is the list of all email addresses of a user. It also contains the
-// primary email address which is saved in user table.
-type EmailAddress struct {
- ID int64 `xorm:"pk autoincr"`
- UID int64 `xorm:"INDEX NOT NULL"`
- Email string `xorm:"UNIQUE NOT NULL"`
- LowerEmail string `xorm:"UNIQUE NOT NULL"`
- IsActivated bool
- IsPrimary bool `xorm:"DEFAULT(false) NOT NULL"`
-}
-
-func init() {
- db.RegisterModel(new(EmailAddress))
-}
-
-// BeforeInsert will be invoked by XORM before inserting a record
-func (email *EmailAddress) BeforeInsert() {
- if email.LowerEmail == "" {
- email.LowerEmail = strings.ToLower(email.Email)
- }
-}
-
-// ValidateEmail check if email is a allowed address
-func ValidateEmail(email string) error {
- if len(email) == 0 {
- return nil
- }
-
- if _, err := mail.ParseAddress(email); err != nil {
- return ErrEmailInvalid{email}
- }
-
- // TODO: add an email allow/block list
-
- return nil
-}
-
-// GetEmailAddresses returns all email addresses belongs to given user.
-func GetEmailAddresses(uid int64) ([]*EmailAddress, error) {
- emails := make([]*EmailAddress, 0, 5)
- if err := db.GetEngine(db.DefaultContext).
- Where("uid=?", uid).
- Asc("id").
- Find(&emails); err != nil {
- return nil, err
- }
- return emails, nil
-}
-
-// GetEmailAddressByID gets a user's email address by ID
-func GetEmailAddressByID(uid, id int64) (*EmailAddress, error) {
- // User ID is required for security reasons
- email := &EmailAddress{UID: uid}
- if has, err := db.GetEngine(db.DefaultContext).ID(id).Get(email); err != nil {
- return nil, err
- } else if !has {
- return nil, nil
- }
- return email, nil
-}
-
-// isEmailActive check if email is activated with a different emailID
-func isEmailActive(e db.Engine, email string, excludeEmailID int64) (bool, error) {
- if len(email) == 0 {
- return true, nil
- }
-
- // Can't filter by boolean field unless it's explicit
- cond := builder.NewCond()
- cond = cond.And(builder.Eq{"lower_email": strings.ToLower(email)}, builder.Neq{"id": excludeEmailID})
- if setting.Service.RegisterEmailConfirm {
- // Inactive (unvalidated) addresses don't count as active if email validation is required
- cond = cond.And(builder.Eq{"is_activated": true})
- }
-
- var em EmailAddress
- if has, err := e.Where(cond).Get(&em); has || err != nil {
- if has {
- log.Info("isEmailActive(%q, %d) found duplicate in email ID %d", email, excludeEmailID, em.ID)
- }
- return has, err
- }
-
- return false, nil
-}
-
-func isEmailUsed(e db.Engine, email string) (bool, error) {
- if len(email) == 0 {
- return true, nil
- }
-
- return e.Where("lower_email=?", strings.ToLower(email)).Get(&EmailAddress{})
-}
-
-// IsEmailUsed returns true if the email has been used.
-func IsEmailUsed(email string) (bool, error) {
- return isEmailUsed(db.GetEngine(db.DefaultContext), email)
-}
-
-func addEmailAddress(e db.Engine, email *EmailAddress) error {
- email.Email = strings.TrimSpace(email.Email)
- used, err := isEmailUsed(e, email.Email)
- if err != nil {
- return err
- } else if used {
- return ErrEmailAlreadyUsed{email.Email}
- }
-
- if err = ValidateEmail(email.Email); err != nil {
- return err
- }
-
- _, err = e.Insert(email)
- return err
-}
-
-// AddEmailAddress adds an email address to given user.
-func AddEmailAddress(email *EmailAddress) error {
- return addEmailAddress(db.GetEngine(db.DefaultContext), email)
-}
-
-// AddEmailAddresses adds an email address to given user.
-func AddEmailAddresses(emails []*EmailAddress) error {
- if len(emails) == 0 {
- return nil
- }
-
- // Check if any of them has been used
- for i := range emails {
- emails[i].Email = strings.TrimSpace(emails[i].Email)
- used, err := IsEmailUsed(emails[i].Email)
- if err != nil {
- return err
- } else if used {
- return ErrEmailAlreadyUsed{emails[i].Email}
- }
- if err = ValidateEmail(emails[i].Email); err != nil {
- return err
- }
- }
-
- if _, err := db.GetEngine(db.DefaultContext).Insert(emails); err != nil {
- return fmt.Errorf("Insert: %v", err)
- }
-
- return nil
-}
-
-// Activate activates the email address to given user.
-func (email *EmailAddress) Activate() error {
+// ActivateEmail activates the email address to given user.
+func ActivateEmail(email *user_model.EmailAddress) error {
sess := db.NewSession(db.DefaultContext)
defer sess.Close()
if err := sess.Begin(); err != nil {
return err
}
- if err := email.updateActivation(sess, true); err != nil {
+ if err := updateActivation(sess, email, true); err != nil {
return err
}
return sess.Commit()
}
-func (email *EmailAddress) updateActivation(e db.Engine, activate bool) error {
+func updateActivation(e db.Engine, email *user_model.EmailAddress, activate bool) error {
user, err := getUserByID(e, email.UID)
if err != nil {
return err
@@ -194,58 +42,17 @@ func (email *EmailAddress) updateActivation(e db.Engine, activate bool) error {
return updateUserCols(e, user, "rands")
}
-// DeleteEmailAddress deletes an email address of given user.
-func DeleteEmailAddress(email *EmailAddress) (err error) {
- if email.IsPrimary {
- return ErrPrimaryEmailCannotDelete{Email: email.Email}
- }
-
- var deleted int64
- // ask to check UID
- address := EmailAddress{
- UID: email.UID,
- }
- if email.ID > 0 {
- deleted, err = db.GetEngine(db.DefaultContext).ID(email.ID).Delete(&address)
- } else {
- if email.Email != "" && email.LowerEmail == "" {
- email.LowerEmail = strings.ToLower(email.Email)
- }
- deleted, err = db.GetEngine(db.DefaultContext).
- Where("lower_email=?", email.LowerEmail).
- Delete(&address)
- }
-
- if err != nil {
- return err
- } else if deleted != 1 {
- return ErrEmailAddressNotExist{Email: email.Email}
- }
- return nil
-}
-
-// DeleteEmailAddresses deletes multiple email addresses
-func DeleteEmailAddresses(emails []*EmailAddress) (err error) {
- for i := range emails {
- if err = DeleteEmailAddress(emails[i]); err != nil {
- return err
- }
- }
-
- return nil
-}
-
// MakeEmailPrimary sets primary email address of given user.
-func MakeEmailPrimary(email *EmailAddress) error {
+func MakeEmailPrimary(email *user_model.EmailAddress) error {
has, err := db.GetEngine(db.DefaultContext).Get(email)
if err != nil {
return err
} else if !has {
- return ErrEmailAddressNotExist{Email: email.Email}
+ return user_model.ErrEmailAddressNotExist{Email: email.Email}
}
if !email.IsActivated {
- return ErrEmailNotActivated
+ return user_model.ErrEmailNotActivated
}
user := &User{}
@@ -269,7 +76,7 @@ func MakeEmailPrimary(email *EmailAddress) error {
}
// 2. Update old primary email
- if _, err = sess.Where("uid=? AND is_primary=?", email.UID, true).Cols("is_primary").Update(&EmailAddress{
+ if _, err = sess.Where("uid=? AND is_primary=?", email.UID, true).Cols("is_primary").Update(&user_model.EmailAddress{
IsPrimary: false,
}); err != nil {
return err
@@ -347,7 +154,7 @@ func SearchEmails(opts *SearchEmailOptions) ([]*SearchEmailResult, int64, error)
}
count, err := db.GetEngine(db.DefaultContext).Join("INNER", "`user`", "`user`.ID = email_address.uid").
- Where(cond).Count(new(EmailAddress))
+ Where(cond).Count(new(user_model.EmailAddress))
if err != nil {
return nil, 0, fmt.Errorf("Count: %v", err)
}
@@ -374,15 +181,16 @@ func SearchEmails(opts *SearchEmailOptions) ([]*SearchEmailResult, int64, error)
// ActivateUserEmail will change the activated state of an email address,
// either primary or secondary (all in the email_address table)
func ActivateUserEmail(userID int64, email string, activate bool) (err error) {
- sess := db.NewSession(db.DefaultContext)
- defer sess.Close()
- if err = sess.Begin(); err != nil {
+ ctx, committer, err := db.TxContext()
+ if err != nil {
return err
}
+ defer committer.Close()
+ sess := db.GetEngine(ctx)
// Activate/deactivate a user's secondary email address
// First check if there's another user active with the same address
- addr := EmailAddress{UID: userID, LowerEmail: strings.ToLower(email)}
+ addr := user_model.EmailAddress{UID: userID, LowerEmail: strings.ToLower(email)}
if has, err := sess.Get(&addr); err != nil {
return err
} else if !has {
@@ -393,13 +201,13 @@ func ActivateUserEmail(userID int64, email string, activate bool) (err error) {
return nil
}
if activate {
- if used, err := isEmailActive(sess, email, addr.ID); err != nil {
+ if used, err := user_model.IsEmailActive(ctx, email, addr.ID); err != nil {
return fmt.Errorf("unable to check isEmailActive() for %s: %v", email, err)
} else if used {
- return ErrEmailAlreadyUsed{Email: email}
+ return user_model.ErrEmailAlreadyUsed{Email: email}
}
}
- if err = addr.updateActivation(sess, activate); err != nil {
+ if err = updateActivation(sess, &addr, activate); err != nil {
return fmt.Errorf("unable to updateActivation() for %d:%s: %w", addr.ID, addr.Email, err)
}
@@ -423,5 +231,5 @@ func ActivateUserEmail(userID int64, email string, activate bool) (err error) {
}
}
- return sess.Commit()
+ return committer.Commit()
}
diff --git a/models/user_mail_test.go b/models/user_email_test.go
index 384f28b7bf..8c2bb48b94 100644
--- a/models/user_mail_test.go
+++ b/models/user_email_test.go
@@ -1,4 +1,4 @@
-// Copyright 2017 The Gitea Authors. All rights reserved.
+// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
@@ -8,154 +8,37 @@ import (
"testing"
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/util"
"github.com/stretchr/testify/assert"
)
-func TestGetEmailAddresses(t *testing.T) {
- assert.NoError(t, db.PrepareTestDatabase())
-
- emails, _ := GetEmailAddresses(int64(1))
- if assert.Len(t, emails, 3) {
- assert.True(t, emails[0].IsPrimary)
- assert.True(t, emails[2].IsActivated)
- assert.False(t, emails[2].IsPrimary)
- }
-
- emails, _ = GetEmailAddresses(int64(2))
- if assert.Len(t, emails, 2) {
- assert.True(t, emails[0].IsPrimary)
- assert.True(t, emails[0].IsActivated)
- }
-}
-
-func TestIsEmailUsed(t *testing.T) {
- assert.NoError(t, db.PrepareTestDatabase())
-
- isExist, _ := IsEmailUsed("")
- assert.True(t, isExist)
- isExist, _ = IsEmailUsed("user11@example.com")
- assert.True(t, isExist)
- isExist, _ = IsEmailUsed("user1234567890@example.com")
- assert.False(t, isExist)
-}
-
-func TestAddEmailAddress(t *testing.T) {
- assert.NoError(t, db.PrepareTestDatabase())
-
- assert.NoError(t, AddEmailAddress(&EmailAddress{
- Email: "user1234567890@example.com",
- LowerEmail: "user1234567890@example.com",
- IsPrimary: true,
- IsActivated: true,
- }))
-
- // ErrEmailAlreadyUsed
- err := AddEmailAddress(&EmailAddress{
- Email: "user1234567890@example.com",
- LowerEmail: "user1234567890@example.com",
- })
- assert.Error(t, err)
- assert.True(t, IsErrEmailAlreadyUsed(err))
-}
-
-func TestAddEmailAddresses(t *testing.T) {
- assert.NoError(t, db.PrepareTestDatabase())
-
- // insert multiple email address
- emails := make([]*EmailAddress, 2)
- emails[0] = &EmailAddress{
- Email: "user1234@example.com",
- LowerEmail: "user1234@example.com",
- IsActivated: true,
- }
- emails[1] = &EmailAddress{
- Email: "user5678@example.com",
- LowerEmail: "user5678@example.com",
- IsActivated: true,
- }
- assert.NoError(t, AddEmailAddresses(emails))
-
- // ErrEmailAlreadyUsed
- err := AddEmailAddresses(emails)
- assert.Error(t, err)
- assert.True(t, IsErrEmailAlreadyUsed(err))
-}
-
-func TestDeleteEmailAddress(t *testing.T) {
- assert.NoError(t, db.PrepareTestDatabase())
-
- assert.NoError(t, DeleteEmailAddress(&EmailAddress{
- UID: int64(1),
- ID: int64(33),
- Email: "user1-2@example.com",
- LowerEmail: "user1-2@example.com",
- }))
-
- assert.NoError(t, DeleteEmailAddress(&EmailAddress{
- UID: int64(1),
- Email: "user1-3@example.com",
- LowerEmail: "user1-3@example.com",
- }))
-
- // Email address does not exist
- err := DeleteEmailAddress(&EmailAddress{
- UID: int64(1),
- Email: "user1234567890@example.com",
- LowerEmail: "user1234567890@example.com",
- })
- assert.Error(t, err)
-}
-
-func TestDeleteEmailAddresses(t *testing.T) {
- assert.NoError(t, db.PrepareTestDatabase())
-
- // delete multiple email address
- emails := make([]*EmailAddress, 2)
- emails[0] = &EmailAddress{
- UID: int64(2),
- ID: int64(3),
- Email: "user2@example.com",
- LowerEmail: "user2@example.com",
- }
- emails[1] = &EmailAddress{
- UID: int64(2),
- Email: "user2-2@example.com",
- LowerEmail: "user2-2@example.com",
- }
- assert.NoError(t, DeleteEmailAddresses(emails))
-
- // ErrEmailAlreadyUsed
- err := DeleteEmailAddresses(emails)
- assert.Error(t, err)
-}
-
func TestMakeEmailPrimary(t *testing.T) {
assert.NoError(t, db.PrepareTestDatabase())
- email := &EmailAddress{
+ email := &user_model.EmailAddress{
Email: "user567890@example.com",
}
err := MakeEmailPrimary(email)
assert.Error(t, err)
- assert.EqualError(t, err, ErrEmailAddressNotExist{email.Email}.Error())
+ assert.EqualError(t, err, user_model.ErrEmailAddressNotExist{Email: email.Email}.Error())
- email = &EmailAddress{
+ email = &user_model.EmailAddress{
Email: "user11@example.com",
}
err = MakeEmailPrimary(email)
assert.Error(t, err)
- assert.EqualError(t, err, ErrEmailNotActivated.Error())
+ assert.EqualError(t, err, user_model.ErrEmailNotActivated.Error())
- email = &EmailAddress{
+ email = &user_model.EmailAddress{
Email: "user9999999@example.com",
}
err = MakeEmailPrimary(email)
assert.Error(t, err)
assert.True(t, IsErrUserNotExist(err))
- email = &EmailAddress{
+ email = &user_model.EmailAddress{
Email: "user101@example.com",
}
err = MakeEmailPrimary(email)
@@ -168,14 +51,14 @@ func TestMakeEmailPrimary(t *testing.T) {
func TestActivate(t *testing.T) {
assert.NoError(t, db.PrepareTestDatabase())
- email := &EmailAddress{
+ email := &user_model.EmailAddress{
ID: int64(1),
UID: int64(1),
Email: "user11@example.com",
}
- assert.NoError(t, email.Activate())
+ assert.NoError(t, ActivateEmail(email))
- emails, _ := GetEmailAddresses(int64(1))
+ emails, _ := user_model.GetEmailAddresses(int64(1))
assert.Len(t, emails, 3)
assert.True(t, emails[0].IsActivated)
assert.True(t, emails[0].IsPrimary)
diff --git a/models/user_redirect.go b/models/user_redirect.go
deleted file mode 100644
index fdc730775f..0000000000
--- a/models/user_redirect.go
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2020 The Gitea Authors. All rights reserved.
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file.
-
-package models
-
-import (
- "strings"
-
- "code.gitea.io/gitea/models/db"
-)
-
-// UserRedirect represents that a user name should be redirected to another
-type UserRedirect struct {
- ID int64 `xorm:"pk autoincr"`
- LowerName string `xorm:"UNIQUE(s) INDEX NOT NULL"`
- RedirectUserID int64 // userID to redirect to
-}
-
-func init() {
- db.RegisterModel(new(UserRedirect))
-}
-
-// LookupUserRedirect look up userID if a user has a redirect name
-func LookupUserRedirect(userName string) (int64, error) {
- userName = strings.ToLower(userName)
- redirect := &UserRedirect{LowerName: userName}
- if has, err := db.GetEngine(db.DefaultContext).Get(redirect); err != nil {
- return 0, err
- } else if !has {
- return 0, ErrUserRedirectNotExist{Name: userName}
- }
- return redirect.RedirectUserID, nil
-}
-
-// newUserRedirect create a new user redirect
-func newUserRedirect(e db.Engine, ID int64, oldUserName, newUserName string) error {
- oldUserName = strings.ToLower(oldUserName)
- newUserName = strings.ToLower(newUserName)
-
- if err := deleteUserRedirect(e, newUserName); err != nil {
- return err
- }
-
- if _, err := e.Insert(&UserRedirect{
- LowerName: oldUserName,
- RedirectUserID: ID,
- }); err != nil {
- return err
- }
- return nil
-}
-
-// deleteUserRedirect delete any redirect from the specified user name to
-// anything else
-func deleteUserRedirect(e db.Engine, userName string) error {
- userName = strings.ToLower(userName)
- _, err := e.Delete(&UserRedirect{LowerName: userName})
- return err
-}
diff --git a/models/user_redirect_test.go b/models/user_redirect_test.go
deleted file mode 100644
index 346bf98b84..0000000000
--- a/models/user_redirect_test.go
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2020 The Gitea Authors. All rights reserved.
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file.
-
-package models
-
-import (
- "testing"
-
- "code.gitea.io/gitea/models/db"
- "github.com/stretchr/testify/assert"
-)
-
-func TestLookupUserRedirect(t *testing.T) {
- assert.NoError(t, db.PrepareTestDatabase())
-
- userID, err := LookupUserRedirect("olduser1")
- assert.NoError(t, err)
- assert.EqualValues(t, 1, userID)
-
- _, err = LookupUserRedirect("doesnotexist")
- assert.True(t, IsErrUserRedirectNotExist(err))
-}
-
-func TestNewUserRedirect(t *testing.T) {
- // redirect to a completely new name
- assert.NoError(t, db.PrepareTestDatabase())
-
- user := db.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
- assert.NoError(t, newUserRedirect(db.GetEngine(db.DefaultContext), user.ID, user.Name, "newusername"))
-
- db.AssertExistsAndLoadBean(t, &UserRedirect{
- LowerName: user.LowerName,
- RedirectUserID: user.ID,
- })
- db.AssertExistsAndLoadBean(t, &UserRedirect{
- LowerName: "olduser1",
- RedirectUserID: user.ID,
- })
-}
-
-func TestNewUserRedirect2(t *testing.T) {
- // redirect to previously used name
- assert.NoError(t, db.PrepareTestDatabase())
-
- user := db.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
- assert.NoError(t, newUserRedirect(db.GetEngine(db.DefaultContext), user.ID, user.Name, "olduser1"))
-
- db.AssertExistsAndLoadBean(t, &UserRedirect{
- LowerName: user.LowerName,
- RedirectUserID: user.ID,
- })
- db.AssertNotExistsBean(t, &UserRedirect{
- LowerName: "olduser1",
- RedirectUserID: user.ID,
- })
-}
-
-func TestNewUserRedirect3(t *testing.T) {
- // redirect for a previously-unredirected user
- assert.NoError(t, db.PrepareTestDatabase())
-
- user := db.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
- assert.NoError(t, newUserRedirect(db.GetEngine(db.DefaultContext), user.ID, user.Name, "newusername"))
-
- db.AssertExistsAndLoadBean(t, &UserRedirect{
- LowerName: user.LowerName,
- RedirectUserID: user.ID,
- })
-}
diff --git a/models/user_test.go b/models/user_test.go
index 3f3536dafa..58044d1e99 100644
--- a/models/user_test.go
+++ b/models/user_test.go
@@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/login"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
@@ -358,7 +359,7 @@ func TestCreateUserInvalidEmail(t *testing.T) {
err := CreateUser(user)
assert.Error(t, err)
- assert.True(t, IsErrEmailInvalid(err))
+ assert.True(t, user_model.IsErrEmailInvalid(err))
}
func TestCreateUser_Issue5882(t *testing.T) {
@@ -511,3 +512,50 @@ func TestUpdateUser(t *testing.T) {
user.Email = "no mail@mail.org"
assert.Error(t, UpdateUser(user))
}
+
+func TestNewUserRedirect(t *testing.T) {
+ // redirect to a completely new name
+ assert.NoError(t, db.PrepareTestDatabase())
+
+ user := db.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
+ assert.NoError(t, user_model.NewUserRedirect(db.DefaultContext, user.ID, user.Name, "newusername"))
+
+ db.AssertExistsAndLoadBean(t, &user_model.Redirect{
+ LowerName: user.LowerName,
+ RedirectUserID: user.ID,
+ })
+ db.AssertExistsAndLoadBean(t, &user_model.Redirect{
+ LowerName: "olduser1",
+ RedirectUserID: user.ID,
+ })
+}
+
+func TestNewUserRedirect2(t *testing.T) {
+ // redirect to previously used name
+ assert.NoError(t, db.PrepareTestDatabase())
+
+ user := db.AssertExistsAndLoadBean(t, &User{ID: 1}).(*User)
+ assert.NoError(t, user_model.NewUserRedirect(db.DefaultContext, user.ID, user.Name, "olduser1"))
+
+ db.AssertExistsAndLoadBean(t, &user_model.Redirect{
+ LowerName: user.LowerName,
+ RedirectUserID: user.ID,
+ })
+ db.AssertNotExistsBean(t, &user_model.Redirect{
+ LowerName: "olduser1",
+ RedirectUserID: user.ID,
+ })
+}
+
+func TestNewUserRedirect3(t *testing.T) {
+ // redirect for a previously-unredirected user
+ assert.NoError(t, db.PrepareTestDatabase())
+
+ user := db.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
+ assert.NoError(t, user_model.NewUserRedirect(db.DefaultContext, user.ID, user.Name, "newusername"))
+
+ db.AssertExistsAndLoadBean(t, &user_model.Redirect{
+ LowerName: user.LowerName,
+ RedirectUserID: user.ID,
+ })
+}