Initial commit: Angular frontend and Expressjs backend
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
export default class EmailNotificationsService {
|
||||
public static sendStatusChange() {
|
||||
const message = "";
|
||||
}
|
||||
}
|
||||
24
worklenz-backend/src/services/notifications/interfaces.ts
Normal file
24
worklenz-backend/src/services/notifications/interfaces.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
export interface INotification {
|
||||
user_ids: string[];
|
||||
message: string;
|
||||
}
|
||||
|
||||
export interface IReceiver {
|
||||
receiver_socket_id: string;
|
||||
team: string;
|
||||
team_id: string;
|
||||
message: string;
|
||||
project_id?: string;
|
||||
project?: string;
|
||||
project_color?: string;
|
||||
task_id?: string;
|
||||
}
|
||||
|
||||
export interface ICreateNotificationRequest {
|
||||
userId: string;
|
||||
teamId: string;
|
||||
socketId: string;
|
||||
message: string;
|
||||
taskId: string | null;
|
||||
projectId: string | null;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import {INotification} from "../interfaces";
|
||||
|
||||
export class TaskAdd implements INotification {
|
||||
private template = `<user> added "<task>" to the "<project>".`;
|
||||
user_ids!: string[];
|
||||
message!: string;
|
||||
|
||||
constructor(userIds: string[], userName: string, taskName: string, projectName: string) {
|
||||
this.user_ids = userIds;
|
||||
this.message = this.template
|
||||
.replace(/<user>/g, userName)
|
||||
.replace(/<task>/g, taskName)
|
||||
.replace(/<project>/g, projectName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import {INotification} from "../interfaces";
|
||||
|
||||
class TaskRemove implements INotification {
|
||||
private template = `<user> removed "<task>" from the "<project>".`;
|
||||
user_ids!: string[];
|
||||
message!: string;
|
||||
|
||||
constructor(userIds: string[], userName: string, taskName: string, projectName: string) {
|
||||
this.user_ids = userIds;
|
||||
this.message = this.template
|
||||
.replace(/<user>/g, userName)
|
||||
.replace(/<task>/g, taskName)
|
||||
.replace(/<project>/g, projectName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
export const NotificationTypes = {
|
||||
NEW_TASK_ADDED: "NEW_TASK_ADDED",
|
||||
TASK_REMOVED: "TASK_REMOVED",
|
||||
ADDED_TO_A_PROJECT: "ADDED_TO_A_PROJECT",
|
||||
REMOVED_FROM_A_PROJECT: "REMOVED_FROM_A_PROJECT",
|
||||
MENTIONED_IN_A_TASK_COMMENT: "MENTIONED_IN_A_TASK_COMMENT",
|
||||
NEW_COMMENT_ADDED_TO_A_TASK: "NEW_COMMENT_ADDED_TO_A_TASK",
|
||||
TASK_TRANSITION: "TASK_TRANSITION",
|
||||
TASK_RENAME: "TASK_RENAME",
|
||||
TASK_ASSIGNMENT: "TASK_ASSIGNMENT",
|
||||
TASK_UNASSIGN: "TASK_UNASSIGN",
|
||||
ADD_TO_A_TEAM: "ADD_TO_A_TEAM",
|
||||
REMOVED_FROM_A_TEAM: "REMOVED_FROM_A_TEAM",
|
||||
};
|
||||
42
worklenz-backend/src/services/notifications/notification.ts
Normal file
42
worklenz-backend/src/services/notifications/notification.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
export declare type Params = {
|
||||
[key: string]: any;
|
||||
};
|
||||
|
||||
export default class WorklenzNotification {
|
||||
private team: string;
|
||||
private team_id: string;
|
||||
private message: string;
|
||||
private url: string | null;
|
||||
private project?: string;
|
||||
private color?: string;
|
||||
private params?: Params;
|
||||
private task_id?: string;
|
||||
private project_id?: string;
|
||||
|
||||
constructor(teamName: string, teamId: string, message: string, url: string | null) {
|
||||
this.team = teamName;
|
||||
this.team_id = teamId;
|
||||
this.message = message;
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public setProject(name: string) {
|
||||
this.project = name;
|
||||
}
|
||||
|
||||
public setColor(code: string) {
|
||||
this.color = code;
|
||||
}
|
||||
|
||||
public setParams(params: Params) {
|
||||
this.params = params;
|
||||
}
|
||||
|
||||
public setTaskId(id: string) {
|
||||
this.task_id = id;
|
||||
}
|
||||
|
||||
public setProjectId(id: string) {
|
||||
this.project_id = id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
import db from "../../config/db";
|
||||
import {IO} from "../../shared/io";
|
||||
import {log_error} from "../../shared/utils";
|
||||
import {SocketEvents} from "../../socket.io/events";
|
||||
import {ICreateNotificationRequest, IReceiver} from "./interfaces";
|
||||
import WorklenzNotification from "./notification";
|
||||
import {sendInvitationEmail} from "../../shared/email-templates";
|
||||
import {IPassportSession} from "../../interfaces/passport-session";
|
||||
|
||||
export class NotificationsService {
|
||||
public static TYPE_POP = 1;
|
||||
public static TYPE_EMAIL = 2;
|
||||
|
||||
private static isAllowPopup(type: number) {
|
||||
return type & this.TYPE_POP;
|
||||
}
|
||||
|
||||
private static isAllowEmail(type: number) {
|
||||
return type & this.TYPE_EMAIL;
|
||||
}
|
||||
|
||||
private static isAllowBoth(type: number) {
|
||||
return this.isAllowPopup(type) && this.isAllowEmail(type);
|
||||
}
|
||||
|
||||
public static async createTaskUpdate(type: string, reporterId: string, taskId: string, userId: string, teamId: string) {
|
||||
if (!userId || !taskId) return;
|
||||
try {
|
||||
const q = "SELECT notify_task_assignment_update($1, $2, $3, $4, $5) AS receiver;";
|
||||
const result = await db.query(q, [type, reporterId, taskId, userId, teamId]);
|
||||
const [data] = result.rows;
|
||||
const receiver = data.receiver || {};
|
||||
|
||||
if (receiver?.receiver_socket_id && (reporterId !== userId)) {
|
||||
NotificationsService.sendNotification(receiver);
|
||||
}
|
||||
} catch (error) {
|
||||
log_error(error);
|
||||
}
|
||||
}
|
||||
|
||||
public static sendNotification(receiver: IReceiver): void {
|
||||
const url = receiver.project_id ? `/worklenz/projects/${receiver.project_id}` : null;
|
||||
const notification = new WorklenzNotification(receiver.team, receiver.team_id, receiver.message, url);
|
||||
|
||||
if (receiver.project) {
|
||||
notification.setProject(receiver.project);
|
||||
}
|
||||
|
||||
if (receiver.project_color) {
|
||||
notification.setColor(receiver.project_color);
|
||||
}
|
||||
|
||||
if (receiver.task_id) {
|
||||
notification.setParams({task: receiver.task_id});
|
||||
notification.setTaskId(receiver.task_id);
|
||||
}
|
||||
|
||||
if (receiver.project_id) {
|
||||
notification.setProjectId(receiver.project_id);
|
||||
}
|
||||
|
||||
IO.emit(SocketEvents.NOTIFICATIONS_UPDATE, receiver.receiver_socket_id, notification);
|
||||
}
|
||||
|
||||
public static sendInvitation(userId: string, userName: string, teamName: string, teamId: string, teamMemberId: string) {
|
||||
const message = `<b>${userName}</b> has invited you to work with <b>${teamName}</b>.`;
|
||||
const payload = {message, team: teamName, team_id: teamId};
|
||||
IO.emitByTeamMemberId(teamMemberId, userId || null, SocketEvents.INVITATIONS_UPDATE, payload);
|
||||
}
|
||||
|
||||
public static async createNotification(request: ICreateNotificationRequest) {
|
||||
try {
|
||||
const q = "SELECT create_notification($1, $2, $3, $4, $5) AS res;";
|
||||
const result = await db.query(q, [request.userId, request.teamId, request.taskId, request.projectId, request.message]);
|
||||
const [data] = result.rows;
|
||||
const response = data.res;
|
||||
|
||||
this.sendNotification({
|
||||
receiver_socket_id: request.socketId,
|
||||
project: response.project,
|
||||
message: request.message,
|
||||
project_color: response.project_color,
|
||||
project_id: request.projectId as string,
|
||||
team: response.team,
|
||||
team_id: request.teamId
|
||||
});
|
||||
} catch (error) {
|
||||
log_error(error);
|
||||
}
|
||||
}
|
||||
|
||||
public static sendTeamMembersInvitations(members: any[], user: IPassportSession, projectId?: string) {
|
||||
for (const member of members) {
|
||||
sendInvitationEmail(
|
||||
!member.is_new,
|
||||
user,
|
||||
!member.is_new ? member.name : member.team_member_id,
|
||||
member.email,
|
||||
member.team_member_user_id,
|
||||
member.name || member.email?.split("@")[0],
|
||||
projectId
|
||||
);
|
||||
|
||||
if (member.team_member_id) {
|
||||
NotificationsService.sendInvitation(
|
||||
user.id as string,
|
||||
user.name as string,
|
||||
user.team_name as string,
|
||||
user.team_id as string,
|
||||
member.team_member_id
|
||||
);
|
||||
}
|
||||
|
||||
member.id = member.team_member_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user