Initial commit: Angular frontend and Expressjs backend

This commit is contained in:
chamikaJ
2024-05-17 09:32:30 +05:30
parent eb0a0d77d6
commit 298ca6beeb
3548 changed files with 193558 additions and 3 deletions

View File

@@ -0,0 +1,5 @@
export default class EmailNotificationsService {
public static sendStatusChange() {
const message = "";
}
}

View 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;
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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",
};

View 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;
}
}

View File

@@ -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;
}
}
}