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
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
"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"
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
}
// 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
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 {
}
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)
"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"
}
}
- 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) {
"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"
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 {
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)
}
})
}
- 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,
return fmt.Errorf("insert team-user relation: %v", err)
}
- return sess.Commit()
+ return committer.Commit()
}
// GetOrgByName returns organization by given name.
"strings"
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
)
case "anything":
return content, nil
case "email":
- emails, err := GetEmailAddresses(user.ID)
+ emails, err := user_model.GetEmailAddresses(user.ID)
if err != nil {
return "", err
}
"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"
)
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")
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
}
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
// 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),
return err
}
- return sess.Commit()
+ return committer.Commit()
}
func countUsers(e db.Engine) int64 {
}
// 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 {
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
}
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 {
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)
if err != nil {
return err
} else if has {
- return ErrEmailAlreadyUsed{u.Email}
+ return user_model.ErrEmailAlreadyUsed{
+ Email: u.Email,
+ }
}
return nil
}
}
u.Email = strings.ToLower(u.Email)
- return ValidateEmail(u.Email)
+ return user_model.ValidateEmail(u.Email)
}
func updateUser(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},
_, err = db.GetEngine(db.DefaultContext).
Where("is_activated = ?", false).
- Delete(new(EmailAddress))
+ Delete(new(user_model.EmailAddress))
return err
}
}
// 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
--- /dev/null
+// 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
+}
--- /dev/null
+// 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)
+}
--- /dev/null
+// 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",
+ )
+}
--- /dev/null
+// 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
+}
--- /dev/null
+// 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))
+}
--- /dev/null
+// 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.
+
+package models
+
+import (
+ "fmt"
+ "strings"
+
+ "code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
+ "code.gitea.io/gitea/modules/util"
+ "xorm.io/builder"
+)
+
+// 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 := updateActivation(sess, email, true); err != nil {
+ return err
+ }
+ return sess.Commit()
+}
+
+func updateActivation(e db.Engine, email *user_model.EmailAddress, activate bool) error {
+ user, err := getUserByID(e, email.UID)
+ if err != nil {
+ return err
+ }
+ if user.Rands, err = GetUserSalt(); err != nil {
+ return err
+ }
+ email.IsActivated = activate
+ if _, err := e.ID(email.ID).Cols("is_activated").Update(email); err != nil {
+ return err
+ }
+ return updateUserCols(e, user, "rands")
+}
+
+// MakeEmailPrimary sets primary email address of given user.
+func MakeEmailPrimary(email *user_model.EmailAddress) error {
+ has, err := db.GetEngine(db.DefaultContext).Get(email)
+ if err != nil {
+ return err
+ } else if !has {
+ return user_model.ErrEmailAddressNotExist{Email: email.Email}
+ }
+
+ if !email.IsActivated {
+ return user_model.ErrEmailNotActivated
+ }
+
+ user := &User{}
+ has, err = db.GetEngine(db.DefaultContext).ID(email.UID).Get(user)
+ if err != nil {
+ return err
+ } else if !has {
+ return ErrUserNotExist{email.UID, "", 0}
+ }
+
+ sess := db.NewSession(db.DefaultContext)
+ defer sess.Close()
+ if err = sess.Begin(); err != nil {
+ return err
+ }
+
+ // 1. Update user table
+ user.Email = email.Email
+ if _, err = sess.ID(user.ID).Cols("email").Update(user); err != nil {
+ return err
+ }
+
+ // 2. Update old primary email
+ if _, err = sess.Where("uid=? AND is_primary=?", email.UID, true).Cols("is_primary").Update(&user_model.EmailAddress{
+ IsPrimary: false,
+ }); err != nil {
+ return err
+ }
+
+ // 3. update new primary email
+ email.IsPrimary = true
+ if _, err = sess.ID(email.ID).Cols("is_primary").Update(email); err != nil {
+ return err
+ }
+
+ return sess.Commit()
+}
+
+// SearchEmailOrderBy is used to sort the results from SearchEmails()
+type SearchEmailOrderBy string
+
+func (s SearchEmailOrderBy) String() string {
+ return string(s)
+}
+
+// Strings for sorting result
+const (
+ SearchEmailOrderByEmail SearchEmailOrderBy = "email_address.lower_email ASC, email_address.is_primary DESC, email_address.id ASC"
+ SearchEmailOrderByEmailReverse SearchEmailOrderBy = "email_address.lower_email DESC, email_address.is_primary ASC, email_address.id DESC"
+ SearchEmailOrderByName SearchEmailOrderBy = "`user`.lower_name ASC, email_address.is_primary DESC, email_address.id ASC"
+ SearchEmailOrderByNameReverse SearchEmailOrderBy = "`user`.lower_name DESC, email_address.is_primary ASC, email_address.id DESC"
+)
+
+// SearchEmailOptions are options to search e-mail addresses for the admin panel
+type SearchEmailOptions struct {
+ db.ListOptions
+ Keyword string
+ SortType SearchEmailOrderBy
+ IsPrimary util.OptionalBool
+ IsActivated util.OptionalBool
+}
+
+// SearchEmailResult is an e-mail address found in the user or email_address table
+type SearchEmailResult struct {
+ UID int64
+ Email string
+ IsActivated bool
+ IsPrimary bool
+ // From User
+ Name string
+ FullName string
+}
+
+// SearchEmails takes options i.e. keyword and part of email name to search,
+// it returns results in given range and number of total results.
+func SearchEmails(opts *SearchEmailOptions) ([]*SearchEmailResult, int64, error) {
+ var cond builder.Cond = builder.Eq{"`user`.`type`": UserTypeIndividual}
+ if len(opts.Keyword) > 0 {
+ likeStr := "%" + strings.ToLower(opts.Keyword) + "%"
+ cond = cond.And(builder.Or(
+ builder.Like{"lower(`user`.full_name)", likeStr},
+ builder.Like{"`user`.lower_name", likeStr},
+ builder.Like{"email_address.lower_email", likeStr},
+ ))
+ }
+
+ switch {
+ case opts.IsPrimary.IsTrue():
+ cond = cond.And(builder.Eq{"email_address.is_primary": true})
+ case opts.IsPrimary.IsFalse():
+ cond = cond.And(builder.Eq{"email_address.is_primary": false})
+ }
+
+ switch {
+ case opts.IsActivated.IsTrue():
+ cond = cond.And(builder.Eq{"email_address.is_activated": true})
+ case opts.IsActivated.IsFalse():
+ cond = cond.And(builder.Eq{"email_address.is_activated": false})
+ }
+
+ count, err := db.GetEngine(db.DefaultContext).Join("INNER", "`user`", "`user`.ID = email_address.uid").
+ Where(cond).Count(new(user_model.EmailAddress))
+ if err != nil {
+ return nil, 0, fmt.Errorf("Count: %v", err)
+ }
+
+ orderby := opts.SortType.String()
+ if orderby == "" {
+ orderby = SearchEmailOrderByEmail.String()
+ }
+
+ opts.SetDefaultValues()
+
+ emails := make([]*SearchEmailResult, 0, opts.PageSize)
+ err = db.GetEngine(db.DefaultContext).Table("email_address").
+ Select("email_address.*, `user`.name, `user`.full_name").
+ Join("INNER", "`user`", "`user`.ID = email_address.uid").
+ Where(cond).
+ OrderBy(orderby).
+ Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).
+ Find(&emails)
+
+ return emails, count, err
+}
+
+// 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) {
+ 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 := user_model.EmailAddress{UID: userID, LowerEmail: strings.ToLower(email)}
+ if has, err := sess.Get(&addr); err != nil {
+ return err
+ } else if !has {
+ return fmt.Errorf("no such email: %d (%s)", userID, email)
+ }
+ if addr.IsActivated == activate {
+ // Already in the desired state; no action
+ return nil
+ }
+ if activate {
+ 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 user_model.ErrEmailAlreadyUsed{Email: email}
+ }
+ }
+ if err = updateActivation(sess, &addr, activate); err != nil {
+ return fmt.Errorf("unable to updateActivation() for %d:%s: %w", addr.ID, addr.Email, err)
+ }
+
+ // Activate/deactivate a user's primary email address and account
+ if addr.IsPrimary {
+ user := User{ID: userID, Email: email}
+ if has, err := sess.Get(&user); err != nil {
+ return err
+ } else if !has {
+ return fmt.Errorf("no user with ID: %d and Email: %s", userID, email)
+ }
+ // The user's activation state should be synchronized with the primary email
+ if user.IsActive != activate {
+ user.IsActive = activate
+ if user.Rands, err = GetUserSalt(); err != nil {
+ return fmt.Errorf("unable to generate salt: %v", err)
+ }
+ if err = updateUserCols(sess, &user, "is_active", "rands"); err != nil {
+ return fmt.Errorf("unable to updateUserCols() for user ID: %d: %v", userID, err)
+ }
+ }
+ }
+
+ return committer.Commit()
+}
--- /dev/null
+// 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.
+
+package models
+
+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 TestMakeEmailPrimary(t *testing.T) {
+ assert.NoError(t, db.PrepareTestDatabase())
+
+ email := &user_model.EmailAddress{
+ Email: "user567890@example.com",
+ }
+ err := MakeEmailPrimary(email)
+ assert.Error(t, err)
+ assert.EqualError(t, err, user_model.ErrEmailAddressNotExist{Email: email.Email}.Error())
+
+ email = &user_model.EmailAddress{
+ Email: "user11@example.com",
+ }
+ err = MakeEmailPrimary(email)
+ assert.Error(t, err)
+ assert.EqualError(t, err, user_model.ErrEmailNotActivated.Error())
+
+ email = &user_model.EmailAddress{
+ Email: "user9999999@example.com",
+ }
+ err = MakeEmailPrimary(email)
+ assert.Error(t, err)
+ assert.True(t, IsErrUserNotExist(err))
+
+ email = &user_model.EmailAddress{
+ Email: "user101@example.com",
+ }
+ err = MakeEmailPrimary(email)
+ assert.NoError(t, err)
+
+ user, _ := GetUserByID(int64(10))
+ assert.Equal(t, "user101@example.com", user.Email)
+}
+
+func TestActivate(t *testing.T) {
+ assert.NoError(t, db.PrepareTestDatabase())
+
+ email := &user_model.EmailAddress{
+ ID: int64(1),
+ UID: int64(1),
+ Email: "user11@example.com",
+ }
+ assert.NoError(t, ActivateEmail(email))
+
+ emails, _ := user_model.GetEmailAddresses(int64(1))
+ assert.Len(t, emails, 3)
+ assert.True(t, emails[0].IsActivated)
+ assert.True(t, emails[0].IsPrimary)
+ assert.False(t, emails[1].IsPrimary)
+ assert.True(t, emails[2].IsActivated)
+ assert.False(t, emails[2].IsPrimary)
+}
+
+func TestListEmails(t *testing.T) {
+ assert.NoError(t, db.PrepareTestDatabase())
+
+ // Must find all users and their emails
+ opts := &SearchEmailOptions{
+ ListOptions: db.ListOptions{
+ PageSize: 10000,
+ },
+ }
+ emails, count, err := SearchEmails(opts)
+ assert.NoError(t, err)
+ assert.NotEqual(t, int64(0), count)
+ assert.True(t, count > 5)
+
+ contains := func(match func(s *SearchEmailResult) bool) bool {
+ for _, v := range emails {
+ if match(v) {
+ return true
+ }
+ }
+ return false
+ }
+
+ assert.True(t, contains(func(s *SearchEmailResult) bool { return s.UID == 18 }))
+ // 'user3' is an organization
+ assert.False(t, contains(func(s *SearchEmailResult) bool { return s.UID == 3 }))
+
+ // Must find no records
+ opts = &SearchEmailOptions{Keyword: "NOTFOUND"}
+ emails, count, err = SearchEmails(opts)
+ assert.NoError(t, err)
+ assert.Equal(t, int64(0), count)
+
+ // Must find users 'user2', 'user28', etc.
+ opts = &SearchEmailOptions{Keyword: "user2"}
+ emails, count, err = SearchEmails(opts)
+ assert.NoError(t, err)
+ assert.NotEqual(t, int64(0), count)
+ assert.True(t, contains(func(s *SearchEmailResult) bool { return s.UID == 2 }))
+ assert.True(t, contains(func(s *SearchEmailResult) bool { return s.UID == 27 }))
+
+ // Must find only primary addresses (i.e. from the `user` table)
+ opts = &SearchEmailOptions{IsPrimary: util.OptionalBoolTrue}
+ emails, count, err = SearchEmails(opts)
+ assert.NoError(t, err)
+ assert.True(t, contains(func(s *SearchEmailResult) bool { return s.IsPrimary }))
+ assert.False(t, contains(func(s *SearchEmailResult) bool { return !s.IsPrimary }))
+
+ // Must find only inactive addresses (i.e. not validated)
+ opts = &SearchEmailOptions{IsActivated: util.OptionalBoolFalse}
+ emails, count, err = SearchEmails(opts)
+ assert.NoError(t, err)
+ assert.True(t, contains(func(s *SearchEmailResult) bool { return !s.IsActivated }))
+ assert.False(t, contains(func(s *SearchEmailResult) bool { return s.IsActivated }))
+
+ // Must find more than one page, but retrieve only one
+ opts = &SearchEmailOptions{
+ ListOptions: db.ListOptions{
+ PageSize: 5,
+ Page: 1,
+ },
+ }
+ emails, count, err = SearchEmails(opts)
+ assert.NoError(t, err)
+ assert.Len(t, emails, 5)
+ assert.Greater(t, count, int64(len(emails)))
+}
+++ /dev/null
-// 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 models
-
-import (
- "fmt"
- "net/mail"
- "strings"
-
- "code.gitea.io/gitea/models/db"
- "code.gitea.io/gitea/modules/log"
- "code.gitea.io/gitea/modules/setting"
- "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 {
- sess := db.NewSession(db.DefaultContext)
- defer sess.Close()
- if err := sess.Begin(); err != nil {
- return err
- }
- if err := email.updateActivation(sess, true); err != nil {
- return err
- }
- return sess.Commit()
-}
-
-func (email *EmailAddress) updateActivation(e db.Engine, activate bool) error {
- user, err := getUserByID(e, email.UID)
- if err != nil {
- return err
- }
- if user.Rands, err = GetUserSalt(); err != nil {
- return err
- }
- email.IsActivated = activate
- if _, err := e.ID(email.ID).Cols("is_activated").Update(email); err != nil {
- return err
- }
- 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 {
- has, err := db.GetEngine(db.DefaultContext).Get(email)
- if err != nil {
- return err
- } else if !has {
- return ErrEmailAddressNotExist{Email: email.Email}
- }
-
- if !email.IsActivated {
- return ErrEmailNotActivated
- }
-
- user := &User{}
- has, err = db.GetEngine(db.DefaultContext).ID(email.UID).Get(user)
- if err != nil {
- return err
- } else if !has {
- return ErrUserNotExist{email.UID, "", 0}
- }
-
- sess := db.NewSession(db.DefaultContext)
- defer sess.Close()
- if err = sess.Begin(); err != nil {
- return err
- }
-
- // 1. Update user table
- user.Email = email.Email
- if _, err = sess.ID(user.ID).Cols("email").Update(user); err != nil {
- return err
- }
-
- // 2. Update old primary email
- if _, err = sess.Where("uid=? AND is_primary=?", email.UID, true).Cols("is_primary").Update(&EmailAddress{
- IsPrimary: false,
- }); err != nil {
- return err
- }
-
- // 3. update new primary email
- email.IsPrimary = true
- if _, err = sess.ID(email.ID).Cols("is_primary").Update(email); err != nil {
- return err
- }
-
- return sess.Commit()
-}
-
-// SearchEmailOrderBy is used to sort the results from SearchEmails()
-type SearchEmailOrderBy string
-
-func (s SearchEmailOrderBy) String() string {
- return string(s)
-}
-
-// Strings for sorting result
-const (
- SearchEmailOrderByEmail SearchEmailOrderBy = "email_address.lower_email ASC, email_address.is_primary DESC, email_address.id ASC"
- SearchEmailOrderByEmailReverse SearchEmailOrderBy = "email_address.lower_email DESC, email_address.is_primary ASC, email_address.id DESC"
- SearchEmailOrderByName SearchEmailOrderBy = "`user`.lower_name ASC, email_address.is_primary DESC, email_address.id ASC"
- SearchEmailOrderByNameReverse SearchEmailOrderBy = "`user`.lower_name DESC, email_address.is_primary ASC, email_address.id DESC"
-)
-
-// SearchEmailOptions are options to search e-mail addresses for the admin panel
-type SearchEmailOptions struct {
- db.ListOptions
- Keyword string
- SortType SearchEmailOrderBy
- IsPrimary util.OptionalBool
- IsActivated util.OptionalBool
-}
-
-// SearchEmailResult is an e-mail address found in the user or email_address table
-type SearchEmailResult struct {
- UID int64
- Email string
- IsActivated bool
- IsPrimary bool
- // From User
- Name string
- FullName string
-}
-
-// SearchEmails takes options i.e. keyword and part of email name to search,
-// it returns results in given range and number of total results.
-func SearchEmails(opts *SearchEmailOptions) ([]*SearchEmailResult, int64, error) {
- var cond builder.Cond = builder.Eq{"`user`.`type`": UserTypeIndividual}
- if len(opts.Keyword) > 0 {
- likeStr := "%" + strings.ToLower(opts.Keyword) + "%"
- cond = cond.And(builder.Or(
- builder.Like{"lower(`user`.full_name)", likeStr},
- builder.Like{"`user`.lower_name", likeStr},
- builder.Like{"email_address.lower_email", likeStr},
- ))
- }
-
- switch {
- case opts.IsPrimary.IsTrue():
- cond = cond.And(builder.Eq{"email_address.is_primary": true})
- case opts.IsPrimary.IsFalse():
- cond = cond.And(builder.Eq{"email_address.is_primary": false})
- }
-
- switch {
- case opts.IsActivated.IsTrue():
- cond = cond.And(builder.Eq{"email_address.is_activated": true})
- case opts.IsActivated.IsFalse():
- cond = cond.And(builder.Eq{"email_address.is_activated": false})
- }
-
- count, err := db.GetEngine(db.DefaultContext).Join("INNER", "`user`", "`user`.ID = email_address.uid").
- Where(cond).Count(new(EmailAddress))
- if err != nil {
- return nil, 0, fmt.Errorf("Count: %v", err)
- }
-
- orderby := opts.SortType.String()
- if orderby == "" {
- orderby = SearchEmailOrderByEmail.String()
- }
-
- opts.SetDefaultValues()
-
- emails := make([]*SearchEmailResult, 0, opts.PageSize)
- err = db.GetEngine(db.DefaultContext).Table("email_address").
- Select("email_address.*, `user`.name, `user`.full_name").
- Join("INNER", "`user`", "`user`.ID = email_address.uid").
- Where(cond).
- OrderBy(orderby).
- Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).
- Find(&emails)
-
- return emails, count, err
-}
-
-// 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 {
- return err
- }
-
- // 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)}
- if has, err := sess.Get(&addr); err != nil {
- return err
- } else if !has {
- return fmt.Errorf("no such email: %d (%s)", userID, email)
- }
- if addr.IsActivated == activate {
- // Already in the desired state; no action
- return nil
- }
- if activate {
- if used, err := isEmailActive(sess, email, addr.ID); err != nil {
- return fmt.Errorf("unable to check isEmailActive() for %s: %v", email, err)
- } else if used {
- return ErrEmailAlreadyUsed{Email: email}
- }
- }
- if err = addr.updateActivation(sess, activate); err != nil {
- return fmt.Errorf("unable to updateActivation() for %d:%s: %w", addr.ID, addr.Email, err)
- }
-
- // Activate/deactivate a user's primary email address and account
- if addr.IsPrimary {
- user := User{ID: userID, Email: email}
- if has, err := sess.Get(&user); err != nil {
- return err
- } else if !has {
- return fmt.Errorf("no user with ID: %d and Email: %s", userID, email)
- }
- // The user's activation state should be synchronized with the primary email
- if user.IsActive != activate {
- user.IsActive = activate
- if user.Rands, err = GetUserSalt(); err != nil {
- return fmt.Errorf("unable to generate salt: %v", err)
- }
- if err = updateUserCols(sess, &user, "is_active", "rands"); err != nil {
- return fmt.Errorf("unable to updateUserCols() for user ID: %d: %v", userID, err)
- }
- }
- }
-
- return sess.Commit()
-}
+++ /dev/null
-// 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 models
-
-import (
- "testing"
-
- "code.gitea.io/gitea/models/db"
- "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: "user567890@example.com",
- }
- err := MakeEmailPrimary(email)
- assert.Error(t, err)
- assert.EqualError(t, err, ErrEmailAddressNotExist{email.Email}.Error())
-
- email = &EmailAddress{
- Email: "user11@example.com",
- }
- err = MakeEmailPrimary(email)
- assert.Error(t, err)
- assert.EqualError(t, err, ErrEmailNotActivated.Error())
-
- email = &EmailAddress{
- Email: "user9999999@example.com",
- }
- err = MakeEmailPrimary(email)
- assert.Error(t, err)
- assert.True(t, IsErrUserNotExist(err))
-
- email = &EmailAddress{
- Email: "user101@example.com",
- }
- err = MakeEmailPrimary(email)
- assert.NoError(t, err)
-
- user, _ := GetUserByID(int64(10))
- assert.Equal(t, "user101@example.com", user.Email)
-}
-
-func TestActivate(t *testing.T) {
- assert.NoError(t, db.PrepareTestDatabase())
-
- email := &EmailAddress{
- ID: int64(1),
- UID: int64(1),
- Email: "user11@example.com",
- }
- assert.NoError(t, email.Activate())
-
- emails, _ := GetEmailAddresses(int64(1))
- assert.Len(t, emails, 3)
- assert.True(t, emails[0].IsActivated)
- assert.True(t, emails[0].IsPrimary)
- assert.False(t, emails[1].IsPrimary)
- assert.True(t, emails[2].IsActivated)
- assert.False(t, emails[2].IsPrimary)
-}
-
-func TestListEmails(t *testing.T) {
- assert.NoError(t, db.PrepareTestDatabase())
-
- // Must find all users and their emails
- opts := &SearchEmailOptions{
- ListOptions: db.ListOptions{
- PageSize: 10000,
- },
- }
- emails, count, err := SearchEmails(opts)
- assert.NoError(t, err)
- assert.NotEqual(t, int64(0), count)
- assert.True(t, count > 5)
-
- contains := func(match func(s *SearchEmailResult) bool) bool {
- for _, v := range emails {
- if match(v) {
- return true
- }
- }
- return false
- }
-
- assert.True(t, contains(func(s *SearchEmailResult) bool { return s.UID == 18 }))
- // 'user3' is an organization
- assert.False(t, contains(func(s *SearchEmailResult) bool { return s.UID == 3 }))
-
- // Must find no records
- opts = &SearchEmailOptions{Keyword: "NOTFOUND"}
- emails, count, err = SearchEmails(opts)
- assert.NoError(t, err)
- assert.Equal(t, int64(0), count)
-
- // Must find users 'user2', 'user28', etc.
- opts = &SearchEmailOptions{Keyword: "user2"}
- emails, count, err = SearchEmails(opts)
- assert.NoError(t, err)
- assert.NotEqual(t, int64(0), count)
- assert.True(t, contains(func(s *SearchEmailResult) bool { return s.UID == 2 }))
- assert.True(t, contains(func(s *SearchEmailResult) bool { return s.UID == 27 }))
-
- // Must find only primary addresses (i.e. from the `user` table)
- opts = &SearchEmailOptions{IsPrimary: util.OptionalBoolTrue}
- emails, count, err = SearchEmails(opts)
- assert.NoError(t, err)
- assert.True(t, contains(func(s *SearchEmailResult) bool { return s.IsPrimary }))
- assert.False(t, contains(func(s *SearchEmailResult) bool { return !s.IsPrimary }))
-
- // Must find only inactive addresses (i.e. not validated)
- opts = &SearchEmailOptions{IsActivated: util.OptionalBoolFalse}
- emails, count, err = SearchEmails(opts)
- assert.NoError(t, err)
- assert.True(t, contains(func(s *SearchEmailResult) bool { return !s.IsActivated }))
- assert.False(t, contains(func(s *SearchEmailResult) bool { return s.IsActivated }))
-
- // Must find more than one page, but retrieve only one
- opts = &SearchEmailOptions{
- ListOptions: db.ListOptions{
- PageSize: 5,
- Page: 1,
- },
- }
- emails, count, err = SearchEmails(opts)
- assert.NoError(t, err)
- assert.Len(t, emails, 5)
- assert.Greater(t, count, int64(len(emails)))
-}
+++ /dev/null
-// 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
-}
+++ /dev/null
-// 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,
- })
-}
"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"
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) {
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,
+ })
+}
"strings"
"code.gitea.io/gitea/models"
+ user_model "code.gitea.io/gitea/models/user"
)
// Organization contains organization context
ctx.Org.Organization, err = models.GetUserByName(orgName)
if err != nil {
if models.IsErrUserNotExist(err) {
- redirectUserID, err := models.LookupUserRedirect(orgName)
+ redirectUserID, err := user_model.LookupUserRedirect(orgName)
if err == nil {
RedirectToUser(ctx, orgName, redirectUserID)
- } else if models.IsErrUserRedirectNotExist(err) {
+ } else if user_model.IsErrUserRedirectNotExist(err) {
ctx.NotFound("GetUserByName", err)
} else {
ctx.ServerError("LookupUserRedirect", err)
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/login"
"code.gitea.io/gitea/models/unit"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/models/webhook"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
)
// ToEmail convert models.EmailAddress to api.Email
-func ToEmail(email *models.EmailAddress) *api.Email {
+func ToEmail(email *user_model.EmailAddress) *api.Email {
return &api.Email{
Email: email.Email,
Verified: email.IsActivated,
}
// ToGPGKeyEmail convert models.EmailAddress to api.GPGKeyEmail
-func ToGPGKeyEmail(email *models.EmailAddress) *api.GPGKeyEmail {
+func ToGPGKeyEmail(email *user_model.EmailAddress) *api.GPGKeyEmail {
return &api.GPGKeyEmail{
Email: email.Email,
Verified: email.IsActivated,
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/login"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/convert"
"code.gitea.io/gitea/modules/log"
if err := models.CreateUser(u, overwriteDefault); err != nil {
if models.IsErrUserAlreadyExist(err) ||
- models.IsErrEmailAlreadyUsed(err) ||
+ user_model.IsErrEmailAlreadyUsed(err) ||
models.IsErrNameReserved(err) ||
models.IsErrNameCharsNotAllowed(err) ||
- models.IsErrEmailInvalid(err) ||
+ user_model.IsErrEmailInvalid(err) ||
models.IsErrNamePatternNotAllowed(err) {
ctx.Error(http.StatusUnprocessableEntity, "", err)
} else {
}
if err := models.UpdateUser(u); err != nil {
- if models.IsErrEmailAlreadyUsed(err) || models.IsErrEmailInvalid(err) {
+ if user_model.IsErrEmailAlreadyUsed(err) || user_model.IsErrEmailInvalid(err) {
ctx.Error(http.StatusUnprocessableEntity, "", err)
} else {
ctx.Error(http.StatusInternalServerError, "UpdateUser", err)
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/unit"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
owner, err = models.GetUserByName(userName)
if err != nil {
if models.IsErrUserNotExist(err) {
- if redirectUserID, err := models.LookupUserRedirect(userName); err == nil {
+ if redirectUserID, err := user_model.LookupUserRedirect(userName); err == nil {
context.RedirectToUser(ctx.Context, userName, redirectUserID)
- } else if models.IsErrUserRedirectNotExist(err) {
+ } else if user_model.IsErrUserRedirectNotExist(err) {
ctx.NotFound("GetUserByName", err)
} else {
ctx.Error(http.StatusInternalServerError, "LookupUserRedirect", err)
ctx.Org.Organization, err = models.GetOrgByName(ctx.Params(":org"))
if err != nil {
if models.IsErrOrgNotExist(err) {
- redirectUserID, err := models.LookupUserRedirect(ctx.Params(":org"))
+ redirectUserID, err := user_model.LookupUserRedirect(ctx.Params(":org"))
if err == nil {
context.RedirectToUser(ctx.Context, ctx.Params(":org"), redirectUserID)
- } else if models.IsErrUserRedirectNotExist(err) {
+ } else if user_model.IsErrUserRedirectNotExist(err) {
ctx.NotFound("GetOrgByName", err)
} else {
ctx.Error(http.StatusInternalServerError, "LookupUserRedirect", err)
"fmt"
"net/http"
- "code.gitea.io/gitea/models"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/convert"
"code.gitea.io/gitea/modules/setting"
// "200":
// "$ref": "#/responses/EmailList"
- emails, err := models.GetEmailAddresses(ctx.User.ID)
+ emails, err := user_model.GetEmailAddresses(ctx.User.ID)
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetEmailAddresses", err)
return
return
}
- emails := make([]*models.EmailAddress, len(form.Emails))
+ emails := make([]*user_model.EmailAddress, len(form.Emails))
for i := range form.Emails {
- emails[i] = &models.EmailAddress{
+ emails[i] = &user_model.EmailAddress{
UID: ctx.User.ID,
Email: form.Emails[i],
IsActivated: !setting.Service.RegisterEmailConfirm,
}
}
- if err := models.AddEmailAddresses(emails); err != nil {
- if models.IsErrEmailAlreadyUsed(err) {
- ctx.Error(http.StatusUnprocessableEntity, "", "Email address has been used: "+err.(models.ErrEmailAlreadyUsed).Email)
- } else if models.IsErrEmailInvalid(err) {
- errMsg := fmt.Sprintf("Email address %s invalid", err.(models.ErrEmailInvalid).Email)
+ if err := user_model.AddEmailAddresses(emails); err != nil {
+ if user_model.IsErrEmailAlreadyUsed(err) {
+ ctx.Error(http.StatusUnprocessableEntity, "", "Email address has been used: "+err.(user_model.ErrEmailAlreadyUsed).Email)
+ } else if user_model.IsErrEmailInvalid(err) {
+ errMsg := fmt.Sprintf("Email address %s invalid", err.(user_model.ErrEmailInvalid).Email)
ctx.Error(http.StatusUnprocessableEntity, "", errMsg)
} else {
ctx.Error(http.StatusInternalServerError, "AddEmailAddresses", err)
return
}
- emails := make([]*models.EmailAddress, len(form.Emails))
+ emails := make([]*user_model.EmailAddress, len(form.Emails))
for i := range form.Emails {
- emails[i] = &models.EmailAddress{
+ emails[i] = &user_model.EmailAddress{
Email: form.Emails[i],
UID: ctx.User.ID,
}
}
- if err := models.DeleteEmailAddresses(emails); err != nil {
- if models.IsErrEmailAddressNotExist(err) {
+ if err := user_model.DeleteEmailAddresses(emails); err != nil {
+ if user_model.IsErrEmailAddressNotExist(err) {
ctx.Error(http.StatusNotFound, "DeleteEmailAddresses", err)
return
}
"net/http"
"code.gitea.io/gitea/models"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/context"
)
user, err := models.GetUserByName(username)
if err != nil {
if models.IsErrUserNotExist(err) {
- if redirectUserID, err2 := models.LookupUserRedirect(username); err2 == nil {
+ if redirectUserID, err2 := user_model.LookupUserRedirect(username); err2 == nil {
context.RedirectToUser(ctx.Context, username, redirectUserID)
} else {
ctx.NotFound("GetUserByName", err)
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
if err := models.ActivateUserEmail(uid, email, activate); err != nil {
log.Error("ActivateUserEmail(%v,%v,%v): %v", uid, email, activate, err)
- if models.IsErrEmailAlreadyUsed(err) {
+ if user_model.IsErrEmailAlreadyUsed(err) {
ctx.Flash.Error(ctx.Tr("admin.emails.duplicate_active"))
} else {
ctx.Flash.Error(ctx.Tr("admin.emails.not_updated", err))
"code.gitea.io/gitea/models"
"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/base"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
case models.IsErrUserAlreadyExist(err):
ctx.Data["Err_UserName"] = true
ctx.RenderWithErr(ctx.Tr("form.username_been_taken"), tplUserNew, &form)
- case models.IsErrEmailAlreadyUsed(err):
+ case user_model.IsErrEmailAlreadyUsed(err):
ctx.Data["Err_Email"] = true
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplUserNew, &form)
- case models.IsErrEmailInvalid(err):
+ case user_model.IsErrEmailInvalid(err):
ctx.Data["Err_Email"] = true
ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplUserNew, &form)
case models.IsErrNameReserved(err):
}
if err := models.UpdateUser(u); err != nil {
- if models.IsErrEmailAlreadyUsed(err) {
+ if user_model.IsErrEmailAlreadyUsed(err) {
ctx.Data["Err_Email"] = true
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplUserEdit, &form)
- } else if models.IsErrEmailInvalid(err) {
+ } else if user_model.IsErrEmailInvalid(err) {
ctx.Data["Err_Email"] = true
ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplUserEdit, &form)
} else {
"code.gitea.io/gitea/models"
"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/context"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
owner, err := models.GetUserByName(username)
if err != nil {
if models.IsErrUserNotExist(err) {
- if redirectUserID, err := models.LookupUserRedirect(username); err == nil {
+ if redirectUserID, err := user_model.LookupUserRedirect(username); err == nil {
context.RedirectToUser(ctx, username, redirectUserID)
} else {
ctx.NotFound(fmt.Sprintf("User %s does not exist", username), nil)
"code.gitea.io/gitea/models"
"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/base"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/eventsource"
if models.IsErrUserNotExist(err) {
ctx.RenderWithErr(ctx.Tr("form.username_password_incorrect"), tplSignIn, &form)
log.Info("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
- } else if models.IsErrEmailAlreadyUsed(err) {
+ } else if user_model.IsErrEmailAlreadyUsed(err) {
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplSignIn, &form)
log.Info("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
} else if models.IsErrUserProhibitLogin(err) {
// Optionally a template can be specified.
func createUserInContext(ctx *context.Context, tpl base.TplName, form interface{}, u *models.User, gothUser *goth.User, allowLink bool) (ok bool) {
if err := models.CreateUser(u); err != nil {
- if allowLink && (models.IsErrUserAlreadyExist(err) || models.IsErrEmailAlreadyUsed(err)) {
+ if allowLink && (models.IsErrUserAlreadyExist(err) || user_model.IsErrEmailAlreadyUsed(err)) {
if setting.OAuth2Client.AccountLinking == setting.OAuth2AccountLinkingAuto {
var user *models.User
user = &models.User{Name: u.Name}
case models.IsErrUserAlreadyExist(err):
ctx.Data["Err_UserName"] = true
ctx.RenderWithErr(ctx.Tr("form.username_been_taken"), tpl, form)
- case models.IsErrEmailAlreadyUsed(err):
+ case user_model.IsErrEmailAlreadyUsed(err):
ctx.Data["Err_Email"] = true
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tpl, form)
- case models.IsErrEmailInvalid(err):
+ case user_model.IsErrEmailInvalid(err):
ctx.Data["Err_Email"] = true
ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tpl, form)
case models.IsErrNameReserved(err):
// Verify code.
if email := models.VerifyActiveEmailCode(code, emailStr); email != nil {
- if err := email.Activate(); err != nil {
+ if err := models.ActivateEmail(email); err != nil {
ctx.ServerError("ActivateEmail", err)
}
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/markup/markdown"
user, err := models.GetUserByName(name)
if err != nil {
if models.IsErrUserNotExist(err) {
- if redirectUserID, err := models.LookupUserRedirect(name); err == nil {
+ if redirectUserID, err := user_model.LookupUserRedirect(name); err == nil {
context.RedirectToUser(ctx, name, redirectUserID)
} else {
ctx.NotFound("GetUserByName", err)
"time"
"code.gitea.io/gitea/models"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
// Make emailaddress primary.
if ctx.FormString("_method") == "PRIMARY" {
- if err := models.MakeEmailPrimary(&models.EmailAddress{ID: ctx.FormInt64("id")}); err != nil {
+ if err := models.MakeEmailPrimary(&user_model.EmailAddress{ID: ctx.FormInt64("id")}); err != nil {
ctx.ServerError("MakeEmailPrimary", err)
return
}
}
id := ctx.FormInt64("id")
- email, err := models.GetEmailAddressByID(ctx.User.ID, id)
+ email, err := user_model.GetEmailAddressByID(ctx.User.ID, id)
if err != nil {
log.Error("GetEmailAddressByID(%d,%d) error: %v", ctx.User.ID, id, err)
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
return
}
- email := &models.EmailAddress{
+ email := &user_model.EmailAddress{
UID: ctx.User.ID,
Email: form.Email,
IsActivated: !setting.Service.RegisterEmailConfirm,
}
- if err := models.AddEmailAddress(email); err != nil {
- if models.IsErrEmailAlreadyUsed(err) {
+ if err := user_model.AddEmailAddress(email); err != nil {
+ if user_model.IsErrEmailAlreadyUsed(err) {
loadAccountData(ctx)
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplSettingsAccount, &form)
return
- } else if models.IsErrEmailInvalid(err) {
+ } else if user_model.IsErrEmailInvalid(err) {
loadAccountData(ctx)
ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplSettingsAccount, &form)
// DeleteEmail response for delete user's email
func DeleteEmail(ctx *context.Context) {
- if err := models.DeleteEmailAddress(&models.EmailAddress{ID: ctx.FormInt64("id"), UID: ctx.User.ID}); err != nil {
+ if err := user_model.DeleteEmailAddress(&user_model.EmailAddress{ID: ctx.FormInt64("id"), UID: ctx.User.ID}); err != nil {
ctx.ServerError("DeleteEmail", err)
return
}
}
func loadAccountData(ctx *context.Context) {
- emlist, err := models.GetEmailAddresses(ctx.User.ID)
+ emlist, err := user_model.GetEmailAddresses(ctx.User.ID)
if err != nil {
ctx.ServerError("GetEmailAddresses", err)
return
}
type UserEmail struct {
- models.EmailAddress
+ user_model.EmailAddress
CanBePrimary bool
}
pendingActivation := ctx.Cache.IsExist("MailResendLimit_" + ctx.User.LowerName)
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
switch {
case models.IsErrUserAlreadyExist(err):
ctx.Flash.Error(ctx.Tr("form.username_been_taken"))
- case models.IsErrEmailAlreadyUsed(err):
+ case user_model.IsErrEmailAlreadyUsed(err):
ctx.Flash.Error(ctx.Tr("form.email_been_used"))
case models.IsErrNameReserved(err):
ctx.Flash.Error(ctx.Tr("user.form.name_reserved", newName))
ctx.User.KeepActivityPrivate = form.KeepActivityPrivate
ctx.User.Visibility = form.Visibility
if err := models.UpdateUserSetting(ctx.User); err != nil {
- if _, ok := err.(models.ErrEmailAlreadyUsed); ok {
+ if _, ok := err.(user_model.ErrEmailAlreadyUsed); ok {
ctx.Flash.Error(ctx.Tr("form.email_been_used"))
ctx.Redirect(setting.AppSubURL + "/user/settings")
return
"code.gitea.io/gitea/models"
"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/log"
// Register the sources
return nil, nil, err
}
if cnt > 1 {
- return nil, nil, models.ErrEmailAlreadyUsed{
+ return nil, nil, user_model.ErrEmailAlreadyUsed{
Email: user.Email,
}
}
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/login"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/auth/pam"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/services/mailer"
if idx > -1 {
username = pamLogin[:idx]
}
- if models.ValidateEmail(email) != nil {
+ if user_model.ValidateEmail(email) != nil {
if source.EmailDomain != "" {
email = fmt.Sprintf("%s@%s", username, source.EmailDomain)
} else {
email = fmt.Sprintf("%s@%s", username, setting.Service.NoReplyAddress)
}
- if models.ValidateEmail(email) != nil {
+ if user_model.ValidateEmail(email) != nil {
email = uuid.New().String() + "@localhost"
}
}
texttmpl "text/template"
"code.gitea.io/gitea/models"
+ user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/emoji"
"code.gitea.io/gitea/modules/log"
}
// SendActivateEmailMail sends confirmation email to confirm new email address
-func SendActivateEmailMail(u *models.User, email *models.EmailAddress) {
+func SendActivateEmailMail(u *models.User, email *user_model.EmailAddress) {
if setting.MailService == nil {
// No mail service configured
return