Skip to content

Commit

Permalink
Move all mail related codes from models to services/mailer (#7200)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
lunny authored Sep 24, 2019
1 parent 730065a commit 5a438ee
Show file tree
Hide file tree
Showing 22 changed files with 253 additions and 134 deletions.
55 changes: 55 additions & 0 deletions models/context.go
Original file line number Diff line number Diff line change
@@ -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
}
15 changes: 15 additions & 0 deletions models/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions models/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand All @@ -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)
}

Expand All @@ -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)
}
Expand All @@ -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)
}

Expand Down
35 changes: 0 additions & 35 deletions models/issue_comment.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions models/issue_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion models/issue_user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
Expand Down
11 changes: 6 additions & 5 deletions modules/notification/mail/mail.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/notification/base"
"code.gitea.io/gitea/services/mailer"
)

type mailNotifier struct {
Expand Down Expand Up @@ -36,13 +37,13 @@ func (m *mailNotifier) NotifyCreateIssueComment(doer *models.User, repo *models.
act = models.ActionCommentIssue
}

if err := comment.MailParticipants(act, issue); err != nil {
if err := mailer.MailParticipantsComment(comment, act, issue); err != nil {
log.Error("MailParticipants: %v", err)
}
}

func (m *mailNotifier) NotifyNewIssue(issue *models.Issue) {
if err := issue.MailParticipants(issue.Poster, models.ActionCreateIssue); err != nil {
if err := mailer.MailParticipants(issue, issue.Poster, models.ActionCreateIssue); err != nil {
log.Error("MailParticipants: %v", err)
}
}
Expand All @@ -63,13 +64,13 @@ func (m *mailNotifier) NotifyIssueChangeStatus(doer *models.User, issue *models.
}
}

if err := issue.MailParticipants(doer, actionType); err != nil {
if err := mailer.MailParticipants(issue, doer, actionType); err != nil {
log.Error("MailParticipants: %v", err)
}
}

func (m *mailNotifier) NotifyNewPullRequest(pr *models.PullRequest) {
if err := pr.Issue.MailParticipants(pr.Issue.Poster, models.ActionCreatePullRequest); err != nil {
if err := mailer.MailParticipants(pr.Issue, pr.Issue.Poster, models.ActionCreatePullRequest); err != nil {
log.Error("MailParticipants: %v", err)
}
}
Expand All @@ -83,7 +84,7 @@ func (m *mailNotifier) NotifyPullRequestReview(pr *models.PullRequest, r *models
} else if comment.Type == models.CommentTypeComment {
act = models.ActionCommentIssue
}
if err := comment.MailParticipants(act, pr.Issue); err != nil {
if err := mailer.MailParticipantsComment(comment, act, pr.Issue); err != nil {
log.Error("MailParticipants: %v", err)
}
}
3 changes: 2 additions & 1 deletion routers/admin/admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"code.gitea.io/gitea/modules/process"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/services/mailer"

"gitea.com/macaron/macaron"
"github.com/unknwon/com"
Expand Down Expand Up @@ -197,7 +198,7 @@ func Dashboard(ctx *context.Context) {
func SendTestMail(ctx *context.Context) {
email := ctx.Query("email")
// Send a test email to the user's email address and redirect back to Config
if err := models.SendTestMail(email); err != nil {
if err := mailer.SendTestMail(email); err != nil {
ctx.Flash.Error(ctx.Tr("admin.config.test_mail_failed", email, err))
} else {
ctx.Flash.Info(ctx.Tr("admin.config.test_mail_sent", email))
Expand Down
5 changes: 3 additions & 2 deletions routers/admin/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/routers"
"code.gitea.io/gitea/services/mailer"

"github.com/unknwon/com"
)
Expand Down Expand Up @@ -116,8 +117,8 @@ func NewUserPost(ctx *context.Context, form auth.AdminCreateUserForm) {
log.Trace("Account created by admin (%s): %s", ctx.User.Name, u.Name)

// Send email notification.
if form.SendNotify && setting.MailService != nil {
models.SendRegisterNotifyMail(ctx.Context, u)
if form.SendNotify {
mailer.SendRegisterNotifyMail(ctx.Locale, u)
}

ctx.Flash.Success(ctx.Tr("admin.users.new_success", u.Name))
Expand Down
6 changes: 3 additions & 3 deletions routers/api/v1/admin/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/routers/api/v1/convert"
"code.gitea.io/gitea/routers/api/v1/user"
"code.gitea.io/gitea/services/mailer"
)

func parseLoginSource(ctx *context.APIContext, u *models.User, sourceID int64, loginName string) {
Expand Down Expand Up @@ -88,8 +88,8 @@ func CreateUser(ctx *context.APIContext, form api.CreateUserOption) {
log.Trace("Account created by admin (%s): %s", ctx.User.Name, u.Name)

// Send email notification.
if form.SendNotify && setting.MailService != nil {
models.SendRegisterNotifyMail(ctx.Context.Context, u)
if form.SendNotify {
mailer.SendRegisterNotifyMail(ctx.Locale, u)
}
ctx.JSON(201, convert.ToUser(u, ctx.IsSigned, ctx.User.IsAdmin))
}
Expand Down
2 changes: 1 addition & 1 deletion routers/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ import (
"code.gitea.io/gitea/modules/highlight"
issue_indexer "code.gitea.io/gitea/modules/indexer/issues"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/mailer"
"code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/markup/external"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/ssh"
"code.gitea.io/gitea/services/mailer"

"gitea.com/macaron/macaron"
)
Expand Down
3 changes: 2 additions & 1 deletion routers/repo/setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/validation"
"code.gitea.io/gitea/routers/utils"
"code.gitea.io/gitea/services/mailer"

"github.com/unknwon/com"
"mvdan.cc/xurls/v2"
Expand Down Expand Up @@ -549,7 +550,7 @@ func CollaborationPost(ctx *context.Context) {
}

if setting.Service.EnableNotifyMail {
models.SendCollaboratorMail(u, ctx.User, ctx.Repo.Repository)
mailer.SendCollaboratorMail(u, ctx.User, ctx.Repo.Repository)
}

ctx.Flash.Success(ctx.Tr("repo.settings.add_collaborator_success"))
Expand Down
3 changes: 2 additions & 1 deletion routers/routes/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"code.gitea.io/gitea/routers/repo"
"code.gitea.io/gitea/routers/user"
userSetting "code.gitea.io/gitea/routers/user/setting"
"code.gitea.io/gitea/services/mailer"

// to registers all internal adapters
_ "code.gitea.io/gitea/modules/session"
Expand Down Expand Up @@ -166,7 +167,7 @@ func NewMacaron() *macaron.Macaron {
))

m.Use(templates.HTMLRenderer())
models.InitMailRender(templates.Mailer())
mailer.InitMailRender(templates.Mailer())

localeNames, err := options.Dir("locale")

Expand Down
Loading

0 comments on commit 5a438ee

Please sign in to comment.