@ -22,6 +22,7 @@ import (
"code.gitea.io/gitea/modules/markup/markdown"
"code.gitea.io/gitea/modules/markup/markdown"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/translation"
"gopkg.in/gomail.v2"
"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 ( ) )
return gomail . Send ( Sender , NewMessage ( [ ] string { email } , "Gitea Test Email!" , "Gitea Test Email!" ) . ToMessage ( ) )
}
}
// SendUserMail sends a mail to the user
// sendUserMail sends a mail to the user
func SendUserMail ( language string , u * models . User , tpl base . TplName , code , subject , info string ) {
func sendUserMail ( language string , u * models . User , tpl base . TplName , code , subject , info string ) {
locale := translation . NewLocale ( language )
data := map [ string ] interface { } {
data := map [ string ] interface { } {
"DisplayName" : u . DisplayName ( ) ,
"DisplayName" : u . DisplayName ( ) ,
"ActiveCodeLives" : timeutil . MinutesToFriendly ( setting . Service . ActiveCodeLives , language ) ,
"ActiveCodeLives" : timeutil . MinutesToFriendly ( setting . Service . ActiveCodeLives , language ) ,
"ResetPwdCodeLives" : timeutil . MinutesToFriendly ( setting . Service . ResetPwdCodeLives , language ) ,
"ResetPwdCodeLives" : timeutil . MinutesToFriendly ( setting . Service . ResetPwdCodeLives , language ) ,
"Code" : code ,
"Code" : code ,
"i18n" : locale ,
"Language" : locale . Language ( ) ,
}
}
var content bytes . Buffer
var content bytes . Buffer
// TODO: i18n templates?
if err := bodyTemplates . ExecuteTemplate ( & content , string ( tpl ) , data ) ; err != nil {
if err := bodyTemplates . ExecuteTemplate ( & content , string ( tpl ) , data ) ; err != nil {
log . Error ( "Template: %v" , err )
log . Error ( "Template: %v" , err )
return
return
@ -79,33 +84,32 @@ func SendUserMail(language string, u *models.User, tpl base.TplName, code, subje
SendAsync ( msg )
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)
// SendActivateAccountMail sends an activation mail to the user (new user registration)
func SendActivateAccountMail ( locale Locale , u * models . User ) {
func SendActivateAccountMail ( locale translation . Locale , u * models . User ) {
S endUserMail( locale . Language ( ) , u , mailAuthActivate , u . GenerateActivateCode ( ) , locale . Tr ( "mail.activate_account" ) , "activate account" )
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
// SendResetPasswordMail sends a password reset mail to the user
func SendResetPasswordMail ( locale Locale , u * models . User ) {
func SendResetPasswordMail ( u * models . User ) {
SendUserMail ( locale . Language ( ) , u , mailAuthResetPassword , u . GenerateActivateCode ( ) , locale . Tr ( "mail.reset_password" ) , "recover account" )
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
// 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 { } {
data := map [ string ] interface { } {
"DisplayName" : u . DisplayName ( ) ,
"DisplayName" : u . DisplayName ( ) ,
"ActiveCodeLives" : timeutil . MinutesToFriendly ( setting . Service . ActiveCodeLives , locale . Language ( ) ) ,
"ActiveCodeLives" : timeutil . MinutesToFriendly ( setting . Service . ActiveCodeLives , locale . Language ( ) ) ,
"Code" : u . GenerateEmailActivateCode ( email . Email ) ,
"Code" : u . GenerateEmailActivateCode ( email . Email ) ,
"Email" : email . Email ,
"Email" : email . Email ,
"i18n" : locale ,
"Language" : locale . Language ( ) ,
}
}
var content bytes . Buffer
var content bytes . Buffer
// TODO: i18n templates?
if err := bodyTemplates . ExecuteTemplate ( & content , string ( mailAuthActivateEmail ) , data ) ; err != nil {
if err := bodyTemplates . ExecuteTemplate ( & content , string ( mailAuthActivateEmail ) , data ) ; err != nil {
log . Error ( "Template: %v" , err )
log . Error ( "Template: %v" , err )
return
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.
// SendRegisterNotifyMail triggers a notify e-mail by admin created a account.
func SendRegisterNotifyMail ( locale Locale , u * models . User ) {
func SendRegisterNotifyMail ( u * models . User ) {
if setting . MailService == nil {
locale := translation . NewLocale ( u . Language )
log . Warn ( "SendRegisterNotifyMail is being invoked but mail service hasn't been initialized" )
return
}
data := map [ string ] interface { } {
data := map [ string ] interface { } {
"DisplayName" : u . DisplayName ( ) ,
"DisplayName" : u . DisplayName ( ) ,
"Username" : u . Name ,
"Username" : u . Name ,
"i18n" : locale ,
"Language" : locale . Language ( ) ,
}
}
var content bytes . Buffer
var content bytes . Buffer
// TODO: i18n templates?
if err := bodyTemplates . ExecuteTemplate ( & content , string ( mailAuthRegisterNotify ) , data ) ; err != nil {
if err := bodyTemplates . ExecuteTemplate ( & content , string ( mailAuthRegisterNotify ) , data ) ; err != nil {
log . Error ( "Template: %v" , err )
log . Error ( "Template: %v" , err )
return
return
@ -144,17 +148,21 @@ func SendRegisterNotifyMail(locale Locale, u *models.User) {
// SendCollaboratorMail sends mail notification to new collaborator.
// SendCollaboratorMail sends mail notification to new collaborator.
func SendCollaboratorMail ( u , doer * models . User , repo * models . Repository ) {
func SendCollaboratorMail ( u , doer * models . User , repo * models . Repository ) {
locale := translation . NewLocale ( u . Language )
repoName := repo . FullName ( )
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 { } {
data := map [ string ] interface { } {
"Subject" : subject ,
"Subject" : subject ,
"RepoName" : repoName ,
"RepoName" : repoName ,
"Link" : repo . HTMLURL ( ) ,
"Link" : repo . HTMLURL ( ) ,
"i18n" : locale ,
"Language" : locale . Language ( ) ,
}
}
var content bytes . Buffer
var content bytes . Buffer
// TODO: i18n templates?
if err := bodyTemplates . ExecuteTemplate ( & content , string ( mailNotifyCollaborator ) , data ) ; err != nil {
if err := bodyTemplates . ExecuteTemplate ( & content , string ( mailNotifyCollaborator ) , data ) ; err != nil {
log . Error ( "Template: %v" , err )
log . Error ( "Template: %v" , err )
return
return
@ -166,7 +174,7 @@ func SendCollaboratorMail(u, doer *models.User, repo *models.Repository) {
SendAsync ( msg )
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 (
var (
subject string
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
// 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 ( ) ) )
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 )
actType , actName , tplName := actionToTemplate ( ctx . Issue , ctx . ActionType , commentType , reviewType )
if actName != "new" {
if actName != "new" {
@ -208,6 +215,7 @@ func composeIssueCommentMessages(ctx *mailCommentContext, tos []string, fromMent
}
}
}
}
}
}
locale := translation . NewLocale ( lang )
mailMeta := map [ string ] interface { } {
mailMeta := map [ string ] interface { } {
"FallbackSubject" : fallback ,
"FallbackSubject" : fallback ,
@ -224,13 +232,16 @@ func composeIssueCommentMessages(ctx *mailCommentContext, tos []string, fromMent
"ActionType" : actType ,
"ActionType" : actType ,
"ActionName" : actName ,
"ActionName" : actName ,
"ReviewComments" : reviewComments ,
"ReviewComments" : reviewComments ,
"i18n" : locale ,
"Language" : locale . Language ( ) ,
}
}
var mailSubject bytes . Buffer
var mailSubject bytes . Buffer
// TODO: i18n templates?
if err := subjectTemplates . ExecuteTemplate ( & mailSubject , string ( tplName ) , mailMeta ) ; err == nil {
if err := subjectTemplates . ExecuteTemplate ( & mailSubject , string ( tplName ) , mailMeta ) ; err == nil {
subject = sanitizeSubject ( mailSubject . String ( ) )
subject = sanitizeSubject ( mailSubject . String ( ) )
} else {
} else {
log . Error ( "ExecuteTemplate [%s]: %v" , string ( tplName ) + "/subject" , err )
log . Error ( "ExecuteTemplate [%s]: %v" , tplName + "/subject" , err )
}
}
if subject == "" {
if subject == "" {
@ -243,6 +254,7 @@ func composeIssueCommentMessages(ctx *mailCommentContext, tos []string, fromMent
var mailBody bytes . Buffer
var mailBody bytes . Buffer
// TODO: i18n templates?
if err := bodyTemplates . ExecuteTemplate ( & mailBody , string ( tplName ) , mailMeta ) ; err != nil {
if err := bodyTemplates . ExecuteTemplate ( & mailBody , string ( tplName ) , mailMeta ) ; err != nil {
log . Error ( "ExecuteTemplate [%s]: %v" , string ( tplName ) + "/body" , err )
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
// SendIssueAssignedMail composes and sends issue assigned email
func SendIssueAssignedMail ( issue * models . Issue , doer * models . User , content string , comment * models . Comment , tos [ ] string ) {
func SendIssueAssignedMail ( issue * models . Issue , doer * models . User , content string , comment * models . Comment , recipients [ ] * models . User ) {
SendAsyncs ( composeIssueCommentMessages ( & mailCommentContext {
langMap := make ( map [ string ] [ ] string )
Issue : issue ,
for _ , user := range recipients {
Doer : doer ,
langMap [ user . Language ] = append ( langMap [ user . Language ] , user . Email )
ActionType : models . ActionType ( 0 ) ,
}
Content : content ,
Comment : comment ,
for lang , tos := range langMap {
} , tos , false , "issue assigned" ) )
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
// actionToTemplate returns the type and name of the action facing the user