mirror of
				https://github.com/go-gitea/gitea
				synced 2025-11-04 05:18:25 +00:00 
			
		
		
		
	Refactor and update mail templates (#35150)
- Moved mail templates to new directories. - Added new devtest ymls. - Embedded styles as much as possible. - Added new translation keys for actions email. --------- Signed-off-by: NorthRealm <155140859+NorthRealm@users.noreply.github.com> Co-authored-by: delvh <dev.lh@web.de>
This commit is contained in:
		@@ -551,6 +551,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:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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,33 @@ 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 {
 | 
				
			||||||
 | 
							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)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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 {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -115,7 +115,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{
 | 
				
			||||||
@@ -160,7 +160,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) {
 | 
				
			||||||
@@ -175,7 +175,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,
 | 
				
			||||||
@@ -204,14 +204,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")
 | 
				
			||||||
@@ -226,13 +226,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})
 | 
				
			||||||
@@ -240,13 +240,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) {
 | 
				
			||||||
@@ -256,7 +256,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,
 | 
				
			||||||
@@ -523,7 +523,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"))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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 {
 | 
				
			||||||
@@ -45,16 +48,15 @@ func composeAndSendActionsWorkflowRunStatusEmail(ctx context.Context, repo *repo
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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)
 | 
				
			||||||
@@ -84,6 +86,7 @@ func composeAndSendActionsWorkflowRunStatusEmail(ctx context.Context, repo *repo
 | 
				
			|||||||
			Name:     converted0.Name,
 | 
								Name:     converted0.Name,
 | 
				
			||||||
			Status:   job.Status,
 | 
								Status:   job.Status,
 | 
				
			||||||
			Attempt:  converted0.RunAttempt,
 | 
								Attempt:  converted0.RunAttempt,
 | 
				
			||||||
 | 
								Duration: job.Duration(),
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -93,27 +96,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 {
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										13
									
								
								templates/mail/org/team_invite.devtest.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								templates/mail/org/team_invite.devtest.yml
									
									
									
									
									
										Normal 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
 | 
				
			||||||
@@ -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>
 | 
						<p>© <a href="{{AppUrl}}">{{AppName}}</a></p>
 | 
				
			||||||
</body>
 | 
					</body>
 | 
				
			||||||
</html>
 | 
					</html>
 | 
				
			||||||
@@ -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
 | 
				
			||||||
@@ -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}}
 | 
				
			||||||
							
								
								
									
										3
									
								
								templates/mail/repo/collaborator.devtest.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								templates/mail/repo/collaborator.devtest.yml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					Subject: Collaborator added
 | 
				
			||||||
 | 
					Link: http://localhost
 | 
				
			||||||
 | 
					RepoName: Repo/Name
 | 
				
			||||||
@@ -1,16 +1,13 @@
 | 
				
			|||||||
<!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">
 | 
						<div style="font-size:small; color:#666;">
 | 
				
			||||||
		<p>
 | 
							<p>
 | 
				
			||||||
			---
 | 
								---
 | 
				
			||||||
			<br>
 | 
								<br>
 | 
				
			||||||
							
								
								
									
										11
									
								
								templates/mail/repo/issue/assigned.devtest.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								templates/mail/repo/issue/assigned.devtest.yml
									
									
									
									
									
										Normal 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
 | 
				
			||||||
@@ -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,7 +15,7 @@
 | 
				
			|||||||
			{{.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">
 | 
						<div style="font-size:small; color:#666;">
 | 
				
			||||||
		<p>
 | 
							<p>
 | 
				
			||||||
			---
 | 
								---
 | 
				
			||||||
			<br>
 | 
								<br>
 | 
				
			||||||
							
								
								
									
										1
									
								
								templates/mail/repo/issue/default.devtest.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								templates/mail/repo/issue/default.devtest.yml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					CanReply: true
 | 
				
			||||||
@@ -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,11 +75,11 @@
 | 
				
			|||||||
			</ul>
 | 
								</ul>
 | 
				
			||||||
		{{end}}
 | 
							{{end}}
 | 
				
			||||||
	</p>
 | 
						</p>
 | 
				
			||||||
	<div class="footer">
 | 
						<div style="font-size:small; color:#666;">
 | 
				
			||||||
		<p>
 | 
							<p>
 | 
				
			||||||
			---
 | 
								---
 | 
				
			||||||
			<br>
 | 
								<br>
 | 
				
			||||||
		<a href="{{.Link}}">{{.locale.Tr "mail.view_it_on" AppName}}</a>{{if .CanReply}} {{.locale.Tr "mail.reply"}}{{end}}.
 | 
								<a href="{{.Link}}">{{.locale.Tr "mail.view_it_on" AppName}}</a>{{if .CanReply}} {{.locale.Tr "mail.reply"}}{{end}}.
 | 
				
			||||||
		</p>
 | 
							</p>
 | 
				
			||||||
	</div>
 | 
						</div>
 | 
				
			||||||
</body>
 | 
					</body>
 | 
				
			||||||
@@ -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,7 +49,7 @@
 | 
				
			|||||||
			{{end}}
 | 
								{{end}}
 | 
				
			||||||
		</ul>
 | 
							</ul>
 | 
				
			||||||
	</p>
 | 
						</p>
 | 
				
			||||||
	<div class="footer">
 | 
						<div style="font-size:small; color:#666;">
 | 
				
			||||||
		<p>
 | 
							<p>
 | 
				
			||||||
			---
 | 
								---
 | 
				
			||||||
			<br>
 | 
								<br>
 | 
				
			||||||
							
								
								
									
										3
									
								
								templates/mail/repo/transfer.devtest.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								templates/mail/repo/transfer.devtest.yml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					Subject: Repository transfer
 | 
				
			||||||
 | 
					Link: http://localhost
 | 
				
			||||||
 | 
					Repo: Repo/Name
 | 
				
			||||||
@@ -10,10 +10,12 @@
 | 
				
			|||||||
	<p>{{.Subject}}.
 | 
						<p>{{.Subject}}.
 | 
				
			||||||
		{{.locale.Tr "mail.repo.transfer.body" $url}}
 | 
							{{.locale.Tr "mail.repo.transfer.body" $url}}
 | 
				
			||||||
	</p>
 | 
						</p>
 | 
				
			||||||
 | 
						<div style="font-size:small; color:#666;">
 | 
				
			||||||
		<p>
 | 
							<p>
 | 
				
			||||||
			---
 | 
								---
 | 
				
			||||||
			<br>
 | 
								<br>
 | 
				
			||||||
			<a href="{{.Link}}">{{.locale.Tr "mail.view_it_on" AppName}}</a>.
 | 
								<a href="{{.Link}}">{{.locale.Tr "mail.view_it_on" AppName}}</a>.
 | 
				
			||||||
		</p>
 | 
							</p>
 | 
				
			||||||
 | 
						</div>
 | 
				
			||||||
</body>
 | 
					</body>
 | 
				
			||||||
</html>
 | 
					</html>
 | 
				
			||||||
@@ -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>
 | 
						<p>© <a href="{{AppUrl}}">{{AppName}}</a></p>
 | 
				
			||||||
</body>
 | 
					</body>
 | 
				
			||||||
</html>
 | 
					</html>
 | 
				
			||||||
							
								
								
									
										4
									
								
								templates/mail/user/auth/activate_email.devtest.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								templates/mail/user/auth/activate_email.devtest.yml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					DisplayName: User Display Name
 | 
				
			||||||
 | 
					Code: The-Activation-Code
 | 
				
			||||||
 | 
					Email: admin@example.com
 | 
				
			||||||
 | 
					ActiveCodeLives: 24h
 | 
				
			||||||
@@ -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>
 | 
						<p>© <a href="{{AppUrl}}">{{AppName}}</a></p>
 | 
				
			||||||
</body>
 | 
					</body>
 | 
				
			||||||
</html>
 | 
					</html>
 | 
				
			||||||
							
								
								
									
										2
									
								
								templates/mail/user/auth/register_notify.devtest.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								templates/mail/user/auth/register_notify.devtest.yml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					DisplayName: User Display Name
 | 
				
			||||||
 | 
					Username: Username
 | 
				
			||||||
@@ -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>
 | 
						<p>© <a href="{{AppUrl}}">{{AppName}}</a></p>
 | 
				
			||||||
</body>
 | 
					</body>
 | 
				
			||||||
</html>
 | 
					</html>
 | 
				
			||||||
							
								
								
									
										3
									
								
								templates/mail/user/auth/reset_passwd.devtest.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								templates/mail/user/auth/reset_passwd.devtest.yml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					DisplayName: User Display Name
 | 
				
			||||||
 | 
					Code: The-Reset-Token
 | 
				
			||||||
 | 
					ResetPwdCodeLives: 24h
 | 
				
			||||||
@@ -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>
 | 
						<p>© <a href="{{AppUrl}}">{{AppName}}</a></p>
 | 
				
			||||||
</body>
 | 
					</body>
 | 
				
			||||||
</html>
 | 
					</html>
 | 
				
			||||||
		Reference in New Issue
	
	Block a user