user: introduce "invite" emails
Invite emails are essentially just reset password emails with a different template (though this can and probably will change (slightly) in the near future)
This commit is contained in:
parent
9172f54fc2
commit
2ef1b4beff
7 changed files with 63 additions and 4 deletions
|
@ -519,6 +519,7 @@ func TestCreateUser(t *testing.T) {
|
|||
cantEmail: tt.cantEmail,
|
||||
lastEmail: tt.req.User.Email,
|
||||
lastClientID: "XXX",
|
||||
lastWasInvite: true,
|
||||
lastRedirectURL: *urlParsed,
|
||||
}
|
||||
if diff := pretty.Compare(wantEmalier, f.emailer); diff != "" {
|
||||
|
@ -578,6 +579,7 @@ type testEmailer struct {
|
|||
lastEmail string
|
||||
lastClientID string
|
||||
lastRedirectURL url.URL
|
||||
lastWasInvite bool
|
||||
}
|
||||
|
||||
// SendResetPasswordEmail returns resetPasswordURL when it can't email, mimicking the behavior of the real UserEmailer.
|
||||
|
@ -585,6 +587,20 @@ func (t *testEmailer) SendResetPasswordEmail(email string, redirectURL url.URL,
|
|||
t.lastEmail = email
|
||||
t.lastRedirectURL = redirectURL
|
||||
t.lastClientID = clientID
|
||||
t.lastWasInvite = false
|
||||
|
||||
var retURL *url.URL
|
||||
if t.cantEmail {
|
||||
retURL = &testResetPasswordURL
|
||||
}
|
||||
return retURL, nil
|
||||
}
|
||||
|
||||
func (t *testEmailer) SendInviteEmail(email string, redirectURL url.URL, clientID string) (*url.URL, error) {
|
||||
t.lastEmail = email
|
||||
t.lastRedirectURL = redirectURL
|
||||
t.lastClientID = clientID
|
||||
t.lastWasInvite = true
|
||||
|
||||
var retURL *url.URL
|
||||
if t.cantEmail {
|
||||
|
|
|
@ -102,7 +102,7 @@ func TestSendResetPasswordEmailHandler(t *testing.T) {
|
|||
wantEmailer: &testEmailer{
|
||||
to: str("Email-1@example.com"),
|
||||
from: "noreply@example.com",
|
||||
subject: "Reset your password.",
|
||||
subject: "Reset Your Password",
|
||||
},
|
||||
wantPRUserID: "ID-1",
|
||||
wantPRRedirect: &testRedirectURL,
|
||||
|
@ -138,7 +138,7 @@ func TestSendResetPasswordEmailHandler(t *testing.T) {
|
|||
wantEmailer: &testEmailer{
|
||||
to: str("Email-1@example.com"),
|
||||
from: "noreply@example.com",
|
||||
subject: "Reset your password.",
|
||||
subject: "Reset Your Password",
|
||||
},
|
||||
wantPRPassword: "password",
|
||||
wantPRUserID: "ID-1",
|
||||
|
|
7
static/email/invite.html
Normal file
7
static/email/invite.html
Normal file
|
@ -0,0 +1,7 @@
|
|||
<html>
|
||||
<body>
|
||||
Welcome to Dex! Click below to set your password:
|
||||
|
||||
<a href="{{ .link }}">Set Password</a>
|
||||
</body>
|
||||
</html>
|
4
static/email/invite.txt
Normal file
4
static/email/invite.txt
Normal file
|
@ -0,0 +1,4 @@
|
|||
Welcome to Dex! Click below to set your password:
|
||||
|
||||
Link:
|
||||
{{ .link }}
|
|
@ -89,6 +89,7 @@ type UsersAPI struct {
|
|||
|
||||
type Emailer interface {
|
||||
SendResetPasswordEmail(string, url.URL, string) (*url.URL, error)
|
||||
SendInviteEmail(string, url.URL, string) (*url.URL, error)
|
||||
}
|
||||
|
||||
type Creds struct {
|
||||
|
@ -169,7 +170,7 @@ func (u *UsersAPI) CreateUser(creds Creds, usr schema.User, redirURL url.URL) (s
|
|||
|
||||
usr = userToSchemaUser(userUser)
|
||||
|
||||
url, err := u.emailer.SendResetPasswordEmail(usr.Email, validRedirURL, creds.ClientID)
|
||||
url, err := u.emailer.SendInviteEmail(usr.Email, validRedirURL, creds.ClientID)
|
||||
|
||||
// An email is sent only if we don't get a link and there's no error.
|
||||
emailSent := err == nil && url == nil
|
||||
|
|
|
@ -20,13 +20,23 @@ type testEmailer struct {
|
|||
lastEmail string
|
||||
lastClientID string
|
||||
lastRedirectURL url.URL
|
||||
lastWasInvite bool
|
||||
}
|
||||
|
||||
// SendResetPasswordEmail returns resetPasswordURL when it can't email, mimicking the behavior of the real UserEmailer.
|
||||
func (t *testEmailer) SendResetPasswordEmail(email string, redirectURL url.URL, clientID string) (*url.URL, error) {
|
||||
return t.sendEmail(email, redirectURL, clientID, false)
|
||||
}
|
||||
|
||||
func (t *testEmailer) SendInviteEmail(email string, redirectURL url.URL, clientID string) (*url.URL, error) {
|
||||
return t.sendEmail(email, redirectURL, clientID, true)
|
||||
}
|
||||
|
||||
func (t *testEmailer) sendEmail(email string, redirectURL url.URL, clientID string, invite bool) (*url.URL, error) {
|
||||
t.lastEmail = email
|
||||
t.lastRedirectURL = redirectURL
|
||||
t.lastClientID = clientID
|
||||
t.lastWasInvite = invite
|
||||
|
||||
var retURL *url.URL
|
||||
if t.cantEmail {
|
||||
|
@ -369,6 +379,7 @@ func TestCreateUser(t *testing.T) {
|
|||
lastEmail: tt.usr.Email,
|
||||
lastClientID: tt.creds.ClientID,
|
||||
lastRedirectURL: tt.redirURL,
|
||||
lastWasInvite: true,
|
||||
}
|
||||
if diff := pretty.Compare(wantEmalier, emailer); diff != "" {
|
||||
t.Errorf("case %d: Compare(want, got) = %v", i,
|
||||
|
|
|
@ -53,6 +53,16 @@ func NewUserEmailer(ur user.UserRepo,
|
|||
// This method DOES NOT check for client ID, redirect URL validity - it is expected that upstream users have already done so.
|
||||
// If there is no emailer is configured, the URL of the aforementioned link is returned, otherwise nil is returned.
|
||||
func (u *UserEmailer) SendResetPasswordEmail(email string, redirectURL url.URL, clientID string) (*url.URL, error) {
|
||||
return u.sendResetPasswordOrInviteEmail(email, redirectURL, clientID, false)
|
||||
}
|
||||
|
||||
// SendInviteEmail is exactly the same as SendResetPasswordEmail, except that it uses the invite template and subject name.
|
||||
// In the near future, invite emails might diverge further.
|
||||
func (u *UserEmailer) SendInviteEmail(email string, redirectURL url.URL, clientID string) (*url.URL, error) {
|
||||
return u.sendResetPasswordOrInviteEmail(email, redirectURL, clientID, true)
|
||||
}
|
||||
|
||||
func (u *UserEmailer) sendResetPasswordOrInviteEmail(email string, redirectURL url.URL, clientID string, invite bool) (*url.URL, error) {
|
||||
usr, err := u.ur.GetByEmail(nil, email)
|
||||
if err == user.ErrorNotFound {
|
||||
log.Errorf("No Such user for email: %q", email)
|
||||
|
@ -95,8 +105,17 @@ func (u *UserEmailer) SendResetPasswordEmail(email string, redirectURL url.URL,
|
|||
q.Set("token", token)
|
||||
resetURL.RawQuery = q.Encode()
|
||||
|
||||
var tmplName, subj string
|
||||
if invite {
|
||||
tmplName = "invite"
|
||||
subj = "Activate Your Account"
|
||||
} else {
|
||||
tmplName = "password-reset"
|
||||
subj = "Reset Your Password"
|
||||
}
|
||||
|
||||
if u.emailer != nil {
|
||||
err = u.emailer.SendMail(u.fromAddress, "Reset your password.", "password-reset",
|
||||
err = u.emailer.SendMail(u.fromAddress, subj, tmplName,
|
||||
map[string]interface{}{
|
||||
"email": usr.Email,
|
||||
"link": resetURL.String(),
|
||||
|
@ -107,6 +126,7 @@ func (u *UserEmailer) SendResetPasswordEmail(email string, redirectURL url.URL,
|
|||
return nil, err
|
||||
}
|
||||
return &resetURL, nil
|
||||
|
||||
}
|
||||
|
||||
// SendEmailVerification sends an email to the user with the given userID containing a link which when visited marks the user as having had their email verified.
|
||||
|
|
Reference in a new issue