mirror of
https://github.com/go-vikunja/vikunja.git
synced 2026-08-22 12:12:18 -05:00
The capability interface carrying a notification's project was optional, and ProjectIDOf defaulted a missing implementation to 0 — which means account-scoped, which means always visible. So a new project-scoped type whose author forgot the method would have leaked task titles, project names and comment bodies to users with no access to the project, with no compile error and no test failure. Register now takes a factory returning PersistedNotification, which requires the method. Registering is what makes a notification persist, so a stored row that cannot be permission-checked no longer compiles. The three account-scoped types say so by returning 0 explicitly instead of by omission.
511 lines
20 KiB
Go
511 lines
20 KiB
Go
// Vikunja is a to-do list application to facilitate your life.
|
|
// Copyright 2018-present Vikunja and contributors. All rights reserved.
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
package models
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"strconv"
|
|
"time"
|
|
|
|
"code.vikunja.io/api/pkg/config"
|
|
"code.vikunja.io/api/pkg/db"
|
|
"code.vikunja.io/api/pkg/i18n"
|
|
"code.vikunja.io/api/pkg/mail"
|
|
"code.vikunja.io/api/pkg/modules/avatar"
|
|
"code.vikunja.io/api/pkg/notifications"
|
|
"code.vikunja.io/api/pkg/user"
|
|
"code.vikunja.io/api/pkg/utils"
|
|
)
|
|
|
|
func init() {
|
|
notifications.Register(func() notifications.PersistedNotification { return &ReminderDueNotification{} })
|
|
notifications.Register(func() notifications.PersistedNotification { return &TaskCommentNotification{} })
|
|
notifications.Register(func() notifications.PersistedNotification { return &TaskAssignedNotification{} })
|
|
notifications.Register(func() notifications.PersistedNotification { return &TaskDeletedNotification{} })
|
|
notifications.Register(func() notifications.PersistedNotification { return &ProjectCreatedNotification{} })
|
|
notifications.Register(func() notifications.PersistedNotification { return &TeamMemberAddedNotification{} })
|
|
notifications.Register(func() notifications.PersistedNotification { return &UserMentionedInTaskNotification{} })
|
|
}
|
|
|
|
// getDoerAvatarDataURI returns the avatar data URI for a user, for use in email headers.
|
|
func getDoerAvatarDataURI(doer *user.User) string {
|
|
provider := avatar.GetProvider(doer)
|
|
dataURI, err := provider.AsDataURI(doer, 20)
|
|
if err != nil {
|
|
return ""
|
|
}
|
|
return dataURI
|
|
}
|
|
|
|
// getThreadID generates a Message-ID format thread ID for a task
|
|
func getThreadID(taskID int64) string {
|
|
return fmt.Sprintf("<task-%d@%s>", taskID, mail.GetMailDomain())
|
|
}
|
|
|
|
// ReminderDueNotification represents a ReminderDueNotification notification
|
|
type ReminderDueNotification struct {
|
|
User *user.User `json:"user,omitempty"`
|
|
Task *Task `json:"task"`
|
|
Project *Project `json:"project"`
|
|
TaskReminder *TaskReminder `json:"reminder"`
|
|
}
|
|
|
|
// ToTitle returns the translated one-line title for ReminderDueNotification
|
|
func (n *ReminderDueNotification) ToTitle(lang string) string {
|
|
return i18n.T(lang, "notifications.task.reminder.subject", n.Task.Title, n.Project.Title)
|
|
}
|
|
|
|
// ToMail returns the mail notification for ReminderDueNotification
|
|
func (n *ReminderDueNotification) ToMail(lang string) *notifications.Mail {
|
|
return notifications.NewMail().
|
|
IncludeLinkToSettings(lang).
|
|
To(n.User.Email).
|
|
Greeting(i18n.T(lang, "notifications.greeting", n.User.GetName())).
|
|
Line(i18n.T(lang, "notifications.task.reminder.message", notifications.EscapeMarkdown(n.Task.Title), notifications.EscapeMarkdown(n.Project.Title))).
|
|
Action(i18n.T(lang, "notifications.common.actions.open_task"), config.ServicePublicURL.GetString()+"tasks/"+strconv.FormatInt(n.Task.ID, 10)).
|
|
Line(i18n.T(lang, "notifications.common.have_nice_day"))
|
|
}
|
|
|
|
// ToDB returns the ReminderDueNotification notification in a format which can be saved in the db
|
|
func (n *ReminderDueNotification) ToDB() interface{} {
|
|
return &ReminderDueNotification{
|
|
Task: n.Task,
|
|
Project: n.Project,
|
|
}
|
|
}
|
|
|
|
// Name returns the name of the notification
|
|
func (n *ReminderDueNotification) Name() string {
|
|
return "task.reminder"
|
|
}
|
|
|
|
// ThreadID returns the thread ID for email threading
|
|
func (n *ReminderDueNotification) ThreadID() string {
|
|
return getThreadID(n.Task.ID)
|
|
}
|
|
|
|
// TaskCommentNotification represents a TaskCommentNotification notification
|
|
type TaskCommentNotification struct {
|
|
Doer *user.User `json:"doer"`
|
|
Task *Task `json:"task"`
|
|
Comment *TaskComment `json:"comment"`
|
|
Mentioned bool `json:"mentioned"`
|
|
Project *Project `json:"project"`
|
|
}
|
|
|
|
func (n *TaskCommentNotification) SubjectID() int64 {
|
|
return n.Comment.ID
|
|
}
|
|
|
|
// ToTitle returns the translated one-line title for TaskCommentNotification
|
|
func (n *TaskCommentNotification) ToTitle(lang string) string {
|
|
if n.Mentioned {
|
|
return i18n.T(lang, "notifications.task.comment.mentioned_subject", n.Doer.GetName(), n.Task.Title, n.Task.GetFullIdentifier())
|
|
}
|
|
return i18n.T(lang, "notifications.task.comment.subject", n.Task.Title, n.Task.GetFullIdentifier())
|
|
}
|
|
|
|
// ToMail returns the mail notification for TaskCommentNotification
|
|
func (n *TaskCommentNotification) ToMail(lang string) *notifications.Mail {
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
formattedComment := formatMentionsForEmail(s, n.Comment.Comment)
|
|
|
|
mail := notifications.NewMail().
|
|
Conversational().
|
|
From(n.Doer.GetNameAndFromEmail())
|
|
|
|
// Add header line
|
|
action := i18n.T(lang, "notifications.common.actions.left_comment", n.Doer.GetName())
|
|
if n.Mentioned {
|
|
action = i18n.T(lang, "notifications.common.actions.mentioned_you_comment", n.Doer.GetName())
|
|
}
|
|
|
|
headerLine := notifications.CreateConversationalHeader(
|
|
getDoerAvatarDataURI(n.Doer),
|
|
action,
|
|
n.Task.GetFrontendURL(),
|
|
n.Project.Title,
|
|
n.Task.GetFullIdentifier(),
|
|
n.Task.Title,
|
|
)
|
|
mail.HeaderLine(headerLine)
|
|
|
|
// Add the actual comment content wrapped in a div for consistent spacing
|
|
mail.HTML(formattedComment)
|
|
|
|
return mail.
|
|
Action(i18n.T(lang, "notifications.common.actions.open_task"), n.Task.GetFrontendURL()).
|
|
IncludeLinkToSettings(lang)
|
|
}
|
|
|
|
// ToDB returns the TaskCommentNotification notification in a format which can be saved in the db
|
|
func (n *TaskCommentNotification) ToDB() interface{} {
|
|
return n
|
|
}
|
|
|
|
// Name returns the name of the notification
|
|
func (n *TaskCommentNotification) Name() string {
|
|
return "task.comment"
|
|
}
|
|
|
|
// ThreadID returns the thread ID for email threading
|
|
func (n *TaskCommentNotification) ThreadID() string {
|
|
return getThreadID(n.Task.ID)
|
|
}
|
|
|
|
// TaskAssignedNotification represents a TaskAssignedNotification notification
|
|
type TaskAssignedNotification struct {
|
|
Doer *user.User `json:"doer"`
|
|
Task *Task `json:"task"`
|
|
Assignee *user.User `json:"assignee"`
|
|
Target *user.User `json:"-"`
|
|
Project *Project `json:"project"`
|
|
}
|
|
|
|
// ToTitle returns the translated one-line title for TaskAssignedNotification
|
|
func (n *TaskAssignedNotification) ToTitle(lang string) string {
|
|
if n.Target.ID == n.Assignee.ID {
|
|
return i18n.T(lang, "notifications.task.assigned.subject_to_assignee", n.Task.Title, n.Task.GetFullIdentifier())
|
|
}
|
|
if n.Doer.ID == n.Assignee.ID {
|
|
return i18n.T(lang, "notifications.task.assigned.subject_to_others_self", n.Task.Title, n.Task.GetFullIdentifier(), n.Doer.GetName())
|
|
}
|
|
return i18n.T(lang, "notifications.task.assigned.subject_to_others", n.Task.Title, n.Task.GetFullIdentifier(), n.Assignee.GetName())
|
|
}
|
|
|
|
// ToMail returns the mail notification for TaskAssignedNotification
|
|
func (n *TaskAssignedNotification) ToMail(lang string) *notifications.Mail {
|
|
if n.Target.ID == n.Assignee.ID {
|
|
// Notification to the assignee
|
|
return notifications.NewMail().
|
|
From(n.Doer.GetNameAndFromEmail()).
|
|
Greeting(i18n.T(lang, "notifications.greeting", n.Target.GetName())).
|
|
Line(i18n.T(lang, "notifications.task.assigned.message_to_assignee", notifications.EscapeMarkdown(n.Doer.GetName()), notifications.EscapeMarkdown(n.Task.Title))).
|
|
Action(i18n.T(lang, "notifications.common.actions.open_task"), n.Task.GetFrontendURL()).
|
|
IncludeLinkToSettings(lang)
|
|
}
|
|
|
|
// Check if the doer assigned the task to themselves
|
|
if n.Doer.ID == n.Assignee.ID {
|
|
return notifications.NewMail().
|
|
From(n.Doer.GetNameAndFromEmail()).
|
|
Greeting(i18n.T(lang, "notifications.greeting", n.Target.GetName())).
|
|
Line(i18n.T(lang, "notifications.task.assigned.message_to_others_self", notifications.EscapeMarkdown(n.Doer.GetName()))).
|
|
Action(i18n.T(lang, "notifications.common.actions.open_task"), n.Task.GetFrontendURL()).
|
|
IncludeLinkToSettings(lang)
|
|
}
|
|
|
|
// Notification to others about assignment
|
|
return notifications.NewMail().
|
|
From(n.Doer.GetNameAndFromEmail()).
|
|
Greeting(i18n.T(lang, "notifications.greeting", n.Target.GetName())).
|
|
Line(i18n.T(lang, "notifications.task.assigned.message_to_others", notifications.EscapeMarkdown(n.Doer.GetName()), notifications.EscapeMarkdown(n.Assignee.GetName()))).
|
|
Action(i18n.T(lang, "notifications.common.actions.open_task"), n.Task.GetFrontendURL()).
|
|
IncludeLinkToSettings(lang)
|
|
}
|
|
|
|
// ToDB returns the TaskAssignedNotification notification in a format which can be saved in the db
|
|
func (n *TaskAssignedNotification) ToDB() interface{} {
|
|
return n
|
|
}
|
|
|
|
// Name returns the name of the notification
|
|
func (n *TaskAssignedNotification) Name() string {
|
|
return "task.assigned"
|
|
}
|
|
|
|
// ThreadID returns the thread ID for email threading
|
|
func (n *TaskAssignedNotification) ThreadID() string {
|
|
return getThreadID(n.Task.ID)
|
|
}
|
|
|
|
// TaskDeletedNotification represents a TaskDeletedNotification notification
|
|
type TaskDeletedNotification struct {
|
|
Doer *user.User `json:"doer"`
|
|
Task *Task `json:"task"`
|
|
}
|
|
|
|
// ToTitle returns the translated one-line title for TaskDeletedNotification
|
|
func (n *TaskDeletedNotification) ToTitle(lang string) string {
|
|
return i18n.T(lang, "notifications.task.deleted.subject", n.Task.Title, n.Task.GetFullIdentifier())
|
|
}
|
|
|
|
// ToMail returns the mail notification for TaskDeletedNotification
|
|
func (n *TaskDeletedNotification) ToMail(lang string) *notifications.Mail {
|
|
return notifications.NewMail().
|
|
Line(i18n.T(lang, "notifications.task.deleted.message", notifications.EscapeMarkdown(n.Doer.GetName()), notifications.EscapeMarkdown(n.Task.Title), notifications.EscapeMarkdown(n.Task.GetFullIdentifier())))
|
|
}
|
|
|
|
// ToDB returns the TaskDeletedNotification notification in a format which can be saved in the db
|
|
func (n *TaskDeletedNotification) ToDB() interface{} {
|
|
return n
|
|
}
|
|
|
|
// Name returns the name of the notification
|
|
func (n *TaskDeletedNotification) Name() string {
|
|
return "task.deleted"
|
|
}
|
|
|
|
// ThreadID returns the thread ID for email threading
|
|
func (n *TaskDeletedNotification) ThreadID() string {
|
|
return getThreadID(n.Task.ID)
|
|
}
|
|
|
|
// ProjectCreatedNotification represents a ProjectCreatedNotification notification
|
|
type ProjectCreatedNotification struct {
|
|
Doer *user.User `json:"doer"`
|
|
Project *Project `json:"project"`
|
|
}
|
|
|
|
// ToTitle returns the translated one-line title for ProjectCreatedNotification
|
|
func (n *ProjectCreatedNotification) ToTitle(lang string) string {
|
|
return i18n.T(lang, "notifications.project.created", n.Doer.GetName(), n.Project.Title)
|
|
}
|
|
|
|
// ToMail returns the mail notification for ProjectCreatedNotification
|
|
func (n *ProjectCreatedNotification) ToMail(lang string) *notifications.Mail {
|
|
return notifications.NewMail().
|
|
Line(i18n.T(lang, "notifications.project.created", notifications.EscapeMarkdown(n.Doer.GetName()), notifications.EscapeMarkdown(n.Project.Title))).
|
|
Action(i18n.T(lang, "notifications.common.actions.open_project"), config.ServicePublicURL.GetString()+"projects/")
|
|
}
|
|
|
|
// ToDB returns the ProjectCreatedNotification notification in a format which can be saved in the db
|
|
func (n *ProjectCreatedNotification) ToDB() interface{} {
|
|
return n
|
|
}
|
|
|
|
// Name returns the name of the notification
|
|
func (n *ProjectCreatedNotification) Name() string {
|
|
return "project.created"
|
|
}
|
|
|
|
// TeamMemberAddedNotification represents a TeamMemberAddedNotification notification
|
|
type TeamMemberAddedNotification struct {
|
|
Member *user.User `json:"member"`
|
|
Doer *user.User `json:"doer"`
|
|
Team *Team `json:"team"`
|
|
}
|
|
|
|
// ToTitle returns the translated one-line title for TeamMemberAddedNotification
|
|
func (n *TeamMemberAddedNotification) ToTitle(lang string) string {
|
|
return i18n.T(lang, "notifications.team.member_added.subject", n.Doer.GetName(), n.Team.Name)
|
|
}
|
|
|
|
// ToMail returns the mail notification for TeamMemberAddedNotification
|
|
func (n *TeamMemberAddedNotification) ToMail(lang string) *notifications.Mail {
|
|
return notifications.NewMail().
|
|
From(n.Doer.GetNameAndFromEmail()).
|
|
Greeting(i18n.T(lang, "notifications.greeting", n.Member.GetName())).
|
|
Line(i18n.T(lang, "notifications.team.member_added.message", notifications.EscapeMarkdown(n.Doer.GetName()), notifications.EscapeMarkdown(n.Team.Name))).
|
|
Action(i18n.T(lang, "notifications.common.actions.open_team"), config.ServicePublicURL.GetString()+"teams/"+strconv.FormatInt(n.Team.ID, 10)+"/edit")
|
|
}
|
|
|
|
// ToDB returns the TeamMemberAddedNotification notification in a format which can be saved in the db
|
|
func (n *TeamMemberAddedNotification) ToDB() interface{} {
|
|
return n
|
|
}
|
|
|
|
// Name returns the name of the notification
|
|
func (n *TeamMemberAddedNotification) Name() string {
|
|
return "team.member.added"
|
|
}
|
|
|
|
func getOverdueSinceString(until time.Duration, language string) (overdueSince string) {
|
|
if until == 0 {
|
|
return i18n.T(language, "notifications.task.overdue.overdue_now")
|
|
}
|
|
|
|
return i18n.T(language, "notifications.task.overdue.overdue_since", utils.HumanizeDuration(until, language))
|
|
}
|
|
|
|
// UndoneTaskOverdueNotification represents a UndoneTaskOverdueNotification notification
|
|
type UndoneTaskOverdueNotification struct {
|
|
User *user.User
|
|
Task *Task
|
|
Project *Project
|
|
}
|
|
|
|
// ToMail returns the mail notification for UndoneTaskOverdueNotification
|
|
func (n *UndoneTaskOverdueNotification) ToMail(lang string) *notifications.Mail {
|
|
until := time.Until(n.Task.DueDate).Round(1*time.Hour) * -1
|
|
return notifications.NewMail().
|
|
IncludeLinkToSettings(lang).
|
|
Subject(i18n.T(lang, "notifications.task.overdue.subject", n.Task.Title, n.Project.Title)).
|
|
Greeting(i18n.T(lang, "notifications.greeting", n.User.GetName())).
|
|
Line(i18n.T(lang, "notifications.task.overdue.message", notifications.EscapeMarkdown(n.Task.Title), notifications.EscapeMarkdown(n.Project.Title), getOverdueSinceString(until, n.User.Language))).
|
|
Action(i18n.T(lang, "notifications.common.actions.open_task"), config.ServicePublicURL.GetString()+"tasks/"+strconv.FormatInt(n.Task.ID, 10)).
|
|
Line(i18n.T(lang, "notifications.common.have_nice_day"))
|
|
}
|
|
|
|
// ToDB returns the UndoneTaskOverdueNotification notification in a format which can be saved in the db
|
|
func (n *UndoneTaskOverdueNotification) ToDB() interface{} {
|
|
return nil
|
|
}
|
|
|
|
// Name returns the name of the notification
|
|
func (n *UndoneTaskOverdueNotification) Name() string {
|
|
return "task.undone.overdue"
|
|
}
|
|
|
|
// ThreadID returns the thread ID for email threading
|
|
func (n *UndoneTaskOverdueNotification) ThreadID() string {
|
|
return getThreadID(n.Task.ID)
|
|
}
|
|
|
|
// UndoneTasksOverdueNotification represents a UndoneTasksOverdueNotification notification
|
|
type UndoneTasksOverdueNotification struct {
|
|
User *user.User
|
|
Tasks map[int64]*Task
|
|
Projects map[int64]*Project
|
|
}
|
|
|
|
// ToMail returns the mail notification for UndoneTasksOverdueNotification
|
|
func (n *UndoneTasksOverdueNotification) ToMail(lang string) *notifications.Mail {
|
|
|
|
sortedTasks := make([]*Task, 0, len(n.Tasks))
|
|
for _, task := range n.Tasks {
|
|
sortedTasks = append(sortedTasks, task)
|
|
}
|
|
|
|
sort.Slice(sortedTasks, func(i, j int) bool {
|
|
return sortedTasks[i].DueDate.Before(sortedTasks[j].DueDate)
|
|
})
|
|
|
|
overdueLine := ""
|
|
for _, task := range sortedTasks {
|
|
until := time.Until(task.DueDate).Round(1*time.Hour) * -1
|
|
overdueLine += `* [` + notifications.EscapeMarkdown(task.Title) + `](` + config.ServicePublicURL.GetString() + "tasks/" + strconv.FormatInt(task.ID, 10) + `) (` + notifications.EscapeMarkdown(n.Projects[task.ProjectID].Title) + `), ` + i18n.T(lang, "notifications.task.overdue.overdue", getOverdueSinceString(until, n.User.Language)) + "\n"
|
|
}
|
|
|
|
return notifications.NewMail().
|
|
IncludeLinkToSettings(lang).
|
|
Subject(i18n.T(lang, "notifications.task.overdue.multiple_subject")).
|
|
Greeting(i18n.T(lang, "notifications.greeting", n.User.GetName())).
|
|
Line(i18n.T(lang, "notifications.task.overdue.multiple_message")).
|
|
Line(overdueLine).
|
|
Action(i18n.T(lang, "notifications.common.actions.open_vikunja"), config.ServicePublicURL.GetString()).
|
|
Line(i18n.T(lang, "notifications.common.have_nice_day"))
|
|
}
|
|
|
|
// ToDB returns the UndoneTasksOverdueNotification notification in a format which can be saved in the db
|
|
func (n *UndoneTasksOverdueNotification) ToDB() interface{} {
|
|
return nil
|
|
}
|
|
|
|
// Name returns the name of the notification
|
|
func (n *UndoneTasksOverdueNotification) Name() string {
|
|
return "task.undone.overdue"
|
|
}
|
|
|
|
// UserMentionedInTaskNotification represents a UserMentionedInTaskNotification notification
|
|
type UserMentionedInTaskNotification struct {
|
|
Doer *user.User `json:"doer"`
|
|
Task *Task `json:"task"`
|
|
IsNew bool `json:"is_new"`
|
|
Project *Project `json:"project"`
|
|
}
|
|
|
|
func (n *UserMentionedInTaskNotification) SubjectID() int64 {
|
|
return n.Task.ID
|
|
}
|
|
|
|
// ToTitle returns the translated one-line title for UserMentionedInTaskNotification
|
|
func (n *UserMentionedInTaskNotification) ToTitle(lang string) string {
|
|
if n.IsNew {
|
|
return i18n.T(lang, "notifications.task.mentioned.subject_new", n.Doer.GetName(), n.Task.Title, n.Task.GetFullIdentifier())
|
|
}
|
|
return i18n.T(lang, "notifications.task.mentioned.subject", n.Doer.GetName(), n.Task.Title, n.Task.GetFullIdentifier())
|
|
}
|
|
|
|
// ToMail returns the mail notification for UserMentionedInTaskNotification
|
|
func (n *UserMentionedInTaskNotification) ToMail(lang string) *notifications.Mail {
|
|
s := db.NewSession()
|
|
defer s.Close()
|
|
formattedDescription := formatMentionsForEmail(s, n.Task.Description)
|
|
|
|
mail := notifications.NewMail().
|
|
Conversational().
|
|
From(n.Doer.GetNameAndFromEmail())
|
|
|
|
// Add header line
|
|
action := i18n.T(lang, "notifications.common.actions.mentioned_you", n.Doer.GetName())
|
|
if n.IsNew {
|
|
action = i18n.T(lang, "notifications.common.actions.mentioned_you_new_task", n.Doer.GetName())
|
|
}
|
|
|
|
headerLine := notifications.CreateConversationalHeader(
|
|
getDoerAvatarDataURI(n.Doer),
|
|
action,
|
|
n.Task.GetFrontendURL(),
|
|
n.Project.Title,
|
|
n.Task.GetFullIdentifier(),
|
|
n.Task.Title,
|
|
)
|
|
mail.HeaderLine(headerLine)
|
|
|
|
if formattedDescription != "" {
|
|
mail.HTML(formattedDescription)
|
|
}
|
|
|
|
return mail.
|
|
Action(i18n.T(lang, "notifications.common.actions.open_task"), n.Task.GetFrontendURL()).
|
|
IncludeLinkToSettings(lang)
|
|
}
|
|
|
|
// ToDB returns the UserMentionedInTaskNotification notification in a format which can be saved in the db
|
|
func (n *UserMentionedInTaskNotification) ToDB() interface{} {
|
|
return n
|
|
}
|
|
|
|
// Name returns the name of the notification
|
|
func (n *UserMentionedInTaskNotification) Name() string {
|
|
return "task.mentioned"
|
|
}
|
|
|
|
// ThreadID returns the thread ID for email threading
|
|
func (n *UserMentionedInTaskNotification) ThreadID() string {
|
|
return getThreadID(n.Task.ID)
|
|
}
|
|
|
|
// DataExportReadyNotification represents a DataExportReadyNotification notification
|
|
type DataExportReadyNotification struct {
|
|
User *user.User `json:"user"`
|
|
}
|
|
|
|
// ToMail returns the mail notification for DataExportReadyNotification
|
|
func (n *DataExportReadyNotification) ToMail(lang string) *notifications.Mail {
|
|
return notifications.NewMail().
|
|
Subject(i18n.T(lang, "notifications.data_export.ready.subject")).
|
|
Greeting(i18n.T(lang, "notifications.greeting", n.User.GetName())).
|
|
Line(i18n.T(lang, "notifications.data_export.ready.message")).
|
|
Action(i18n.T(lang, "notifications.common.actions.download"), config.ServicePublicURL.GetString()+"user/export/download").
|
|
Line(i18n.T(lang, "notifications.data_export.ready.availability")).
|
|
Line(i18n.T(lang, "notifications.common.have_nice_day"))
|
|
}
|
|
|
|
// ToDB returns the DataExportReadyNotification notification in a format which can be saved in the db
|
|
func (n *DataExportReadyNotification) ToDB() interface{} {
|
|
return nil
|
|
}
|
|
|
|
// Name returns the name of the notification
|
|
func (n *DataExportReadyNotification) Name() string {
|
|
return "data.export.ready"
|
|
}
|