This commit is contained in:
NorthRealm 2025-07-26 12:02:44 -07:00 committed by GitHub
commit 84fa76ff64
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
31 changed files with 172 additions and 138 deletions

View File

@ -550,6 +550,14 @@ repo.transfer.body = To accept or reject it, visit %s or just ignore it.
repo.collaborator.added.subject = %s added you to %s repo.collaborator.added.subject = %s added you to %s
repo.collaborator.added.text = You have been added as a collaborator of repository: repo.collaborator.added.text = You have been added as a collaborator of repository:
repo.actions.run.failed = Run failed
repo.actions.run.succeeded = Run succeeded
repo.actions.run.cancelled = Run cancelled
repo.actions.jobs.all_succeeded = All jobs have succeeded
repo.actions.jobs.all_failed = All jobs have failed
repo.actions.jobs.some_not_successful = Some jobs were not successful
repo.actions.jobs.all_cancelled = All jobs have been cancelled
team_invite.subject = %[1]s has invited you to join the %[2]s organization team_invite.subject = %[1]s has invited you to join the %[2]s organization
team_invite.text_1 = %[1]s has invited you to join team %[2]s in organization %[3]s. team_invite.text_1 = %[1]s has invited you to join team %[2]s in organization %[3]s.
team_invite.text_2 = Please click the following link to join the team: team_invite.text_2 = Please click the following link to join the team:

View File

@ -260,18 +260,18 @@ func actionToTemplate(issue *issues_model.Issue, actionType activities_model.Act
} }
} }
template = typeName + "/" + name template = "repo/" + typeName + "/" + name
ok := LoadedTemplates().BodyTemplates.Lookup(template) != nil ok := LoadedTemplates().BodyTemplates.Lookup(template) != nil
if !ok && typeName != "issue" { if !ok && typeName != "issue" {
template = "issue/" + name template = "repo/issue/" + name
ok = LoadedTemplates().BodyTemplates.Lookup(template) != nil ok = LoadedTemplates().BodyTemplates.Lookup(template) != nil
} }
if !ok { if !ok {
template = typeName + "/default" template = "repo/" + typeName + "/default"
ok = LoadedTemplates().BodyTemplates.Lookup(template) != nil ok = LoadedTemplates().BodyTemplates.Lookup(template) != nil
} }
if !ok { if !ok {
template = "issue/default" template = "repo/issue/default"
} }
return typeName, name, template return typeName, name, template
} }

View File

@ -19,7 +19,7 @@ import (
sender_service "code.gitea.io/gitea/services/mailer/sender" sender_service "code.gitea.io/gitea/services/mailer/sender"
) )
const tplNewReleaseMail templates.TplName = "release" const tplNewReleaseMail templates.TplName = "repo/release"
func generateMessageIDForRelease(release *repo_model.Release) string { func generateMessageIDForRelease(release *repo_model.Release) string {
return fmt.Sprintf("<%s/releases/%d@%s>", release.Repo.FullName(), release.ID, setting.Domain) return fmt.Sprintf("<%s/releases/%d@%s>", release.Repo.FullName(), release.ID, setting.Domain)

View File

@ -11,13 +11,17 @@ import (
"code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/organization"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/translation" "code.gitea.io/gitea/modules/translation"
sender_service "code.gitea.io/gitea/services/mailer/sender" sender_service "code.gitea.io/gitea/services/mailer/sender"
) )
const mailRepoTransferNotify templates.TplName = "notify/repo_transfer" const (
mailNotifyCollaborator templates.TplName = "repo/collaborator"
mailRepoTransferNotify templates.TplName = "repo/transfer"
)
// SendRepoTransferNotifyMail triggers a notification e-mail when a pending repository transfer was created // SendRepoTransferNotifyMail triggers a notification e-mail when a pending repository transfer was created
func SendRepoTransferNotifyMail(ctx context.Context, doer, newOwner *user_model.User, repo *repo_model.Repository) error { func SendRepoTransferNotifyMail(ctx context.Context, doer, newOwner *user_model.User, repo *repo_model.Repository) error {
@ -91,3 +95,34 @@ func sendRepoTransferNotifyMailPerLang(lang string, newOwner, doer *user_model.U
return nil return nil
} }
// SendCollaboratorMail sends mail notification to new collaborator.
func SendCollaboratorMail(u, doer *user_model.User, repo *repo_model.Repository) {
if setting.MailService == nil || !u.IsActive {
// No mail service configured OR the user is inactive
return
}
locale := translation.NewLocale(u.Language)
repoName := repo.FullName()
subject := locale.TrString("mail.repo.collaborator.added.subject", doer.DisplayName(), repoName)
data := map[string]any{
"locale": locale,
"Subject": subject,
"RepoName": repoName,
"Link": repo.HTMLURL(),
"Language": locale.Language(),
}
var content bytes.Buffer
if err := LoadedTemplates().BodyTemplates.ExecuteTemplate(&content, string(mailNotifyCollaborator), data); err != nil {
log.Error("Template: %v", err)
return
}
msg := sender_service.NewMessage(u.EmailTo(), subject, content.String())
msg.Info = fmt.Sprintf("UID: %d, add collaborator", u.ID)
SendAsync(msg)
}

View File

@ -19,7 +19,7 @@ import (
sender_service "code.gitea.io/gitea/services/mailer/sender" sender_service "code.gitea.io/gitea/services/mailer/sender"
) )
const tplTeamInviteMail templates.TplName = "team_invite" const tplTeamInviteMail templates.TplName = "org/team_invite"
// MailTeamInvite sends team invites // MailTeamInvite sends team invites
func MailTeamInvite(ctx context.Context, inviter *user_model.User, team *org_model.Team, invite *org_model.TeamInvite) error { func MailTeamInvite(ctx context.Context, inviter *user_model.User, team *org_model.Team, invite *org_model.TeamInvite) error {

View File

@ -116,7 +116,7 @@ func TestComposeIssueComment(t *testing.T) {
setting.IncomingEmail.Enabled = true setting.IncomingEmail.Enabled = true
defer func() { setting.IncomingEmail.Enabled = false }() defer func() { setting.IncomingEmail.Enabled = false }()
prepareMailTemplates("issue/comment", subjectTpl, bodyTpl) prepareMailTemplates("repo/issue/comment", subjectTpl, bodyTpl)
recipients := []*user_model.User{{Name: "Test", Email: "test@gitea.com"}, {Name: "Test2", Email: "test2@gitea.com"}} recipients := []*user_model.User{{Name: "Test", Email: "test@gitea.com"}, {Name: "Test2", Email: "test2@gitea.com"}}
msgs, err := composeIssueCommentMessages(t.Context(), &mailComment{ msgs, err := composeIssueCommentMessages(t.Context(), &mailComment{
@ -161,7 +161,7 @@ func TestComposeIssueComment(t *testing.T) {
func TestMailMentionsComment(t *testing.T) { func TestMailMentionsComment(t *testing.T) {
doer, _, issue, comment := prepareMailerTest(t) doer, _, issue, comment := prepareMailerTest(t)
comment.Poster = doer comment.Poster = doer
prepareMailTemplates("issue/comment", subjectTpl, bodyTpl) prepareMailTemplates("repo/issue/comment", subjectTpl, bodyTpl)
mails := 0 mails := 0
defer test.MockVariableValue(&SendAsync, func(msgs ...*sender_service.Message) { defer test.MockVariableValue(&SendAsync, func(msgs ...*sender_service.Message) {
@ -176,7 +176,7 @@ func TestMailMentionsComment(t *testing.T) {
func TestComposeIssueMessage(t *testing.T) { func TestComposeIssueMessage(t *testing.T) {
doer, _, issue, _ := prepareMailerTest(t) doer, _, issue, _ := prepareMailerTest(t)
prepareMailTemplates("issue/new", subjectTpl, bodyTpl) prepareMailTemplates("repo/issue/new", subjectTpl, bodyTpl)
recipients := []*user_model.User{{Name: "Test", Email: "test@gitea.com"}, {Name: "Test2", Email: "test2@gitea.com"}} recipients := []*user_model.User{{Name: "Test", Email: "test@gitea.com"}, {Name: "Test2", Email: "test2@gitea.com"}}
msgs, err := composeIssueCommentMessages(t.Context(), &mailComment{ msgs, err := composeIssueCommentMessages(t.Context(), &mailComment{
Issue: issue, Doer: doer, ActionType: activities_model.ActionCreateIssue, Issue: issue, Doer: doer, ActionType: activities_model.ActionCreateIssue,
@ -205,14 +205,14 @@ func TestTemplateSelection(t *testing.T) {
doer, repo, issue, comment := prepareMailerTest(t) doer, repo, issue, comment := prepareMailerTest(t)
recipients := []*user_model.User{{Name: "Test", Email: "test@gitea.com"}} recipients := []*user_model.User{{Name: "Test", Email: "test@gitea.com"}}
prepareMailTemplates("issue/default", "issue/default/subject", "issue/default/body") prepareMailTemplates("repo/issue/default", "repo/issue/default/subject", "repo/issue/default/body")
texttmpl.Must(LoadedTemplates().SubjectTemplates.New("issue/new").Parse("issue/new/subject")) texttmpl.Must(LoadedTemplates().SubjectTemplates.New("repo/issue/new").Parse("repo/issue/new/subject"))
texttmpl.Must(LoadedTemplates().SubjectTemplates.New("pull/comment").Parse("pull/comment/subject")) texttmpl.Must(LoadedTemplates().SubjectTemplates.New("repo/pull/comment").Parse("repo/pull/comment/subject"))
texttmpl.Must(LoadedTemplates().SubjectTemplates.New("issue/close").Parse("")) // Must default to a fallback subject texttmpl.Must(LoadedTemplates().SubjectTemplates.New("repo/issue/close").Parse("")) // Must default to a fallback subject
template.Must(LoadedTemplates().BodyTemplates.New("issue/new").Parse("issue/new/body")) template.Must(LoadedTemplates().BodyTemplates.New("repo/issue/new").Parse("repo/issue/new/body"))
template.Must(LoadedTemplates().BodyTemplates.New("pull/comment").Parse("pull/comment/body")) template.Must(LoadedTemplates().BodyTemplates.New("repo/pull/comment").Parse("repo/pull/comment/body"))
template.Must(LoadedTemplates().BodyTemplates.New("issue/close").Parse("issue/close/body")) template.Must(LoadedTemplates().BodyTemplates.New("repo/issue/close").Parse("repo/issue/close/body"))
expect := func(t *testing.T, msg *sender_service.Message, expSubject, expBody string) { expect := func(t *testing.T, msg *sender_service.Message, expSubject, expBody string) {
subject := msg.ToMessage().GetGenHeader("Subject") subject := msg.ToMessage().GetGenHeader("Subject")
@ -227,13 +227,13 @@ func TestTemplateSelection(t *testing.T) {
Issue: issue, Doer: doer, ActionType: activities_model.ActionCreateIssue, Issue: issue, Doer: doer, ActionType: activities_model.ActionCreateIssue,
Content: "test body", Content: "test body",
}, recipients, false, "TestTemplateSelection") }, recipients, false, "TestTemplateSelection")
expect(t, msg, "issue/new/subject", "issue/new/body") expect(t, msg, "repo/issue/new/subject", "repo/issue/new/body")
msg = testComposeIssueCommentMessage(t, &mailComment{ msg = testComposeIssueCommentMessage(t, &mailComment{
Issue: issue, Doer: doer, ActionType: activities_model.ActionCommentIssue, Issue: issue, Doer: doer, ActionType: activities_model.ActionCommentIssue,
Content: "test body", Comment: comment, Content: "test body", Comment: comment,
}, recipients, false, "TestTemplateSelection") }, recipients, false, "TestTemplateSelection")
expect(t, msg, "issue/default/subject", "issue/default/body") expect(t, msg, "repo/issue/default/subject", "repo/issue/default/body")
pull := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2, Repo: repo, Poster: doer}) pull := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2, Repo: repo, Poster: doer})
comment = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 4, Issue: pull}) comment = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 4, Issue: pull})
@ -241,13 +241,13 @@ func TestTemplateSelection(t *testing.T) {
Issue: pull, Doer: doer, ActionType: activities_model.ActionCommentPull, Issue: pull, Doer: doer, ActionType: activities_model.ActionCommentPull,
Content: "test body", Comment: comment, Content: "test body", Comment: comment,
}, recipients, false, "TestTemplateSelection") }, recipients, false, "TestTemplateSelection")
expect(t, msg, "pull/comment/subject", "pull/comment/body") expect(t, msg, "repo/pull/comment/subject", "repo/pull/comment/body")
msg = testComposeIssueCommentMessage(t, &mailComment{ msg = testComposeIssueCommentMessage(t, &mailComment{
Issue: issue, Doer: doer, ActionType: activities_model.ActionCloseIssue, Issue: issue, Doer: doer, ActionType: activities_model.ActionCloseIssue,
Content: "test body", Comment: comment, Content: "test body", Comment: comment,
}, recipients, false, "TestTemplateSelection") }, recipients, false, "TestTemplateSelection")
expect(t, msg, "Re: [user2/repo1] issue1 (#1)", "issue/close/body") expect(t, msg, "Re: [user2/repo1] issue1 (#1)", "repo/issue/close/body")
} }
func TestTemplateServices(t *testing.T) { func TestTemplateServices(t *testing.T) {
@ -257,7 +257,7 @@ func TestTemplateServices(t *testing.T) {
expect := func(t *testing.T, issue *issues_model.Issue, comment *issues_model.Comment, doer *user_model.User, expect := func(t *testing.T, issue *issues_model.Issue, comment *issues_model.Comment, doer *user_model.User,
actionType activities_model.ActionType, fromMention bool, tplSubject, tplBody, expSubject, expBody string, actionType activities_model.ActionType, fromMention bool, tplSubject, tplBody, expSubject, expBody string,
) { ) {
prepareMailTemplates("issue/default", tplSubject, tplBody) prepareMailTemplates("repo/issue/default", tplSubject, tplBody)
recipients := []*user_model.User{{Name: "Test", Email: "test@gitea.com"}} recipients := []*user_model.User{{Name: "Test", Email: "test@gitea.com"}}
msg := testComposeIssueCommentMessage(t, &mailComment{ msg := testComposeIssueCommentMessage(t, &mailComment{
Issue: issue, Doer: doer, ActionType: actionType, Issue: issue, Doer: doer, ActionType: actionType,
@ -524,7 +524,7 @@ func TestEmbedBase64Images(t *testing.T) {
att2ImgBase64 := fmt.Sprintf(`<img src="%s"/>`, att2Base64) att2ImgBase64 := fmt.Sprintf(`<img src="%s"/>`, att2Base64)
t.Run("ComposeMessage", func(t *testing.T) { t.Run("ComposeMessage", func(t *testing.T) {
prepareMailTemplates("issue/new", subjectTpl, bodyTpl) prepareMailTemplates("repo/issue/new", subjectTpl, bodyTpl)
issue.Content = fmt.Sprintf(`MSG-BEFORE <image src="attachments/%s"> MSG-AFTER`, att1.UUID) issue.Content = fmt.Sprintf(`MSG-BEFORE <image src="attachments/%s"> MSG-AFTER`, att1.UUID)
require.NoError(t, issues_model.UpdateIssueCols(t.Context(), issue, "content")) require.NoError(t, issues_model.UpdateIssueCols(t.Context(), issue, "content"))

View File

@ -7,7 +7,6 @@ import (
"bytes" "bytes"
"fmt" "fmt"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
@ -18,11 +17,10 @@ import (
) )
const ( const (
mailAuthActivate templates.TplName = "auth/activate" mailAuthActivate templates.TplName = "user/auth/activate"
mailAuthActivateEmail templates.TplName = "auth/activate_email" mailAuthActivateEmail templates.TplName = "user/auth/activate_email"
mailAuthResetPassword templates.TplName = "auth/reset_passwd" mailAuthResetPassword templates.TplName = "user/auth/reset_passwd"
mailAuthRegisterNotify templates.TplName = "auth/register_notify" mailAuthRegisterNotify templates.TplName = "user/auth/register_notify"
mailNotifyCollaborator templates.TplName = "notify/collaborator"
) )
// sendUserMail sends a mail to the user // sendUserMail sends a mail to the user
@ -128,34 +126,3 @@ func SendRegisterNotifyMail(u *user_model.User) {
SendAsync(msg) SendAsync(msg)
} }
// SendCollaboratorMail sends mail notification to new collaborator.
func SendCollaboratorMail(u, doer *user_model.User, repo *repo_model.Repository) {
if setting.MailService == nil || !u.IsActive {
// No mail service configured OR the user is inactive
return
}
locale := translation.NewLocale(u.Language)
repoName := repo.FullName()
subject := locale.TrString("mail.repo.collaborator.added.subject", doer.DisplayName(), repoName)
data := map[string]any{
"locale": locale,
"Subject": subject,
"RepoName": repoName,
"Link": repo.HTMLURL(),
"Language": locale.Language(),
}
var content bytes.Buffer
if err := LoadedTemplates().BodyTemplates.ExecuteTemplate(&content, string(mailNotifyCollaborator), data); err != nil {
log.Error("Template: %v", err)
return
}
msg := sender_service.NewMessage(u.EmailTo(), subject, content.String())
msg.Info = fmt.Sprintf("UID: %d, add collaborator", u.ID)
SendAsync(msg)
}

View File

@ -8,6 +8,7 @@ import (
"context" "context"
"fmt" "fmt"
"sort" "sort"
"time"
actions_model "code.gitea.io/gitea/models/actions" actions_model "code.gitea.io/gitea/models/actions"
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
@ -15,18 +16,20 @@ import (
"code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/translation" "code.gitea.io/gitea/modules/translation"
"code.gitea.io/gitea/services/convert" "code.gitea.io/gitea/services/convert"
sender_service "code.gitea.io/gitea/services/mailer/sender" sender_service "code.gitea.io/gitea/services/mailer/sender"
) )
const tplWorkflowRun = "notify/workflow_run" const tplWorkflowRun templates.TplName = "repo/actions/workflow_run"
type convertedWorkflowJob struct { type convertedWorkflowJob struct {
HTMLURL string HTMLURL string
Status actions_model.Status Name string
Name string Status actions_model.Status
Attempt int64 Attempt int64
Duration time.Duration
} }
func generateMessageIDForActionsWorkflowRunStatusEmail(repo *repo_model.Repository, run *actions_model.ActionRun) string { func generateMessageIDForActionsWorkflowRunStatusEmail(repo *repo_model.Repository, run *actions_model.ActionRun) string {
@ -34,16 +37,15 @@ func generateMessageIDForActionsWorkflowRunStatusEmail(repo *repo_model.Reposito
} }
func composeAndSendActionsWorkflowRunStatusEmail(ctx context.Context, repo *repo_model.Repository, run *actions_model.ActionRun, sender *user_model.User, recipients []*user_model.User) { func composeAndSendActionsWorkflowRunStatusEmail(ctx context.Context, repo *repo_model.Repository, run *actions_model.ActionRun, sender *user_model.User, recipients []*user_model.User) {
subject := "Run" var subjectTrString string
switch run.Status { switch run.Status {
case actions_model.StatusFailure: case actions_model.StatusFailure:
subject += " failed" subjectTrString = "mail.repo.actions.run.failed"
case actions_model.StatusCancelled: case actions_model.StatusCancelled:
subject += " cancelled" subjectTrString = "mail.repo.actions.run.cancelled"
case actions_model.StatusSuccess: case actions_model.StatusSuccess:
subject += " succeeded" subjectTrString = "mail.repo.actions.run.succeeded"
} }
subject = fmt.Sprintf("%s: %s (%s)", subject, run.WorkflowID, base.ShortSha(run.CommitSHA))
displayName := fromDisplayName(sender) displayName := fromDisplayName(sender)
messageID := generateMessageIDForActionsWorkflowRunStatusEmail(repo, run) messageID := generateMessageIDForActionsWorkflowRunStatusEmail(repo, run)
metadataHeaders := generateMetadataHeaders(repo) metadataHeaders := generateMetadataHeaders(repo)
@ -74,10 +76,11 @@ func composeAndSendActionsWorkflowRunStatusEmail(ctx context.Context, repo *repo
continue continue
} }
convertedJobs = append(convertedJobs, convertedWorkflowJob{ convertedJobs = append(convertedJobs, convertedWorkflowJob{
HTMLURL: converted0.HTMLURL, HTMLURL: converted0.HTMLURL,
Name: converted0.Name, Name: converted0.Name,
Status: job.Status, Status: job.Status,
Attempt: converted0.RunAttempt, Attempt: converted0.RunAttempt,
Duration: job.Duration(),
}) })
} }
@ -87,27 +90,28 @@ func composeAndSendActionsWorkflowRunStatusEmail(ctx context.Context, repo *repo
} }
for lang, tos := range langMap { for lang, tos := range langMap {
locale := translation.NewLocale(lang) locale := translation.NewLocale(lang)
var runStatusText string var runStatusTrString string
switch run.Status { switch run.Status {
case actions_model.StatusSuccess: case actions_model.StatusSuccess:
runStatusText = "All jobs have succeeded" runStatusTrString = "mail.repo.actions.jobs.all_succeeded"
case actions_model.StatusFailure: case actions_model.StatusFailure:
runStatusText = "All jobs have failed" runStatusTrString = "mail.repo.actions.jobs.all_failed"
for _, job := range jobs { for _, job := range jobs {
if !job.Status.IsFailure() { if !job.Status.IsFailure() {
runStatusText = "Some jobs were not successful" runStatusTrString = "mail.repo.actions.jobs.some_not_successful"
break break
} }
} }
case actions_model.StatusCancelled: case actions_model.StatusCancelled:
runStatusText = "All jobs have been cancelled" runStatusTrString = "mail.repo.actions.jobs.all_cancelled"
} }
subject := fmt.Sprintf("%s: %s (%s)", locale.TrString(subjectTrString), run.WorkflowID, base.ShortSha(run.CommitSHA))
var mailBody bytes.Buffer var mailBody bytes.Buffer
if err := LoadedTemplates().BodyTemplates.ExecuteTemplate(&mailBody, tplWorkflowRun, map[string]any{ if err := LoadedTemplates().BodyTemplates.ExecuteTemplate(&mailBody, string(tplWorkflowRun), map[string]any{
"Subject": subject, "Subject": subject,
"Repo": repo, "Repo": repo,
"Run": run, "Run": run,
"RunStatusText": runStatusText, "RunStatusText": locale.TrString(runStatusTrString),
"Jobs": convertedJobs, "Jobs": convertedJobs,
"locale": locale, "locale": locale,
}); err != nil { }); err != nil {

View File

@ -0,0 +1,6 @@
<!DOCTYPE html>
<html>
<body>
<p>© <a target="_blank" rel="noopener noreferrer" href="{{AppUrl}}">{{AppName}}</a></p>
</body>
</html>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<body>
<div style="font-size:small; color:#666;">
<p>
---
<br>
<a href="{{.Link}}">{{.locale.Tr "mail.view_it_on" AppName}}</a>{{if .CanReply}}&nbsp;{{.locale.Tr "mail.reply"}}{{end}}.
</p>
</div>
</body>
</html>

View File

@ -0,0 +1,13 @@
Inviter:
DisplayName: Inviter Display Name
Team:
Name: Team name
Organization:
DisplayName: Organization Display Name
InviteURL: http://localhost/org/team/invite
Invite:
Email: invited@example.com

View File

@ -10,6 +10,6 @@
<p>{{.locale.Tr "mail.link_not_working_do_paste"}}</p> <p>{{.locale.Tr "mail.link_not_working_do_paste"}}</p>
<p>{{.locale.Tr "mail.team_invite.text_3" .Invite.Email}}</p> <p>{{.locale.Tr "mail.team_invite.text_3" .Invite.Email}}</p>
<p>© <a target="_blank" rel="noopener noreferrer" href="{{AppUrl}}">{{AppName}}</a></p> {{template "footer_gitea"}}
</body> </body>
</html> </html>

View File

@ -1,10 +1,10 @@
RunStatusText: run status text .... RunStatusText: Jobs status aggregation
Repo: Repo:
FullName: RepoName FullName: Repo/Name
Run: Run:
WorkflowID: WorkflowID WorkflowID: workflow.yml
HTMLURL: http://localhost/run/1 HTMLURL: http://localhost/run/1
Jobs: Jobs:
@ -12,7 +12,9 @@ Jobs:
Status: success Status: success
Attempt: 1 Attempt: 1
HTMLURL: http://localhost/job/1 HTMLURL: http://localhost/job/1
Duration: 1h2m3s
- Name: Job-Name-2 - Name: Job-Name-2
Status: failed Status: failure
Attempt: 2 Attempt: 2
HTMLURL: http://localhost/job/2 HTMLURL: http://localhost/job/2
Duration: 1h2m3s

View File

@ -15,7 +15,7 @@
{{range $job := .Jobs}} {{range $job := .Jobs}}
<li style="background-color: #ffffff; border: 1px solid #ddd; border-radius: 6px; padding: 12px 16px; margin-bottom: 10px; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05); transition: box-shadow 0.2s ease;"> <li style="background-color: #ffffff; border: 1px solid #ddd; border-radius: 6px; padding: 12px 16px; margin-bottom: 10px; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05); transition: box-shadow 0.2s ease;">
<a href="{{$job.HTMLURL}}" style="color: #0073e6; text-decoration: none; font-weight: bold;"> <a href="{{$job.HTMLURL}}" style="color: #0073e6; text-decoration: none; font-weight: bold;">
{{$job.Status}}: {{$job.Name}}{{if gt $job.Attempt 1}}, Attempt #{{$job.Attempt}}{{end}} {{$job.Status}}: {{$job.Name}}{{if gt $job.Attempt 1}}, Attempt #{{$job.Attempt}}{{end}}, {{$job.Duration}}
</a> </a>
</li> </li>
{{end}} {{end}}

View File

@ -0,0 +1,3 @@
Subject: Collaborator added
Link: http://localhost
RepoName: Repo/Name

View File

@ -1,21 +1,12 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<style>
.footer { font-size:small; color:#666;}
</style>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>{{.Subject}}</title> <title>{{.Subject}}</title>
</head> </head>
<body> <body>
<p>{{.locale.Tr "mail.repo.collaborator.added.text"}} <code>{{.RepoName}}</code></p> <p>{{.locale.Tr "mail.repo.collaborator.added.text"}} <code>{{.RepoName}}</code></p>
<div class="footer"> {{template "footer_view_on_gitea" .}}
<p>
---
<br>
<a href="{{.Link}}">{{.locale.Tr "mail.view_it_on" AppName}}</a>.
</p>
</div>
</body> </body>
</html> </html>

View File

@ -0,0 +1,11 @@
Subject: Issue assigned
Link: http://localhost
Issue:
Index: 1
Repo:
FullName: Repo/Name
HTMLURL: http://localhost/issue
Doer:
Name: DoerName

View File

@ -1,9 +1,6 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<style>
.footer { font-size:small; color:#666;}
</style>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>{{.Subject}}</title> <title>{{.Subject}}</title>
</head> </head>
@ -18,12 +15,6 @@
{{.locale.Tr "mail.issue_assigned.issue" .Doer.Name $link $repo_url}} {{.locale.Tr "mail.issue_assigned.issue" .Doer.Name $link $repo_url}}
{{end}} {{end}}
</p> </p>
<div class="footer"> {{template "footer_view_on_gitea" .}}
<p>
---
<br>
<a href="{{.Link}}">{{.locale.Tr "mail.view_it_on" AppName}}</a>.
</p>
</div>
</body> </body>
</html> </html>

View File

@ -0,0 +1 @@
CanReply: true

View File

@ -6,11 +6,6 @@
<style> <style>
blockquote { padding-left: 1em; margin: 1em 0; border-left: 1px solid grey; color: #777} blockquote { padding-left: 1em; margin: 1em 0; border-left: 1px solid grey; color: #777}
.footer { font-size:small; color:#666;}
{{if .ReviewComments}}
.review { padding-left: 1em; margin: 1em 0; }
.review > pre { padding: 1em; border-left: 1px solid grey; }
{{end}}
</style> </style>
</head> </head>
@ -63,8 +58,8 @@
{{- range .ReviewComments}} {{- range .ReviewComments}}
<hr> <hr>
{{$.locale.Tr "mail.issue.in_tree_path" .TreePath}} {{$.locale.Tr "mail.issue.in_tree_path" .TreePath}}
<div class="review"> <div style="padding-left: 1em; margin: 1em 0;">
<pre>{{.Patch}}</pre> <pre style="padding: 1em; border-left: 1px solid grey;">{{.Patch}}</pre>
<div>{{.RenderedContent}}</div> <div>{{.RenderedContent}}</div>
</div> </div>
{{end -}} {{end -}}
@ -80,12 +75,6 @@
</ul> </ul>
{{end}} {{end}}
</p> </p>
<div class="footer"> {{template "footer_view_on_gitea" .}}
<p>
---
<br>
<a href="{{.Link}}">{{.locale.Tr "mail.view_it_on" AppName}}</a>{{if .CanReply}} {{.locale.Tr "mail.reply"}}{{end}}.
</p>
</div>
</body> </body>
</html> </html>

View File

@ -6,7 +6,6 @@
<style> <style>
blockquote { padding-left: 1em; margin: 1em 0; border-left: 1px solid grey; color: #777} blockquote { padding-left: 1em; margin: 1em 0; border-left: 1px solid grey; color: #777}
.footer { font-size:small; color:#666;}
</style> </style>
</head> </head>
@ -50,12 +49,6 @@
{{end}} {{end}}
</ul> </ul>
</p> </p>
<div class="footer"> {{template "footer_view_on_gitea" .}}
<p>
---
<br>
<a href="{{.Link}}">{{.locale.Tr "mail.view_it_on" AppName}}</a>.
</p>
</div>
</body> </body>
</html> </html>

View File

@ -0,0 +1,3 @@
Subject: Repository transfer
Link: http://localhost
Repo: Repo/Name

View File

@ -10,10 +10,6 @@
<p>{{.Subject}}. <p>{{.Subject}}.
{{.locale.Tr "mail.repo.transfer.body" $url}} {{.locale.Tr "mail.repo.transfer.body" $url}}
</p> </p>
<p> {{template "footer_view_on_gitea" .}}
---
<br>
<a href="{{.Link}}">{{.locale.Tr "mail.view_it_on" AppName}}</a>.
</p>
</body> </body>
</html> </html>

View File

@ -12,6 +12,6 @@
<p>{{.locale.Tr "mail.activate_account.text_2" .ActiveCodeLives}}</p><p><a href="{{$activate_url}}">{{$activate_url}}</a></p><br> <p>{{.locale.Tr "mail.activate_account.text_2" .ActiveCodeLives}}</p><p><a href="{{$activate_url}}">{{$activate_url}}</a></p><br>
<p>{{.locale.Tr "mail.link_not_working_do_paste"}}</p> <p>{{.locale.Tr "mail.link_not_working_do_paste"}}</p>
<p>© <a target="_blank" rel="noopener noreferrer" href="{{AppUrl}}">{{AppName}}</a></p> {{template "footer_gitea"}}
</body> </body>
</html> </html>

View File

@ -0,0 +1,4 @@
DisplayName: User Display Name
Code: The-Activation-Code
Email: admin@example.com
ActiveCodeLives: 24h

View File

@ -12,6 +12,6 @@
<p>{{.locale.Tr "mail.activate_email.text" .ActiveCodeLives}}</p><p><a href="{{$activate_url}}">{{$activate_url}}</a></p><br> <p>{{.locale.Tr "mail.activate_email.text" .ActiveCodeLives}}</p><p><a href="{{$activate_url}}">{{$activate_url}}</a></p><br>
<p>{{.locale.Tr "mail.link_not_working_do_paste"}}</p> <p>{{.locale.Tr "mail.link_not_working_do_paste"}}</p>
<p>© <a target="_blank" rel="noopener noreferrer" href="{{AppUrl}}">{{AppName}}</a></p> {{template "footer_gitea"}}
</body> </body>
</html> </html>

View File

@ -0,0 +1,2 @@
DisplayName: User Display Name
Username: Username

View File

@ -13,6 +13,6 @@
<p>{{.locale.Tr "mail.register_notify.text_2" .Username}}</p><p><a href="{{AppUrl}}user/login">{{AppUrl}}user/login</a></p><br> <p>{{.locale.Tr "mail.register_notify.text_2" .Username}}</p><p><a href="{{AppUrl}}user/login">{{AppUrl}}user/login</a></p><br>
<p>{{.locale.Tr "mail.register_notify.text_3" $set_pwd_url}}</p><br> <p>{{.locale.Tr "mail.register_notify.text_3" $set_pwd_url}}</p><br>
<p>© <a target="_blank" rel="noopener noreferrer" href="{{AppUrl}}">{{AppName}}</a></p> {{template "footer_gitea"}}
</body> </body>
</html> </html>

View File

@ -0,0 +1,3 @@
DisplayName: User Display Name
Code: The-Reset-Token
ResetPwdCodeLives: 24h

View File

@ -12,6 +12,6 @@
<p>{{.locale.Tr "mail.reset_password.text" .ResetPwdCodeLives}}</p><p><a href="{{$recover_url}}">{{$recover_url}}</a></p><br> <p>{{.locale.Tr "mail.reset_password.text" .ResetPwdCodeLives}}</p><p><a href="{{$recover_url}}">{{$recover_url}}</a></p><br>
<p>{{.locale.Tr "mail.link_not_working_do_paste"}}</p> <p>{{.locale.Tr "mail.link_not_working_do_paste"}}</p>
<p>© <a target="_blank" rel="noopener noreferrer" href="{{AppUrl}}">{{AppName}}</a></p> {{template "footer_gitea"}}
</body> </body>
</html> </html>