Explorar o código

Add alternative email addresses to the model

A new struct is created named EmailAddress that contains alternative
email addresses for users. Also the email related methods; IsEmailUsed
and GetUserByEmail are updated.

DeleteUser deletes the extra email addresses and DeleteInactivateUsers
also deletes inactive accounts. This could be factored out, but should
do it for now.
Peter Smit %!s(int64=10) %!d(string=hai) anos
pai
achega
99599c099f
Modificáronse 2 ficheiros con 42 adicións e 9 borrados
  1. 1 1
      models/models.go
  2. 41 8
      models/user.go

+ 1 - 1
models/models.go

@@ -45,7 +45,7 @@ func init() {
 		new(Issue), new(Comment), new(Attachment), new(IssueUser), new(Label), new(Milestone),
 		new(Mirror), new(Release), new(LoginSource), new(Webhook),
 		new(UpdateTask), new(HookTask), new(Team), new(OrgUser), new(TeamUser),
-		new(Notice))
+		new(Notice), new(EmailAddress))
 }
 
 func LoadModelsConfig() {

+ 41 - 8
models/user.go

@@ -50,10 +50,11 @@ var (
 
 // User represents the object of individual and member of organization.
 type User struct {
-	Id          int64
-	LowerName   string `xorm:"UNIQUE NOT NULL"`
-	Name        string `xorm:"UNIQUE NOT NULL"`
-	FullName    string
+	Id        int64
+	LowerName string `xorm:"UNIQUE NOT NULL"`
+	Name      string `xorm:"UNIQUE NOT NULL"`
+	FullName  string
+	// Email is the primary email address (to be used for communication).
 	Email       string `xorm:"UNIQUE(s) NOT NULL"`
 	Passwd      string `xorm:"NOT NULL"`
 	LoginType   LoginType
@@ -93,6 +94,15 @@ type User struct {
 	Members     []*User `xorm:"-"`
 }
 
+// EmailAdresses is the list of all email addresses of a user. Can contain the
+// primary email address, but is not obligatory
+type EmailAddress struct {
+	Id          int64
+	OwnerId     int64  `xorm:"INDEX NOT NULL"`
+	Email       string `xorm:"UNIQUE NOT NULL"`
+	IsActivated bool
+}
+
 // DashboardLink returns the user dashboard page link.
 func (u *User) DashboardLink() string {
 	if u.IsOrganization() {
@@ -248,6 +258,9 @@ func IsEmailUsed(email string) (bool, error) {
 	if len(email) == 0 {
 		return false, nil
 	}
+	if used, err := x.Get(&EmailAddress{Email: email}); used || err != nil {
+		return used, err
+	}
 	return x.Get(&User{Email: email})
 }
 
@@ -488,6 +501,10 @@ func DeleteUser(u *User) error {
 	if _, err = x.Delete(&Access{UserName: u.LowerName}); err != nil {
 		return err
 	}
+	// Delete all alternative email addresses
+	if _, err = x.Delete(&EmailAddress{OwnerId: u.Id}); err != nil {
+		return err
+	}
 	// Delete all SSH keys.
 	keys := make([]*PublicKey, 0, 10)
 	if err = x.Find(&keys, &PublicKey{OwnerId: u.Id}); err != nil {
@@ -508,9 +525,12 @@ func DeleteUser(u *User) error {
 	return err
 }
 
-// DeleteInactivateUsers deletes all inactivate users.
+// DeleteInactivateUsers deletes all inactivate users and email addresses.
 func DeleteInactivateUsers() error {
 	_, err := x.Where("is_active=?", false).Delete(new(User))
+	if err == nil {
+		_, err = x.Delete(&EmailAddress{IsActivated: false})
+	}
 	return err
 }
 
@@ -629,14 +649,27 @@ func GetUserByEmail(email string) (*User, error) {
 	if len(email) == 0 {
 		return nil, ErrUserNotExist
 	}
+	// First try to find the user by primary email
 	user := &User{Email: strings.ToLower(email)}
 	has, err := x.Get(user)
 	if err != nil {
 		return nil, err
-	} else if !has {
-		return nil, ErrUserNotExist
 	}
-	return user, nil
+	if has {
+		return user, nil
+	}
+
+	// Otherwise, check in alternative list for activated email addresses
+	emailAddress := &EmailAddress{Email: strings.ToLower(email), IsActivated: true}
+	has, err = x.Get(emailAddress)
+	if err != nil {
+		return nil, err
+	}
+	if has {
+		return GetUserById(emailAddress.OwnerId)
+	}
+
+	return nil, ErrUserNotExist
 }
 
 // SearchUserByName returns given number of users whose name contains keyword.