feat(07-03): add avatars, mail templates, and password-change command
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
112
mail_test.go
Normal file
112
mail_test.go
Normal file
@@ -0,0 +1,112 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/url"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.golem15.com/golem15/fonoteka/plugins/golem15/user/controllers"
|
||||
"git.golem15.com/golem15/fonoteka/plugins/golem15/user/models"
|
||||
"git.golem15.com/golem15/summercms/backpack"
|
||||
"git.golem15.com/golem15/summercms/postcard"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type recordingMail struct {
|
||||
inner postcard.Mailer
|
||||
msgs []postcard.Message
|
||||
}
|
||||
|
||||
func (r *recordingMail) Send(ctx context.Context, msg postcard.Message) error {
|
||||
r.msgs = append(r.msgs, msg)
|
||||
if r.inner == nil {
|
||||
return nil
|
||||
}
|
||||
return r.inner.Send(ctx, msg)
|
||||
}
|
||||
|
||||
func TestMail(t *testing.T) {
|
||||
app, gdb := sessionApp(t, "0s")
|
||||
disableRegisterThrottle(t, app)
|
||||
if err := app.Config.Set("golem15.user.activation.activate_mode", "user"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rec, mem := publishMemoryMail(t, app)
|
||||
|
||||
postRegister(t, app, "198.51.100.10", `{"email":"mail-pl@example.test","password":"correct-horse","name":"Ada","preferred_locale":"pl"}`)
|
||||
postRegister(t, app, "198.51.100.11", `{"email":"mail-en@example.test","password":"correct-horse","name":"Grace","preferred_locale":"en"}`)
|
||||
assertTemplate(t, rec, "golem15.user::mail.activate", "mail-pl@example.test")
|
||||
assertTemplate(t, rec, "golem15.user::mail.activate-en", "mail-en@example.test")
|
||||
for _, msg := range rec.msgs {
|
||||
if !strings.HasPrefix(msg.Template, "golem15.user::mail.activate") {
|
||||
continue
|
||||
}
|
||||
link, _ := msg.Vars["link"].(string)
|
||||
code, _ := msg.Vars["code"].(string)
|
||||
decoded, err := url.QueryUnescape(link)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if link == "" || code == "" || !strings.Contains(decoded, code) {
|
||||
t.Fatalf("activate vars template=%s link=%q code=%q", msg.Template, link, code)
|
||||
}
|
||||
}
|
||||
if len(mem.Messages()) < 2 {
|
||||
t.Fatalf("memory driver recorded %d messages", len(mem.Messages()))
|
||||
}
|
||||
|
||||
before := len(rec.msgs)
|
||||
postJSON(t, controllers.ForgotPassword(app), "/_user/api/v1/forgot-password", `{"email":"mail-pl@example.test"}`)
|
||||
postJSON(t, controllers.ForgotPassword(app), "/_user/api/v1/forgot-password", `{"email":"mail-en@example.test"}`)
|
||||
assertTemplate(t, rec, "golem15.user::mail.restore", "mail-pl@example.test")
|
||||
assertTemplate(t, rec, "golem15.user::mail.restore-en", "mail-en@example.test")
|
||||
if len(mem.Messages()) < before+2 {
|
||||
t.Fatalf("memory driver recorded %d messages after restore", len(mem.Messages()))
|
||||
}
|
||||
|
||||
softDelete(t, gdb, "react-pl@example.test", "pl")
|
||||
softDelete(t, gdb, "react-en@example.test", "en")
|
||||
postJSON(t, controllers.Login(app), "/_user/api/v1/login", `{"email":"react-pl@example.test","password":"correct-horse"}`)
|
||||
postJSON(t, controllers.Login(app), "/_user/api/v1/login", `{"email":"react-en@example.test","password":"correct-horse"}`)
|
||||
assertTemplate(t, rec, "golem15.user::mail.reactivate", "react-pl@example.test")
|
||||
assertTemplate(t, rec, "golem15.user::mail.reactivate-en", "react-en@example.test")
|
||||
}
|
||||
|
||||
func publishMemoryMail(t *testing.T, app *backpack.App) (*recordingMail, *postcard.MemoryDriver) {
|
||||
t.Helper()
|
||||
cat := postcard.NewCatalog()
|
||||
p := &Plugin{}
|
||||
if err := cat.Register(p.ID(), p.MailTemplatesFS(), p.MailTemplates(), p.MailLayouts()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mem := postcard.NewMemoryDriver()
|
||||
inner := postcard.NewMailer(cat, mem, postcard.Options{From: "noreply@example.test"})
|
||||
rec := &recordingMail{inner: inner}
|
||||
if err := app.Publish[postcard.Mailer](rec); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return rec, mem
|
||||
}
|
||||
|
||||
func assertTemplate(t *testing.T, rec *recordingMail, template, to string) {
|
||||
t.Helper()
|
||||
for _, msg := range rec.msgs {
|
||||
if msg.Template == template && len(msg.To) == 1 && msg.To[0] == to {
|
||||
return
|
||||
}
|
||||
}
|
||||
t.Fatalf("missing send %s to %s in %d messages", template, to, len(rec.msgs))
|
||||
}
|
||||
|
||||
func softDelete(t *testing.T, gdb *gorm.DB, email, locale string) {
|
||||
t.Helper()
|
||||
user := insertUser(t, gdb, email, "correct-horse")
|
||||
if err := gdb.Model(user).Update("preferred_locale", locale).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := gdb.Model(&models.User{}).Where("id = ?", user.ID).Update("deleted_at", time.Now()).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user