jojo/services/mailer/mail_release.go
Gusted 5e1a2f9cc4 fix: filter recipients for new release mails
Remove recipients that are not active (e.g. done by moderation or
organizational reasons) and those that have the permi ssion to read
releases on that repository.
2026-03-06 11:21:07 -07:00

107 lines
2.9 KiB
Go

// Copyright 2020 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package mailer
import (
"bytes"
"context"
"slices"
access_model "forgejo.org/models/perm/access"
repo_model "forgejo.org/models/repo"
"forgejo.org/models/unit"
user_model "forgejo.org/models/user"
"forgejo.org/modules/base"
"forgejo.org/modules/log"
"forgejo.org/modules/markup"
"forgejo.org/modules/markup/markdown"
"forgejo.org/modules/setting"
"forgejo.org/modules/translation"
)
const (
tplNewReleaseMail base.TplName = "release"
)
// MailNewRelease send new release notify to all repo watchers.
func MailNewRelease(ctx context.Context, rel *repo_model.Release) {
if setting.MailService == nil {
// No mail service configured
return
}
watcherIDList, err := repo_model.GetRepoWatchersIDs(ctx, rel.RepoID)
if err != nil {
log.Error("GetRepoWatchersIDs(%d): %v", rel.RepoID, err)
return
}
recipients, err := user_model.GetMaileableUsersByIDs(ctx, watcherIDList, false)
if err != nil {
log.Error("user_model.GetMaileableUsersByIDs: %v", err)
return
}
// Users are not eligible to receive this mail if they are not active or
// they don't have permissions to read releases.
recipients = slices.DeleteFunc(recipients, func(u *user_model.User) bool {
return !u.IsActive || !access_model.CheckRepoUnitUser(ctx, rel.Repo, u, unit.TypeReleases)
})
langMap := make(map[string][]*user_model.User)
for _, user := range recipients {
if user.ID != rel.PublisherID {
langMap[user.Language] = append(langMap[user.Language], user)
}
}
for lang, tos := range langMap {
mailNewRelease(ctx, lang, tos, rel)
}
}
func mailNewRelease(ctx context.Context, lang string, tos []*user_model.User, rel *repo_model.Release) {
locale := translation.NewLocale(lang)
var err error
rel.RenderedNote, err = markdown.RenderString(&markup.RenderContext{
Ctx: ctx,
Links: markup.Links{
Base: rel.Repo.HTMLURL(),
},
Metas: rel.Repo.ComposeMetas(ctx),
}, rel.Note)
if err != nil {
log.Error("markdown.RenderString(%d): %v", rel.RepoID, err)
return
}
subject := locale.TrString("mail.release.new.subject", rel.TagName, rel.Repo.FullName())
mailMeta := map[string]any{
"locale": locale,
"Release": rel,
"Subject": subject,
"Language": locale.Language(),
"Link": rel.HTMLURL(),
}
var mailBody bytes.Buffer
if err := bodyTemplates.ExecuteTemplate(&mailBody, string(tplNewReleaseMail), mailMeta); err != nil {
log.Error("ExecuteTemplate [%s]: %v", string(tplNewReleaseMail)+"/body", err)
return
}
msgs := make([]*Message, 0, len(tos))
publisherName := fromDisplayName(rel.Publisher)
msgID := createMessageIDForRelease(rel)
for _, to := range tos {
msg := NewMessageFrom(to.EmailTo(), publisherName, setting.MailService.FromEmail, subject, mailBody.String())
msg.Info = subject
msg.SetHeader("Message-ID", msgID)
msgs = append(msgs, msg)
}
SendAsync(msgs...)
}