diff --git a/internal/usecase/interactor/emails/password_reset_html.tmpl b/internal/usecase/interactor/emails/password_reset_html.tmpl new file mode 100644 index 00000000..43ee3058 --- /dev/null +++ b/internal/usecase/interactor/emails/password_reset_html.tmpl @@ -0,0 +1,22 @@ + + + +
+ + + + ++ You have submitted a password change request! If it was you, please confirm the password change. + To reset your password click on the following link: +
+ + {{ . }} + +If you are having any issues with your account, please don't hesitate to contact us by replying to this mail. Thank you!
+ + + + \ No newline at end of file diff --git a/internal/usecase/interactor/emails/password_reset_text.tmpl b/internal/usecase/interactor/emails/password_reset_text.tmpl new file mode 100644 index 00000000..03d4fd2b --- /dev/null +++ b/internal/usecase/interactor/emails/password_reset_text.tmpl @@ -0,0 +1,7 @@ +ReEarth +You have submitted a password change request! If it was you, please confirm the password change. +To reset your password click on the following link: + +{{ . }} + +If you are having any issues with your account, please don't hesitate to contact us by replying to this mail. Thank you! \ No newline at end of file diff --git a/internal/usecase/interactor/user.go b/internal/usecase/interactor/user.go index c13fa040..8419e331 100644 --- a/internal/usecase/interactor/user.go +++ b/internal/usecase/interactor/user.go @@ -1,15 +1,20 @@ package interactor import ( + "bytes" "context" + _ "embed" "errors" + htmlTmpl "html/template" "net/mail" + textTmpl "text/template" "github.com/reearth/reearth-backend/internal/usecase" "github.com/reearth/reearth-backend/internal/usecase/gateway" "github.com/reearth/reearth-backend/internal/usecase/interfaces" "github.com/reearth/reearth-backend/internal/usecase/repo" "github.com/reearth/reearth-backend/pkg/id" + "github.com/reearth/reearth-backend/pkg/log" "github.com/reearth/reearth-backend/pkg/project" "github.com/reearth/reearth-backend/pkg/rerror" "github.com/reearth/reearth-backend/pkg/user" @@ -29,9 +34,32 @@ type User struct { transaction repo.Transaction file gateway.File authenticator gateway.Authenticator + mailer gateway.Mailer signupSecret string } +var ( + //go:embed emails/password_reset_html.tmpl + passwordResetHTMLTMPLStr string + //go:embed emails/password_reset_text.tmpl + passwordResetTextTMPLStr string + + passwordResetTextTMPL *textTmpl.Template + passwordResetHTMLTMPL *htmlTmpl.Template +) + +func init() { + var err error + passwordResetTextTMPL, err = textTmpl.New("passwordReset").Parse(passwordResetTextTMPLStr) + if err != nil { + log.Panicf("password reset email template parse error: %s\n", err) + } + passwordResetHTMLTMPL, err = htmlTmpl.New("passwordReset").Parse(passwordResetHTMLTMPLStr) + if err != nil { + log.Panicf("password reset email template parse error: %s\n", err) + } +} + func NewUser(r *repo.Container, g *gateway.Container, signupSecret string) interfaces.User { return &User{ userRepo: r.User, @@ -47,6 +75,7 @@ func NewUser(r *repo.Container, g *gateway.Container, signupSecret string) inter file: g.File, authenticator: g.Authenticator, signupSecret: signupSecret, + mailer: g.Mailer, } } @@ -253,12 +282,34 @@ func (i *User) StartPasswordReset(ctx context.Context, email string) error { return err } - u.SetPasswordReset(user.NewPasswordReset()) + pr := user.NewPasswordReset() + u.SetPasswordReset(pr) if err := i.userRepo.Save(ctx, u); err != nil { return err } + var TextOut, HTMLOut bytes.Buffer + link := "localhost:3000/?pwd-reset-token=" + pr.Token + err = passwordResetTextTMPL.Execute(&TextOut, link) + if err != nil { + return err + } + err = passwordResetHTMLTMPL.Execute(&HTMLOut, link) + if err != nil { + return err + } + + err = i.mailer.SendMail([]gateway.Contact{ + { + Email: u.Email(), + Name: u.Name(), + }, + }, "Password reset", TextOut.String(), HTMLOut.String()) + if err != nil { + return err + } + tx.Commit() return nil } diff --git a/pkg/log/log.go b/pkg/log/log.go index 23ed1c84..a42a6f00 100644 --- a/pkg/log/log.go +++ b/pkg/log/log.go @@ -102,3 +102,7 @@ func Errorln(args ...interface{}) { func Fatalln(args ...interface{}) { logrus.Fatalln(args...) } + +func Panicf(format string, args ...interface{}) { + logrus.Panicf(format, args...) +}