mirror of
https://github.com/dnote/dnote
synced 2026-03-14 22:45:50 +01:00
Create verification token
This commit is contained in:
parent
f2873075d3
commit
9c1c812ea1
5 changed files with 129 additions and 4 deletions
|
|
@ -38,8 +38,9 @@ func NewWebRoutes(a *app.App, c *Controllers) []Route {
|
|||
{"GET", "/password-reset", c.Users.PasswordResetView.ServeHTTP, true},
|
||||
{"PATCH", "/password-reset", c.Users.PasswordReset, true},
|
||||
{"GET", "/password-reset/{token}", c.Users.PasswordResetConfirm, true},
|
||||
{"GET", "/verify-email", mw.Auth(a, c.Users.VerifyEmail, redirectGuest), true},
|
||||
{"POST", "/reset-token", c.Users.CreateResetToken, true},
|
||||
{"POST", "/verification-token", mw.Auth(a, c.Users.CreateEmailVerificationToken, redirectGuest), true},
|
||||
{"GET", "/verify-email", mw.Auth(a, c.Users.VerifyEmail, redirectGuest), true},
|
||||
{"PATCH", "/account/profile", mw.Auth(a, c.Users.ProfileUpdate, nil), true},
|
||||
{"PATCH", "/account/password", mw.Auth(a, c.Users.PasswordUpdate, nil), true},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/dnote/dnote/pkg/server/database"
|
||||
"github.com/dnote/dnote/pkg/server/helpers"
|
||||
"github.com/dnote/dnote/pkg/server/log"
|
||||
"github.com/dnote/dnote/pkg/server/mailer"
|
||||
"github.com/dnote/dnote/pkg/server/token"
|
||||
"github.com/dnote/dnote/pkg/server/views"
|
||||
"github.com/gorilla/mux"
|
||||
|
|
@ -666,3 +667,51 @@ func (u *Users) VerifyEmail(w http.ResponseWriter, r *http.Request) {
|
|||
setSessionCookie(w, session.Key, session.ExpiresAt)
|
||||
http.Redirect(w, r, "/", http.StatusFound)
|
||||
}
|
||||
|
||||
func (u *Users) CreateEmailVerificationToken(w http.ResponseWriter, r *http.Request) {
|
||||
vd := views.Data{}
|
||||
|
||||
user := context.User(r.Context())
|
||||
if user == nil {
|
||||
handleHTMLError(w, r, app.ErrLoginRequired, "No authenticated user found", u.EmailVerificationView, vd)
|
||||
return
|
||||
}
|
||||
|
||||
var account database.Account
|
||||
err := u.app.DB.Where("user_id = ?", user.ID).First(&account).Error
|
||||
if err != nil {
|
||||
handleHTMLError(w, r, err, "finding account", u.EmailVerificationView, vd)
|
||||
return
|
||||
}
|
||||
|
||||
if account.EmailVerified {
|
||||
handleHTMLError(w, r, app.ErrEmailAlreadyVerified, "email is already verified.", u.EmailVerificationView, vd)
|
||||
return
|
||||
}
|
||||
if account.Email.String == "" {
|
||||
handleHTMLError(w, r, app.ErrEmailRequired, "email is empty.", u.EmailVerificationView, vd)
|
||||
return
|
||||
}
|
||||
|
||||
tok, err := token.Create(u.app.DB, account.UserID, database.TokenTypeEmailVerification)
|
||||
if err != nil {
|
||||
handleHTMLError(w, r, err, "saving token", u.EmailVerificationView, vd)
|
||||
return
|
||||
}
|
||||
|
||||
if err := u.app.SendVerificationEmail(account.Email.String, tok.Value); err != nil {
|
||||
if errors.Cause(err) == mailer.ErrSMTPNotConfigured {
|
||||
handleHTMLError(w, r, app.ErrInvalidSMTPConfig, "SMTP config is not configured correctly.", u.EmailVerificationView, vd)
|
||||
} else {
|
||||
handleHTMLError(w, r, err, "sending verification email", u.EmailVerificationView, vd)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
alert := views.Alert{
|
||||
Level: views.AlertLvlSuccess,
|
||||
Message: "Please check your email for the verification",
|
||||
}
|
||||
views.RedirectAlert(w, r, "/", http.StatusFound, alert)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1314,3 +1314,75 @@ func TestVerifyEmail(t *testing.T) {
|
|||
assert.Equal(t, token.UsedAt, (*time.Time)(nil), "token should have not been used")
|
||||
})
|
||||
}
|
||||
|
||||
func TestCreateVerificationToken(t *testing.T) {
|
||||
t.Run("success", func(t *testing.T) {
|
||||
defer testutils.ClearData(testutils.DB)
|
||||
|
||||
// Setup
|
||||
emailBackend := testutils.MockEmailbackendImplementation{}
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
EmailBackend: &emailBackend,
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
user := testutils.SetupUserData()
|
||||
testutils.SetupAccountData(user, "alice@example.com", "pass1234")
|
||||
|
||||
// Execute
|
||||
req := testutils.MakeReq(server.URL, "POST", "/verification-token", "")
|
||||
res := testutils.HTTPAuthDo(t, req, user)
|
||||
|
||||
// Test
|
||||
assert.StatusCodeEquals(t, res, http.StatusFound, "status code mismatch")
|
||||
|
||||
var account database.Account
|
||||
var token database.Token
|
||||
var tokenCount int
|
||||
testutils.MustExec(t, testutils.DB.Where("user_id = ?", user.ID).First(&account), "finding account")
|
||||
testutils.MustExec(t, testutils.DB.Where("user_id = ? AND type = ?", user.ID, database.TokenTypeEmailVerification).First(&token), "finding token")
|
||||
testutils.MustExec(t, testutils.DB.Model(&database.Token{}).Count(&tokenCount), "counting token")
|
||||
|
||||
assert.Equal(t, account.EmailVerified, false, "email_verified should not have been updated")
|
||||
assert.NotEqual(t, token.Value, "", "token Value mismatch")
|
||||
assert.Equal(t, tokenCount, 1, "token count mismatch")
|
||||
assert.Equal(t, token.UsedAt, (*time.Time)(nil), "token UsedAt mismatch")
|
||||
assert.Equal(t, len(emailBackend.Emails), 1, "email queue count mismatch")
|
||||
})
|
||||
|
||||
t.Run("already verified", func(t *testing.T) {
|
||||
defer testutils.ClearData(testutils.DB)
|
||||
// Setup
|
||||
server := MustNewServer(t, &app.App{
|
||||
Clock: clock.NewMock(),
|
||||
Config: config.Config{
|
||||
PageTemplateDir: "../views",
|
||||
},
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
user := testutils.SetupUserData()
|
||||
a := testutils.SetupAccountData(user, "alice@example.com", "pass1234")
|
||||
a.EmailVerified = true
|
||||
testutils.MustExec(t, testutils.DB.Save(&a), "preparing account")
|
||||
|
||||
// Execute
|
||||
req := testutils.MakeReq(server.URL, "POST", "/verification-token", "")
|
||||
res := testutils.HTTPAuthDo(t, req, user)
|
||||
|
||||
// Test
|
||||
assert.StatusCodeEquals(t, res, http.StatusConflict, "Status code mismatch")
|
||||
|
||||
var account database.Account
|
||||
var tokenCount int
|
||||
testutils.MustExec(t, testutils.DB.Where("user_id = ?", user.ID).First(&account), "finding account")
|
||||
testutils.MustExec(t, testutils.DB.Model(&database.Token{}).Count(&tokenCount), "counting token")
|
||||
|
||||
assert.Equal(t, account.EmailVerified, true, "email_verified should not have been updated")
|
||||
assert.Equal(t, tokenCount, 0, "token count mismatch")
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@
|
|||
</div>
|
||||
|
||||
<div class="setting-right">
|
||||
{{ if eq true false }} b{{end}}
|
||||
|
||||
{{if .EmailVerified}}
|
||||
Yes
|
||||
{{else}}
|
||||
|
|
|
|||
|
|
@ -128,11 +128,12 @@ func (v *View) Render(w http.ResponseWriter, r *http.Request, data *Data, status
|
|||
vd.Yield = map[string]interface{}{}
|
||||
}
|
||||
if vd.Account != nil {
|
||||
vd.Yield["Email"] = &vd.Account.Email.String
|
||||
vd.Yield["EmailVerified"] = &vd.Account.EmailVerified
|
||||
vd.Yield["Email"] = vd.Account.Email.String
|
||||
vd.Yield["EmailVerified"] = vd.Account.EmailVerified
|
||||
vd.Yield["EmailVerified"] = vd.Account.EmailVerified
|
||||
}
|
||||
if vd.User != nil {
|
||||
vd.Yield["Cloud"] = &vd.User.Cloud
|
||||
vd.Yield["Cloud"] = vd.User.Cloud
|
||||
}
|
||||
vd.Yield["CurrentPath"] = r.URL.Path
|
||||
vd.Yield["Standalone"] = buildinfo.Standalone
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue