diff options
author | Lunny Xiao <xiaolunwen@gmail.com> | 2019-09-24 13:02:49 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-09-24 13:02:49 +0800 |
commit | 5a438ee3c0303efcb9d1935ff521917fe8a109e8 (patch) | |
tree | 8f36452631fc8a6d077addbbf857da6d50024a0a /models | |
parent | 730065a3dc72683460b95ba1486dba8ec355a373 (diff) | |
download | gitea-5a438ee3c0303efcb9d1935ff521917fe8a109e8.tar.gz gitea-5a438ee3c0303efcb9d1935ff521917fe8a109e8.zip |
Move all mail related codes from models to services/mailer (#7200)
* move all mail related codes from models to modules/mailer
* fix lint
* use DBContext instead Engine
* use WithContext not WithEngine
* Use DBContext instead of Engine
* don't use defer when sess.Close()
* move DBContext to context.go and add some methods
* move mailer from modules/ to services
* fix lint
* fix tests
* fix fmt
* add gitea copyright
* fix tests
* don't expose db functions
* make code clear
* add DefaultDBContext
* fix build
* fix bug
Diffstat (limited to 'models')
-rw-r--r-- | models/context.go | 55 | ||||
-rw-r--r-- | models/error.go | 15 | ||||
-rw-r--r-- | models/issue.go | 8 | ||||
-rw-r--r-- | models/issue_comment.go | 35 | ||||
-rw-r--r-- | models/issue_mail.go | 159 | ||||
-rw-r--r-- | models/issue_user.go | 8 | ||||
-rw-r--r-- | models/issue_user_test.go | 2 | ||||
-rw-r--r-- | models/mail.go | 217 | ||||
-rw-r--r-- | models/mail_test.go | 87 |
9 files changed, 79 insertions, 507 deletions
diff --git a/models/context.go b/models/context.go new file mode 100644 index 0000000000..5f47c595a2 --- /dev/null +++ b/models/context.go @@ -0,0 +1,55 @@ +// Copyright 2019 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package models + +// DBContext represents a db context +type DBContext struct { + e Engine +} + +// DefaultDBContext represents a DBContext with default Engine +func DefaultDBContext() DBContext { + return DBContext{x} +} + +// Committer represents an interface to Commit or Close the dbcontext +type Committer interface { + Commit() error + Close() +} + +// TxDBContext represents a transaction DBContext +func TxDBContext() (DBContext, Committer, error) { + sess := x.NewSession() + if err := sess.Begin(); err != nil { + sess.Close() + return DBContext{}, nil, err + } + + return DBContext{sess}, sess, nil +} + +// WithContext represents executing database operations +func WithContext(f func(ctx DBContext) error) error { + return f(DBContext{x}) +} + +// WithTx represents executing database operations on a trasaction +func WithTx(f func(ctx DBContext) error) error { + sess := x.NewSession() + if err := sess.Begin(); err != nil { + sess.Close() + return err + } + + if err := f(DBContext{sess}); err != nil { + sess.Close() + return err + } + + err := sess.Commit() + sess.Close() + return err +} diff --git a/models/error.go b/models/error.go index c025437c50..9974287a0a 100644 --- a/models/error.go +++ b/models/error.go @@ -11,6 +11,21 @@ import ( "code.gitea.io/gitea/modules/git" ) +// ErrNotExist represents a non-exist error. +type ErrNotExist struct { + ID int64 +} + +// IsErrNotExist checks if an error is an ErrNotExist +func IsErrNotExist(err error) bool { + _, ok := err.(ErrNotExist) + return ok +} + +func (err ErrNotExist) Error() string { + return fmt.Sprintf("record does not exist [id: %d]", err.ID) +} + // ErrNameReserved represents a "reserved name" error. type ErrNameReserved struct { Name string diff --git a/models/issue.go b/models/issue.go index bb2db94407..c4b15e9ddf 100644 --- a/models/issue.go +++ b/models/issue.go @@ -1503,7 +1503,7 @@ func getParticipantsByIssueID(e Engine, issueID int64) ([]*User, error) { // UpdateIssueMentions extracts mentioned people from content and // updates issue-user relations for them. -func UpdateIssueMentions(e Engine, issueID int64, mentions []string) error { +func UpdateIssueMentions(ctx DBContext, issueID int64, mentions []string) error { if len(mentions) == 0 { return nil } @@ -1513,7 +1513,7 @@ func UpdateIssueMentions(e Engine, issueID int64, mentions []string) error { } users := make([]*User, 0, len(mentions)) - if err := e.In("lower_name", mentions).Asc("lower_name").Find(&users); err != nil { + if err := ctx.e.In("lower_name", mentions).Asc("lower_name").Find(&users); err != nil { return fmt.Errorf("find mentioned users: %v", err) } @@ -1525,7 +1525,7 @@ func UpdateIssueMentions(e Engine, issueID int64, mentions []string) error { } memberIDs := make([]int64, 0, user.NumMembers) - orgUsers, err := getOrgUsersByOrgID(e, user.ID) + orgUsers, err := getOrgUsersByOrgID(ctx.e, user.ID) if err != nil { return fmt.Errorf("GetOrgUsersByOrgID [%d]: %v", user.ID, err) } @@ -1537,7 +1537,7 @@ func UpdateIssueMentions(e Engine, issueID int64, mentions []string) error { ids = append(ids, memberIDs...) } - if err := UpdateIssueUsersByMentions(e, issueID, ids); err != nil { + if err := UpdateIssueUsersByMentions(ctx, issueID, ids); err != nil { return fmt.Errorf("UpdateIssueUsersByMentions: %v", err) } diff --git a/models/issue_comment.go b/models/issue_comment.go index 0bb313c30b..6786032f41 100644 --- a/models/issue_comment.go +++ b/models/issue_comment.go @@ -12,7 +12,6 @@ import ( "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup/markdown" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" @@ -395,40 +394,6 @@ func (c *Comment) LoadDepIssueDetails() (err error) { return err } -// MailParticipants sends new comment emails to repository watchers -// and mentioned people. -func (c *Comment) MailParticipants(opType ActionType, issue *Issue) (err error) { - return c.mailParticipants(x, opType, issue) -} - -func (c *Comment) mailParticipants(e Engine, opType ActionType, issue *Issue) (err error) { - mentions := markup.FindAllMentions(c.Content) - if err = UpdateIssueMentions(e, c.IssueID, mentions); err != nil { - return fmt.Errorf("UpdateIssueMentions [%d]: %v", c.IssueID, err) - } - - if len(c.Content) > 0 { - if err = mailIssueCommentToParticipants(e, issue, c.Poster, c.Content, c, mentions); err != nil { - log.Error("mailIssueCommentToParticipants: %v", err) - } - } - - switch opType { - case ActionCloseIssue: - ct := fmt.Sprintf("Closed #%d.", issue.Index) - if err = mailIssueCommentToParticipants(e, issue, c.Poster, ct, c, mentions); err != nil { - log.Error("mailIssueCommentToParticipants: %v", err) - } - case ActionReopenIssue: - ct := fmt.Sprintf("Reopened #%d.", issue.Index) - if err = mailIssueCommentToParticipants(e, issue, c.Poster, ct, c, mentions); err != nil { - log.Error("mailIssueCommentToParticipants: %v", err) - } - } - - return nil -} - func (c *Comment) loadReactions(e Engine) (err error) { if c.Reactions != nil { return nil diff --git a/models/issue_mail.go b/models/issue_mail.go deleted file mode 100644 index 87d991e500..0000000000 --- a/models/issue_mail.go +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2016 The Gogs Authors. All rights reserved. -// Copyright 2018 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package models - -import ( - "fmt" - - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/markup" - "code.gitea.io/gitea/modules/setting" - - "github.com/unknwon/com" -) - -func (issue *Issue) mailSubject() string { - return fmt.Sprintf("[%s] %s (#%d)", issue.Repo.FullName(), issue.Title, issue.Index) -} - -// mailIssueCommentToParticipants can be used for both new issue creation and comment. -// This function sends two list of emails: -// 1. Repository watchers and users who are participated in comments. -// 2. Users who are not in 1. but get mentioned in current issue/comment. -func mailIssueCommentToParticipants(e Engine, issue *Issue, doer *User, content string, comment *Comment, mentions []string) error { - if !setting.Service.EnableNotifyMail { - return nil - } - - watchers, err := getWatchers(e, issue.RepoID) - if err != nil { - return fmt.Errorf("getWatchers [repo_id: %d]: %v", issue.RepoID, err) - } - participants, err := getParticipantsByIssueID(e, issue.ID) - if err != nil { - return fmt.Errorf("getParticipantsByIssueID [issue_id: %d]: %v", issue.ID, err) - } - - // In case the issue poster is not watching the repository and is active, - // even if we have duplicated in watchers, can be safely filtered out. - err = issue.loadPoster(e) - if err != nil { - return fmt.Errorf("GetUserByID [%d]: %v", issue.PosterID, err) - } - if issue.PosterID != doer.ID && issue.Poster.IsActive && !issue.Poster.ProhibitLogin { - participants = append(participants, issue.Poster) - } - - // Assignees must receive any communications - assignees, err := getAssigneesByIssue(e, issue) - if err != nil { - return err - } - - for _, assignee := range assignees { - if assignee.ID != doer.ID { - participants = append(participants, assignee) - } - } - - tos := make([]string, 0, len(watchers)) // List of email addresses. - names := make([]string, 0, len(watchers)) - for i := range watchers { - if watchers[i].UserID == doer.ID { - continue - } - - to, err := getUserByID(e, watchers[i].UserID) - if err != nil { - return fmt.Errorf("GetUserByID [%d]: %v", watchers[i].UserID, err) - } - if to.IsOrganization() || to.EmailNotifications() != EmailNotificationsEnabled { - continue - } - - tos = append(tos, to.Email) - names = append(names, to.Name) - } - for i := range participants { - if participants[i].ID == doer.ID || - com.IsSliceContainsStr(names, participants[i].Name) || - participants[i].EmailNotifications() != EmailNotificationsEnabled { - continue - } - - tos = append(tos, participants[i].Email) - names = append(names, participants[i].Name) - } - - if err := issue.loadRepo(e); err != nil { - return err - } - - for _, to := range tos { - SendIssueCommentMail(issue, doer, content, comment, []string{to}) - } - - // Mail mentioned people and exclude watchers. - names = append(names, doer.Name) - tos = make([]string, 0, len(mentions)) // list of user names. - for i := range mentions { - if com.IsSliceContainsStr(names, mentions[i]) { - continue - } - - tos = append(tos, mentions[i]) - } - - emails := getUserEmailsByNames(e, tos) - - for _, to := range emails { - SendIssueMentionMail(issue, doer, content, comment, []string{to}) - } - - return nil -} - -// MailParticipants sends new issue thread created emails to repository watchers -// and mentioned people. -func (issue *Issue) MailParticipants(doer *User, opType ActionType) (err error) { - return issue.mailParticipants(x, doer, opType) -} - -func (issue *Issue) mailParticipants(e Engine, doer *User, opType ActionType) (err error) { - mentions := markup.FindAllMentions(issue.Content) - - if err = UpdateIssueMentions(e, issue.ID, mentions); err != nil { - return fmt.Errorf("UpdateIssueMentions [%d]: %v", issue.ID, err) - } - - if len(issue.Content) > 0 { - if err = mailIssueCommentToParticipants(e, issue, doer, issue.Content, nil, mentions); err != nil { - log.Error("mailIssueCommentToParticipants: %v", err) - } - } - - switch opType { - case ActionCreateIssue, ActionCreatePullRequest: - if len(issue.Content) == 0 { - ct := fmt.Sprintf("Created #%d.", issue.Index) - if err = mailIssueCommentToParticipants(e, issue, doer, ct, nil, mentions); err != nil { - log.Error("mailIssueCommentToParticipants: %v", err) - } - } - case ActionCloseIssue, ActionClosePullRequest: - ct := fmt.Sprintf("Closed #%d.", issue.Index) - if err = mailIssueCommentToParticipants(e, issue, doer, ct, nil, mentions); err != nil { - log.Error("mailIssueCommentToParticipants: %v", err) - } - case ActionReopenIssue, ActionReopenPullRequest: - ct := fmt.Sprintf("Reopened #%d.", issue.Index) - if err = mailIssueCommentToParticipants(e, issue, doer, ct, nil, mentions); err != nil { - log.Error("mailIssueCommentToParticipants: %v", err) - } - } - - return nil -} diff --git a/models/issue_user.go b/models/issue_user.go index 58eb5117f8..d55a0dc2fb 100644 --- a/models/issue_user.go +++ b/models/issue_user.go @@ -94,22 +94,22 @@ func UpdateIssueUserByRead(uid, issueID int64) error { } // UpdateIssueUsersByMentions updates issue-user pairs by mentioning. -func UpdateIssueUsersByMentions(e Engine, issueID int64, uids []int64) error { +func UpdateIssueUsersByMentions(ctx DBContext, issueID int64, uids []int64) error { for _, uid := range uids { iu := &IssueUser{ UID: uid, IssueID: issueID, } - has, err := e.Get(iu) + has, err := ctx.e.Get(iu) if err != nil { return err } iu.IsMentioned = true if has { - _, err = e.ID(iu.ID).Cols("is_mentioned").Update(iu) + _, err = ctx.e.ID(iu.ID).Cols("is_mentioned").Update(iu) } else { - _, err = e.Insert(iu) + _, err = ctx.e.Insert(iu) } if err != nil { return err diff --git a/models/issue_user_test.go b/models/issue_user_test.go index a333bc8619..a57ab33f9e 100644 --- a/models/issue_user_test.go +++ b/models/issue_user_test.go @@ -50,7 +50,7 @@ func TestUpdateIssueUsersByMentions(t *testing.T) { issue := AssertExistsAndLoadBean(t, &Issue{ID: 1}).(*Issue) uids := []int64{2, 5} - assert.NoError(t, UpdateIssueUsersByMentions(x, issue.ID, uids)) + assert.NoError(t, UpdateIssueUsersByMentions(DefaultDBContext(), issue.ID, uids)) for _, uid := range uids { AssertExistsAndLoadBean(t, &IssueUser{IssueID: issue.ID, UID: uid}, "is_mentioned=1") } diff --git a/models/mail.go b/models/mail.go deleted file mode 100644 index 2c72818cec..0000000000 --- a/models/mail.go +++ /dev/null @@ -1,217 +0,0 @@ -// Copyright 2016 The Gogs Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package models - -import ( - "bytes" - "fmt" - "html/template" - "path" - - "code.gitea.io/gitea/modules/base" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/mailer" - "code.gitea.io/gitea/modules/markup" - "code.gitea.io/gitea/modules/markup/markdown" - "code.gitea.io/gitea/modules/setting" - "code.gitea.io/gitea/modules/timeutil" - - "gopkg.in/gomail.v2" -) - -const ( - mailAuthActivate base.TplName = "auth/activate" - mailAuthActivateEmail base.TplName = "auth/activate_email" - mailAuthResetPassword base.TplName = "auth/reset_passwd" - mailAuthRegisterNotify base.TplName = "auth/register_notify" - - mailIssueComment base.TplName = "issue/comment" - mailIssueMention base.TplName = "issue/mention" - - mailNotifyCollaborator base.TplName = "notify/collaborator" -) - -var templates *template.Template - -// InitMailRender initializes the mail renderer -func InitMailRender(tmpls *template.Template) { - templates = tmpls -} - -// SendTestMail sends a test mail -func SendTestMail(email string) error { - return gomail.Send(mailer.Sender, mailer.NewMessage([]string{email}, "Gitea Test Email!", "Gitea Test Email!").Message) -} - -// SendUserMail sends a mail to the user -func SendUserMail(language string, u *User, tpl base.TplName, code, subject, info string) { - data := map[string]interface{}{ - "DisplayName": u.DisplayName(), - "ActiveCodeLives": timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, language), - "ResetPwdCodeLives": timeutil.MinutesToFriendly(setting.Service.ResetPwdCodeLives, language), - "Code": code, - } - - var content bytes.Buffer - - if err := templates.ExecuteTemplate(&content, string(tpl), data); err != nil { - log.Error("Template: %v", err) - return - } - - msg := mailer.NewMessage([]string{u.Email}, subject, content.String()) - msg.Info = fmt.Sprintf("UID: %d, %s", u.ID, info) - - mailer.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 *User) { - SendUserMail(locale.Language(), u, mailAuthActivate, u.GenerateActivateCode(), locale.Tr("mail.activate_account"), "activate account") -} - -// SendResetPasswordMail sends a password reset mail to the user -func SendResetPasswordMail(locale Locale, u *User) { - SendUserMail(locale.Language(), u, mailAuthResetPassword, u.GenerateActivateCode(), locale.Tr("mail.reset_password"), "recover account") -} - -// SendActivateEmailMail sends confirmation email to confirm new email address -func SendActivateEmailMail(locale Locale, u *User, email *EmailAddress) { - data := map[string]interface{}{ - "DisplayName": u.DisplayName(), - "ActiveCodeLives": timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, locale.Language()), - "Code": u.GenerateEmailActivateCode(email.Email), - "Email": email.Email, - } - - var content bytes.Buffer - - if err := templates.ExecuteTemplate(&content, string(mailAuthActivateEmail), data); err != nil { - log.Error("Template: %v", err) - return - } - - msg := mailer.NewMessage([]string{email.Email}, locale.Tr("mail.activate_email"), content.String()) - msg.Info = fmt.Sprintf("UID: %d, activate email", u.ID) - - mailer.SendAsync(msg) -} - -// SendRegisterNotifyMail triggers a notify e-mail by admin created a account. -func SendRegisterNotifyMail(locale Locale, u *User) { - data := map[string]interface{}{ - "DisplayName": u.DisplayName(), - "Username": u.Name, - } - - var content bytes.Buffer - - if err := templates.ExecuteTemplate(&content, string(mailAuthRegisterNotify), data); err != nil { - log.Error("Template: %v", err) - return - } - - msg := mailer.NewMessage([]string{u.Email}, locale.Tr("mail.register_notify"), content.String()) - msg.Info = fmt.Sprintf("UID: %d, registration notify", u.ID) - - mailer.SendAsync(msg) -} - -// SendCollaboratorMail sends mail notification to new collaborator. -func SendCollaboratorMail(u, doer *User, repo *Repository) { - repoName := path.Join(repo.Owner.Name, repo.Name) - subject := fmt.Sprintf("%s added you to %s", doer.DisplayName(), repoName) - - data := map[string]interface{}{ - "Subject": subject, - "RepoName": repoName, - "Link": repo.HTMLURL(), - } - - var content bytes.Buffer - - if err := templates.ExecuteTemplate(&content, string(mailNotifyCollaborator), data); err != nil { - log.Error("Template: %v", err) - return - } - - msg := mailer.NewMessage([]string{u.Email}, subject, content.String()) - msg.Info = fmt.Sprintf("UID: %d, add collaborator", u.ID) - - mailer.SendAsync(msg) -} - -func composeTplData(subject, body, link string) map[string]interface{} { - data := make(map[string]interface{}, 10) - data["Subject"] = subject - data["Body"] = body - data["Link"] = link - return data -} - -func composeIssueCommentMessage(issue *Issue, doer *User, content string, comment *Comment, tplName base.TplName, tos []string, info string) *mailer.Message { - var subject string - if comment != nil { - subject = "Re: " + issue.mailSubject() - } else { - subject = issue.mailSubject() - } - - err := issue.LoadRepo() - if err != nil { - log.Error("LoadRepo: %v", err) - } - body := string(markup.RenderByType(markdown.MarkupName, []byte(content), issue.Repo.HTMLURL(), issue.Repo.ComposeMetas())) - - var data = make(map[string]interface{}, 10) - if comment != nil { - data = composeTplData(subject, body, issue.HTMLURL()+"#"+comment.HashTag()) - } else { - data = composeTplData(subject, body, issue.HTMLURL()) - } - data["Doer"] = doer - - var mailBody bytes.Buffer - - if err := templates.ExecuteTemplate(&mailBody, string(tplName), data); err != nil { - log.Error("Template: %v", err) - } - - msg := mailer.NewMessageFrom(tos, doer.DisplayName(), setting.MailService.FromEmail, subject, mailBody.String()) - msg.Info = fmt.Sprintf("Subject: %s, %s", subject, info) - - // Set Message-ID on first message so replies know what to reference - if comment == nil { - msg.SetHeader("Message-ID", "<"+issue.ReplyReference()+">") - } else { - msg.SetHeader("In-Reply-To", "<"+issue.ReplyReference()+">") - msg.SetHeader("References", "<"+issue.ReplyReference()+">") - } - - return msg -} - -// SendIssueCommentMail composes and sends issue comment emails to target receivers. -func SendIssueCommentMail(issue *Issue, doer *User, content string, comment *Comment, tos []string) { - if len(tos) == 0 { - return - } - - mailer.SendAsync(composeIssueCommentMessage(issue, doer, content, comment, mailIssueComment, tos, "issue comment")) -} - -// SendIssueMentionMail composes and sends issue mention emails to target receivers. -func SendIssueMentionMail(issue *Issue, doer *User, content string, comment *Comment, tos []string) { - if len(tos) == 0 { - return - } - mailer.SendAsync(composeIssueCommentMessage(issue, doer, content, comment, mailIssueMention, tos, "issue mention")) -} diff --git a/models/mail_test.go b/models/mail_test.go deleted file mode 100644 index 51c52427f0..0000000000 --- a/models/mail_test.go +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2019 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package models - -import ( - "html/template" - "testing" - - "code.gitea.io/gitea/modules/setting" - - "github.com/stretchr/testify/assert" -) - -const tmpl = ` -<!DOCTYPE html> -<html> -<head> - <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> - <title>{{.Subject}}</title> -</head> - -<body> - <p>{{.Body}}</p> - <p> - --- - <br> - <a href="{{.Link}}">View it on Gitea</a>. - </p> -</body> -</html> -` - -func TestComposeIssueCommentMessage(t *testing.T) { - assert.NoError(t, PrepareTestDatabase()) - var MailService setting.Mailer - - MailService.From = "test@gitea.com" - setting.MailService = &MailService - - doer := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User) - repo := AssertExistsAndLoadBean(t, &Repository{ID: 1, Owner: doer}).(*Repository) - issue := AssertExistsAndLoadBean(t, &Issue{ID: 1, Repo: repo, Poster: doer}).(*Issue) - comment := AssertExistsAndLoadBean(t, &Comment{ID: 2, Issue: issue}).(*Comment) - - email := template.Must(template.New("issue/comment").Parse(tmpl)) - InitMailRender(email) - - tos := []string{"test@gitea.com", "test2@gitea.com"} - msg := composeIssueCommentMessage(issue, doer, "test body", comment, mailIssueComment, tos, "issue comment") - - subject := msg.GetHeader("Subject") - inreplyTo := msg.GetHeader("In-Reply-To") - references := msg.GetHeader("References") - - assert.Equal(t, subject[0], "Re: "+issue.mailSubject(), "Comment reply subject should contain Re:") - assert.Equal(t, inreplyTo[0], "<user2/repo1/issues/1@localhost>", "In-Reply-To header doesn't match") - assert.Equal(t, references[0], "<user2/repo1/issues/1@localhost>", "References header doesn't match") - -} - -func TestComposeIssueMessage(t *testing.T) { - assert.NoError(t, PrepareTestDatabase()) - var MailService setting.Mailer - - MailService.From = "test@gitea.com" - setting.MailService = &MailService - - doer := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User) - repo := AssertExistsAndLoadBean(t, &Repository{ID: 1, Owner: doer}).(*Repository) - issue := AssertExistsAndLoadBean(t, &Issue{ID: 1, Repo: repo, Poster: doer}).(*Issue) - - email := template.Must(template.New("issue/comment").Parse(tmpl)) - InitMailRender(email) - - tos := []string{"test@gitea.com", "test2@gitea.com"} - msg := composeIssueCommentMessage(issue, doer, "test body", nil, mailIssueComment, tos, "issue create") - - subject := msg.GetHeader("Subject") - messageID := msg.GetHeader("Message-ID") - - assert.Equal(t, subject[0], issue.mailSubject(), "Subject not equal to issue.mailSubject()") - assert.Nil(t, msg.GetHeader("In-Reply-To")) - assert.Nil(t, msg.GetHeader("References")) - assert.Equal(t, messageID[0], "<user2/repo1/issues/1@localhost>", "Message-ID header doesn't match") -} |