From 99599c099f818ec7e0c41974f774d145170048a5 Mon Sep 17 00:00:00 2001 From: Peter Smit Date: Wed, 17 Dec 2014 10:26:19 +0200 Subject: [PATCH] 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. --- models/models.go | 2 +- models/user.go | 49 ++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/models/models.go b/models/models.go index 92849f585..677f9ba9d 100644 --- a/models/models.go +++ b/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() { diff --git a/models/user.go b/models/user.go index 7e6a6c824..08710763d 100644 --- a/models/user.go +++ b/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.