mirror of
https://github.com/go-gitea/gitea
synced 2025-07-22 18:28:37 +00:00
[refactor] mailer service (#15072)
* Unexport SendUserMail * Instead of "[]*models.User" or "[]string" lists infent "[]*MailRecipient" for mailer * adopt * code format * TODOs for "i18n" * clean * no fallback for lang -> just use english * lint * exec testComposeIssueCommentMessage per lang and use only emails * rm MailRecipient * Dont reload from users from db if you alredy have in ram * nits * minimize diff Signed-off-by: 6543 <6543@obermui.de> * localize subjects * linter ... * Tr extend * start tmpl edit ... * Apply suggestions from code review * use translation.Locale * improve mailIssueCommentBatch Signed-off-by: Andrew Thornton <art27@cantab.net> * add i18n to datas Signed-off-by: Andrew Thornton <art27@cantab.net> * a comment Co-authored-by: Andrew Thornton <art27@cantab.net>
This commit is contained in:
@@ -22,6 +22,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/markup/markdown"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
|
||||
"gopkg.in/gomail.v2"
|
||||
)
|
||||
@@ -57,17 +58,21 @@ func SendTestMail(email string) error {
|
||||
return gomail.Send(Sender, NewMessage([]string{email}, "Gitea Test Email!", "Gitea Test Email!").ToMessage())
|
||||
}
|
||||
|
||||
// SendUserMail sends a mail to the user
|
||||
func SendUserMail(language string, u *models.User, tpl base.TplName, code, subject, info string) {
|
||||
// sendUserMail sends a mail to the user
|
||||
func sendUserMail(language string, u *models.User, tpl base.TplName, code, subject, info string) {
|
||||
locale := translation.NewLocale(language)
|
||||
data := map[string]interface{}{
|
||||
"DisplayName": u.DisplayName(),
|
||||
"ActiveCodeLives": timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, language),
|
||||
"ResetPwdCodeLives": timeutil.MinutesToFriendly(setting.Service.ResetPwdCodeLives, language),
|
||||
"Code": code,
|
||||
"i18n": locale,
|
||||
"Language": locale.Language(),
|
||||
}
|
||||
|
||||
var content bytes.Buffer
|
||||
|
||||
// TODO: i18n templates?
|
||||
if err := bodyTemplates.ExecuteTemplate(&content, string(tpl), data); err != nil {
|
||||
log.Error("Template: %v", err)
|
||||
return
|
||||
@@ -79,33 +84,32 @@ func SendUserMail(language string, u *models.User, tpl base.TplName, code, subje
|
||||
SendAsync(msg)
|
||||
}
|
||||
|
||||
// Locale represents an interface to translation
|
||||
type Locale interface {
|
||||
Language() string
|
||||
Tr(string, ...interface{}) string
|
||||
}
|
||||
|
||||
// SendActivateAccountMail sends an activation mail to the user (new user registration)
|
||||
func SendActivateAccountMail(locale Locale, u *models.User) {
|
||||
SendUserMail(locale.Language(), u, mailAuthActivate, u.GenerateActivateCode(), locale.Tr("mail.activate_account"), "activate account")
|
||||
func SendActivateAccountMail(locale translation.Locale, u *models.User) {
|
||||
sendUserMail(locale.Language(), u, mailAuthActivate, u.GenerateEmailActivateCode(u.Email), locale.Tr("mail.activate_account"), "activate account")
|
||||
}
|
||||
|
||||
// SendResetPasswordMail sends a password reset mail to the user
|
||||
func SendResetPasswordMail(locale Locale, u *models.User) {
|
||||
SendUserMail(locale.Language(), u, mailAuthResetPassword, u.GenerateActivateCode(), locale.Tr("mail.reset_password"), "recover account")
|
||||
func SendResetPasswordMail(u *models.User) {
|
||||
locale := translation.NewLocale(u.Language)
|
||||
sendUserMail(u.Language, u, mailAuthResetPassword, u.GenerateEmailActivateCode(u.Email), locale.Tr("mail.reset_password"), "recover account")
|
||||
}
|
||||
|
||||
// SendActivateEmailMail sends confirmation email to confirm new email address
|
||||
func SendActivateEmailMail(locale Locale, u *models.User, email *models.EmailAddress) {
|
||||
func SendActivateEmailMail(u *models.User, email *models.EmailAddress) {
|
||||
locale := translation.NewLocale(u.Language)
|
||||
data := map[string]interface{}{
|
||||
"DisplayName": u.DisplayName(),
|
||||
"ActiveCodeLives": timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, locale.Language()),
|
||||
"Code": u.GenerateEmailActivateCode(email.Email),
|
||||
"Email": email.Email,
|
||||
"i18n": locale,
|
||||
"Language": locale.Language(),
|
||||
}
|
||||
|
||||
var content bytes.Buffer
|
||||
|
||||
// TODO: i18n templates?
|
||||
if err := bodyTemplates.ExecuteTemplate(&content, string(mailAuthActivateEmail), data); err != nil {
|
||||
log.Error("Template: %v", err)
|
||||
return
|
||||
@@ -118,19 +122,19 @@ func SendActivateEmailMail(locale Locale, u *models.User, email *models.EmailAdd
|
||||
}
|
||||
|
||||
// SendRegisterNotifyMail triggers a notify e-mail by admin created a account.
|
||||
func SendRegisterNotifyMail(locale Locale, u *models.User) {
|
||||
if setting.MailService == nil {
|
||||
log.Warn("SendRegisterNotifyMail is being invoked but mail service hasn't been initialized")
|
||||
return
|
||||
}
|
||||
func SendRegisterNotifyMail(u *models.User) {
|
||||
locale := translation.NewLocale(u.Language)
|
||||
|
||||
data := map[string]interface{}{
|
||||
"DisplayName": u.DisplayName(),
|
||||
"Username": u.Name,
|
||||
"i18n": locale,
|
||||
"Language": locale.Language(),
|
||||
}
|
||||
|
||||
var content bytes.Buffer
|
||||
|
||||
// TODO: i18n templates?
|
||||
if err := bodyTemplates.ExecuteTemplate(&content, string(mailAuthRegisterNotify), data); err != nil {
|
||||
log.Error("Template: %v", err)
|
||||
return
|
||||
@@ -144,17 +148,21 @@ func SendRegisterNotifyMail(locale Locale, u *models.User) {
|
||||
|
||||
// SendCollaboratorMail sends mail notification to new collaborator.
|
||||
func SendCollaboratorMail(u, doer *models.User, repo *models.Repository) {
|
||||
locale := translation.NewLocale(u.Language)
|
||||
repoName := repo.FullName()
|
||||
subject := fmt.Sprintf("%s added you to %s", doer.DisplayName(), repoName)
|
||||
|
||||
subject := locale.Tr("mail.repo.collaborator.added.subject", doer.DisplayName(), repoName)
|
||||
data := map[string]interface{}{
|
||||
"Subject": subject,
|
||||
"RepoName": repoName,
|
||||
"Link": repo.HTMLURL(),
|
||||
"i18n": locale,
|
||||
"Language": locale.Language(),
|
||||
}
|
||||
|
||||
var content bytes.Buffer
|
||||
|
||||
// TODO: i18n templates?
|
||||
if err := bodyTemplates.ExecuteTemplate(&content, string(mailNotifyCollaborator), data); err != nil {
|
||||
log.Error("Template: %v", err)
|
||||
return
|
||||
@@ -166,7 +174,7 @@ func SendCollaboratorMail(u, doer *models.User, repo *models.Repository) {
|
||||
SendAsync(msg)
|
||||
}
|
||||
|
||||
func composeIssueCommentMessages(ctx *mailCommentContext, tos []string, fromMention bool, info string) []*Message {
|
||||
func composeIssueCommentMessages(ctx *mailCommentContext, lang string, tos []string, fromMention bool, info string) []*Message {
|
||||
|
||||
var (
|
||||
subject string
|
||||
@@ -192,7 +200,6 @@ func composeIssueCommentMessages(ctx *mailCommentContext, tos []string, fromMent
|
||||
|
||||
// This is the body of the new issue or comment, not the mail body
|
||||
body := string(markup.RenderByType(markdown.MarkupName, []byte(ctx.Content), ctx.Issue.Repo.HTMLURL(), ctx.Issue.Repo.ComposeMetas()))
|
||||
|
||||
actType, actName, tplName := actionToTemplate(ctx.Issue, ctx.ActionType, commentType, reviewType)
|
||||
|
||||
if actName != "new" {
|
||||
@@ -208,6 +215,7 @@ func composeIssueCommentMessages(ctx *mailCommentContext, tos []string, fromMent
|
||||
}
|
||||
}
|
||||
}
|
||||
locale := translation.NewLocale(lang)
|
||||
|
||||
mailMeta := map[string]interface{}{
|
||||
"FallbackSubject": fallback,
|
||||
@@ -224,13 +232,16 @@ func composeIssueCommentMessages(ctx *mailCommentContext, tos []string, fromMent
|
||||
"ActionType": actType,
|
||||
"ActionName": actName,
|
||||
"ReviewComments": reviewComments,
|
||||
"i18n": locale,
|
||||
"Language": locale.Language(),
|
||||
}
|
||||
|
||||
var mailSubject bytes.Buffer
|
||||
// TODO: i18n templates?
|
||||
if err := subjectTemplates.ExecuteTemplate(&mailSubject, string(tplName), mailMeta); err == nil {
|
||||
subject = sanitizeSubject(mailSubject.String())
|
||||
} else {
|
||||
log.Error("ExecuteTemplate [%s]: %v", string(tplName)+"/subject", err)
|
||||
log.Error("ExecuteTemplate [%s]: %v", tplName+"/subject", err)
|
||||
}
|
||||
|
||||
if subject == "" {
|
||||
@@ -243,6 +254,7 @@ func composeIssueCommentMessages(ctx *mailCommentContext, tos []string, fromMent
|
||||
|
||||
var mailBody bytes.Buffer
|
||||
|
||||
// TODO: i18n templates?
|
||||
if err := bodyTemplates.ExecuteTemplate(&mailBody, string(tplName), mailMeta); err != nil {
|
||||
log.Error("ExecuteTemplate [%s]: %v", string(tplName)+"/body", err)
|
||||
}
|
||||
@@ -276,14 +288,21 @@ func sanitizeSubject(subject string) string {
|
||||
}
|
||||
|
||||
// SendIssueAssignedMail composes and sends issue assigned email
|
||||
func SendIssueAssignedMail(issue *models.Issue, doer *models.User, content string, comment *models.Comment, tos []string) {
|
||||
SendAsyncs(composeIssueCommentMessages(&mailCommentContext{
|
||||
Issue: issue,
|
||||
Doer: doer,
|
||||
ActionType: models.ActionType(0),
|
||||
Content: content,
|
||||
Comment: comment,
|
||||
}, tos, false, "issue assigned"))
|
||||
func SendIssueAssignedMail(issue *models.Issue, doer *models.User, content string, comment *models.Comment, recipients []*models.User) {
|
||||
langMap := make(map[string][]string)
|
||||
for _, user := range recipients {
|
||||
langMap[user.Language] = append(langMap[user.Language], user.Email)
|
||||
}
|
||||
|
||||
for lang, tos := range langMap {
|
||||
SendAsyncs(composeIssueCommentMessages(&mailCommentContext{
|
||||
Issue: issue,
|
||||
Doer: doer,
|
||||
ActionType: models.ActionType(0),
|
||||
Content: content,
|
||||
Comment: comment,
|
||||
}, lang, tos, false, "issue assigned"))
|
||||
}
|
||||
}
|
||||
|
||||
// actionToTemplate returns the type and name of the action facing the user
|
||||
|
Reference in New Issue
Block a user