mirror of
https://github.com/go-gitea/gitea.git
synced 2025-08-03 12:49:46 +00:00
MOVE
This commit is contained in:
parent
de1114b4e8
commit
061d81788d
@ -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,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)
|
||||||
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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"))
|
||||||
|
@ -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)
|
|
||||||
}
|
|
||||||
|
@ -15,12 +15,13 @@ 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
|
||||||
@ -103,7 +104,7 @@ func composeAndSendActionsWorkflowRunStatusEmail(ctx context.Context, repo *repo
|
|||||||
runStatusText = "All jobs have been cancelled"
|
runStatusText = "All jobs have been cancelled"
|
||||||
}
|
}
|
||||||
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,
|
||||||
|
3
templates/mail/user/auth/activate_email.devtest.yml
Normal file
3
templates/mail/user/auth/activate_email.devtest.yml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
DisplayName: User Display Name
|
||||||
|
Code: The-Activation-Code
|
||||||
|
ActiveCodeLives: 24h
|
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
|
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-Activation-Code
|
||||||
|
ResetPwdCodeLives: 24h
|
Loading…
Reference in New Issue
Block a user