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,16 @@
import {Server, Socket} from "socket.io";
import db from "../../config/db";
import {log} from "../util";
import {SocketEvents} from "../events";
export async function on_login(_io: Server, socket: Socket, id?: string) {
log(socket.id, `user connected`);
try {
const q = "UPDATE users SET socket_id = $1 WHERE id = $2";
await db.query(q, [socket.id, id]);
socket.emit(SocketEvents.LOGIN.toString());
} catch (error) {
// ignored
}
}

View File

@@ -0,0 +1,62 @@
import {Server, Socket} from "socket.io";
import db from "../../config/db";
import WorklenzControllerBase from "../../controllers/worklenz-controller-base";
import {getRandomColorCode} from "../../shared/utils";
import {SocketEvents} from "../events";
import {log_error} from "../util";
import {logLabelsUpdate} from "../../services/activity-logs/activity-logs.service";
export async function on_create_label(_io: Server, socket: Socket, data?: string) {
try {
const body = JSON.parse(data as string);
if (body.label?.length > 30) return;
body.color = getRandomColorCode();
const q = `SELECT assign_or_create_label($1, $2, $3, $4) AS label;`;
const result = await db.query(q, [body.team_id, body.task_id, body.label, body.color]);
const [d] = result.rows;
const labelId = d.label?.id;
if (labelId) {
const q2 = `
SELECT task_labels.label_id AS id,
(SELECT name FROM team_labels WHERE id = task_labels.label_id) AS name,
(SELECT color_code FROM team_labels WHERE id = task_labels.label_id)
FROM task_labels
WHERE task_id = $1
ORDER BY name
`;
const result2 = await db.query(q2, [body.task_id]);
const labels = WorklenzControllerBase.createTagList(result2.rows, 2);
const newLabel = {
id: labelId,
selected: true,
color_code: body.color,
name: body.label.trim()
};
socket.emit(SocketEvents.CREATE_LABEL.toString(), {
id: body.task_id,
parent_task: body.parent_task,
new_label: newLabel,
is_new: !!d.label?.is_new,
all_labels: result2.rows,
labels
});
logLabelsUpdate({
task_id: body.task_id,
socket,
new_value: labelId,
old_value: null
});
}
} catch (error) {
log_error(error);
}
}

View File

@@ -0,0 +1,30 @@
import { Server, Socket } from "socket.io";
import db from "../../config/db";
import { SocketEvents } from "../events";
import { log_error } from "../util";
import { getColor } from "../../shared/utils";
export async function on_create_project_category(_io: Server, socket: Socket, data?: string) {
try {
const body = JSON.parse(data as string);
const q = `
INSERT INTO project_categories (name, team_id, created_by, color_code)
VALUES ($1, $2, $3, $4)
RETURNING id, name, color_code;
`;
const result = await db.query(q, [body.name, body.team_id, body.user_id, body.name ? getColor(body.name) : null]);
const [d] = result.rows;
socket.emit(SocketEvents.CREATE_PROJECT_CATEGORY.toString(), {
id: body.project_id,
category_id: d.id,
category_name: d.name,
category_color: d.color_code
});
} catch (error) {
log_error(error);
}
}

View File

@@ -0,0 +1,14 @@
import {Server, Socket} from "socket.io";
import db from "../../config/db";
import {log} from "../util";
export async function on_disconnect(io: Server, socket: Socket, reason?: string) {
log(socket.id, `disconnected (${reason})`);
try {
const q = "UPDATE users SET socket_id = NULL WHERE socket_id = $1";
await db.query(q, [socket.id]);
} catch (error) {
// ignored
}
}

View File

@@ -0,0 +1,24 @@
import {Server, Socket} from "socket.io";
import {SocketEvents} from "../events";
import {log_error} from "../util";
import TasksControllerV2 from "../../controllers/tasks-controller-v2";
export async function on_get_task_progress(_io: Server, socket: Socket, taskId?: string) {
try {
const task: any = {};
task.id = taskId;
const info = await TasksControllerV2.getTaskCompleteRatio(task.parent_task_id || task.id);
if (info) {
task.complete_ratio = info.ratio;
task.completed_count = info.total_completed;
task.total_tasks_count = info.total_tasks;
}
return socket.emit(SocketEvents.GET_TASK_PROGRESS.toString(), task);
} catch (error) {
log_error(error);
}
socket.emit(SocketEvents.GET_TASK_PROGRESS.toString(), null);
}

View File

@@ -0,0 +1,49 @@
import {Server, Socket} from "socket.io";
import {log_error} from "../util";
import {SocketEvents} from "../events";
import db from "../../config/db";
import {getColor} from "../../shared/utils";
import TasksControllerV2 from "../../controllers/tasks-controller-v2";
export async function on_join_project_room(_io: Server, socket: Socket, data: { id: string | null; type: string; }) {
const payload = {...data};
payload.id = /undefined|null/.test(data.id as string) ? null : payload.id;
if (!payload.id) return;
try {
if (payload.type === "join") {
await socket.join(payload.id);
} else {
await socket.leave(payload.id);
}
const clients = await _io.in(payload.id).fetchSockets();
const socketIds = clients.map(socket => `'${socket.id}'`).join(`,`);
if (!socketIds) return;
const q = `
SELECT name, avatar_url
FROM users
WHERE socket_id IN (${socketIds})
AND EXISTS(SELECT 1
FROM team_members
WHERE team_id = (SELECT team_id FROM projects WHERE id = $1)
AND user_id = users.id);
`;
const result = await db.query(q, [payload.id]);
const users = result.rows.map((a: { name: string; color_code?: string; }) => {
a.color_code = getColor(a.name);
return a;
});
const members = TasksControllerV2.createTagList(users);
socket.emit(SocketEvents.JOIN_OR_LEAVE_PROJECT_ROOM.toString(), members);
socket.to(payload.id).emit(SocketEvents.JOIN_OR_LEAVE_PROJECT_ROOM.toString(), members);
} catch (error) {
log_error(error);
}
}

View File

@@ -0,0 +1,28 @@
import {Server, Socket} from "socket.io";
import db from "../../config/db";
import {SocketEvents} from "../events";
import {log_error} from "../util";
export async function on_phase_end_date_change(_io: Server, socket: Socket, data?: string) {
try {
const q = `UPDATE project_phases
SET end_date = $2
WHERE id = $1
RETURNING start_date, end_date;`;
const body = JSON.parse(data as string);
const result = await db.query(q, [body.phase_id, body.end_date]);
const [d] = result.rows;
socket.emit(SocketEvents.PHASE_END_DATE_CHANGE.toString(), {
phase_id: body.phase_id,
end_date: d.end_date
});
return;
} catch (error) {
log_error(error);
}
socket.emit(SocketEvents.PHASE_END_DATE_CHANGE.toString(), null);
}

View File

@@ -0,0 +1,28 @@
import {Server, Socket} from "socket.io";
import db from "../../config/db";
import {SocketEvents} from "../events";
import {log_error} from "../util";
export async function on_phase_start_date_change(_io: Server, socket: Socket, data?: string) {
try {
const q = `UPDATE project_phases
SET start_date = $2
WHERE id = $1
RETURNING start_date, end_date;`;
const body = JSON.parse(data as string);
const result = await db.query(q, [body.phase_id, body.start_date]);
const [d] = result.rows;
socket.emit(SocketEvents.PHASE_START_DATE_CHANGE.toString(), {
phase_id: body.phase_id,
start_date: d.start_date
});
return;
} catch (error) {
log_error(error);
}
socket.emit(SocketEvents.PHASE_START_DATE_CHANGE.toString(), null);
}

View File

@@ -0,0 +1,37 @@
import { Server, Socket } from "socket.io";
import db from "../../config/db";
import { SocketEvents } from "../events";
import { log_error } from "../util";
export async function on_project_category_change(_io: Server, socket: Socket, data?: string) {
try {
const body = JSON.parse(data as string);
const q = `UPDATE projects SET category_id = $2 WHERE id = $1;`;
await db.query(q, [body.project_id, body.category_id]);
if (body.is_update) {
const q2 = "SELECT id, name, color_code FROM project_categories WHERE id = $1;";
const result = await db.query(q2, [body.category_id]);
const [d] = result.rows;
socket.emit(SocketEvents.PROJECT_CATEGORY_CHANGE.toString(), {
id: body.project_id,
category_id: d.id,
category_name: d.name,
category_color: d.color_code
});
} else {
socket.emit(SocketEvents.PROJECT_CATEGORY_CHANGE.toString(), {
id: body.project_id,
category_id: null,
category_name: null,
category_color: null
});
}
} catch (error) {
log_error(error);
}
}

View File

@@ -0,0 +1,21 @@
import {Server, Socket} from "socket.io";
import db from "../../config/db";
import {SocketEvents} from "../events";
import {log_error} from "../util";
export async function on_project_end_date_change(_io: Server, socket: Socket, data?: string) {
try {
const body = JSON.parse(data as string);
const q = `UPDATE projects SET end_date = $2 WHERE id = $1 RETURNING end_date;`;
await db.query(q, [body.project_id, body.end_date]);
socket.emit(SocketEvents.PROJECT_END_DATE_CHANGE.toString(), {
id: body.project_id,
end_date: body.end_date
});
} catch (error) {
log_error(error);
}
}

View File

@@ -0,0 +1,26 @@
import {Server, Socket} from "socket.io";
import db from "../../config/db";
import {SocketEvents} from "../events";
import {log_error} from "../util";
export async function on_project_health_change(_io: Server, socket: Socket, data?: string) {
try {
const body = JSON.parse(data as string);
const q = `UPDATE projects SET health_id = $2 WHERE id = $1;`;
await db.query(q, [body.project_id, body.health_id]);
const q2 = "SELECT color_code FROM sys_project_healths WHERE id=$1";
const result = await db.query(q2, [body.health_id]);
const [d] = result.rows;
socket.emit(SocketEvents.PROJECT_HEALTH_CHANGE.toString(), {
id: body.project_id,
color_code: d.color_code,
health_id: body.health_id
});
} catch (error) {
log_error(error);
}
}

View File

@@ -0,0 +1,21 @@
import {Server, Socket} from "socket.io";
import db from "../../config/db";
import {SocketEvents} from "../events";
import {log_error} from "../util";
export async function on_project_start_date_change(_io: Server, socket: Socket, data?: string) {
try {
const body = JSON.parse(data as string);
const q = `UPDATE projects SET start_date = $2 WHERE id = $1 RETURNING start_date;`;
await db.query(q, [body.project_id, body.start_date]);
socket.emit(SocketEvents.PROJECT_START_DATE_CHANGE.toString(), {
id: body.project_id,
start_date: body.start_date
});
} catch (error) {
log_error(error);
}
}

View File

@@ -0,0 +1,28 @@
import {Server, Socket} from "socket.io";
import db from "../../config/db";
import {SocketEvents} from "../events";
import {log_error} from "../util";
export async function on_project_status_change(_io: Server, socket: Socket, data?: string) {
try {
const body = JSON.parse(data as string);
const q = `UPDATE projects SET status_id = $2 WHERE id = $1;`;
await db.query(q, [body.project_id, body.status_id]);
const q2 = "SELECT id,name,color_code,icon FROM sys_project_statuses WHERE id=$1";
const result = await db.query(q2, [body.status_id]);
const [d] = result.rows;
socket.emit(SocketEvents.PROJECT_STATUS_CHANGE.toString(), {
id: body.project_id,
status: d.id,
status_icon: d.icon,
status_color: d.color_code,
status_name: d.name
});
} catch (error) {
log_error(error);
}
}

View File

@@ -0,0 +1,37 @@
import {Server, Socket} from "socket.io";
import db from "../../config/db";
import {SocketEvents} from "../events";
import {log_error} from "../util";
import TasksControllerV2 from "../../controllers/tasks-controller-v2";
interface IProjectSubscribeRequest {
mode: number;
project_id: string;
user_id: string;
team_member_id: string;
}
export async function on_project_subscriber_change(_io: Server, socket: Socket, data?: IProjectSubscribeRequest) {
if (!data) return;
try {
const isSubscribe = data.mode == 0;
const q = isSubscribe
? `INSERT INTO project_subscribers (user_id, project_id, team_member_id)
VALUES ($1, $2, $3);`
: `DELETE
FROM project_subscribers
WHERE user_id = $1
AND project_id = $2
AND team_member_id = $3;`;
await db.query(q, [data.user_id, data.project_id, data.team_member_id]);
const subscribers = await TasksControllerV2.getTaskSubscribers(data.project_id);
socket.emit(SocketEvents.PROJECT_SUBSCRIBERS_CHANGE.toString(), subscribers);
return;
} catch (error) {
log_error(error);
}
}

View File

@@ -0,0 +1,124 @@
import {Server, Socket} from "socket.io";
import db from "../../config/db";
import WorklenzControllerBase from "../../controllers/worklenz-controller-base";
import {NotificationsService} from "../../services/notifications/notifications.service";
import {getColor} from "../../shared/utils";
import {SocketEvents} from "../events";
import {getLoggedInUserIdFromSocket, log_error, notifyProjectUpdates} from "../util";
import {logMemberAssignment} from "../../services/activity-logs/activity-logs.service";
export async function getAssignees(taskId: string): Promise<Array<{
team_member_id?: string;
project_member_id?: string;
name?: string;
avatar_url?: string;
user_id?: string;
}>> {
const result1 = await db.query("SELECT get_task_assignees($1) AS assignees;", [taskId]);
const [d] = result1.rows;
const assignees = d.assignees || [];
assignees.forEach((a: any) => a.color_code = getColor(a.name));
return assignees;
}
export async function getTeamMembers(teamId: string) {
const result = await db.query("SELECT get_team_members($1, NULL) AS members;", [teamId]);
const [data] = result.rows;
return data?.members || [];
}
async function runAssignOrRemove(data: any, isAssignment = false) {
const q = isAssignment
? "SELECT create_task_assignee($1, $2, $3, $4) AS data;"
: `SELECT remove_task_assignee($1, $2, $3) AS data;`;
const params = isAssignment
? [data.team_member_id, data.project_id, data.task_id, data.reporter_id]
: [data.task_id, data.team_member_id, data.project_id];
const result = await db.query(q, params);
const [assignment] = result.rows;
return assignment.data as {
user_id: string;
team_id: string;
task_id?: string;
project_member_id?: string;
team_member_id?: string;
} || null;
}
export async function on_quick_assign_or_remove(_io: Server, socket: Socket, data?: string) {
try {
const body = JSON.parse(data as string);
const isAssign = body.mode == 0;
const userId = getLoggedInUserIdFromSocket(socket);
const assignment = await runAssignOrRemove(body, isAssign);
const assignees = await getAssignees(body.task_id);
const members = await getTeamMembers(body.team_id);
// for inline display
const names = WorklenzControllerBase.createTagList(assignees);
const type = isAssign ? "ASSIGN" : "UNASSIGN";
logMemberAssignment({
task_id: body.task_id,
socket,
new_value: body.team_member_id,
old_value: null,
assign_type: type
});
if (userId !== assignment.user_id) {
NotificationsService.createTaskUpdate(
type,
userId as string,
body.task_id,
assignment.user_id,
assignment.team_id
);
}
notifyProjectUpdates(socket, body.task_id);
const res = {id: body.task_id, parent_task: body.parent_task, members, assignees, names, mode: body.mode, team_member_id: body.team_member_id};
socket.emit(SocketEvents.QUICK_ASSIGNEES_UPDATE.toString(), res);
return;
} catch (error) {
log_error(error);
}
socket.emit(SocketEvents.QUICK_ASSIGNEES_UPDATE.toString(), null);
}
export async function assignMemberIfNot(taskId: string, userId: string, teamId: string, io: Server, socket: Socket) {
try {
const q = `
SELECT
team_member_id,
(SELECT project_id FROM tasks WHERE id = $1) as project_id,
(SELECT parent_task_id FROM tasks WHERE id = $1) as parent_task_id
FROM team_member_info_view WHERE user_id = $2 AND team_id = $3
`;
const result = await db.query(q, [taskId, userId, teamId]);
const [data] = result.rows;
const body = {
team_member_id: data.team_member_id,
project_id: data.project_id,
task_id: taskId,
reporter_id: userId,
mode: 0,
parent_task: data.parent_task_id
};
await on_quick_assign_or_remove(io, socket, JSON.stringify(body));
} catch (e) {
log_error(e);
}
}

View File

@@ -0,0 +1,120 @@
import {Server, Socket} from "socket.io";
import db from "../../config/db";
import {getColor, toMinutes} from "../../shared/utils";
import {SocketEvents} from "../events";
import {log_error, notifyProjectUpdates} from "../util";
import TasksControllerV2 from "../../controllers/tasks-controller-v2";
import {TASK_STATUS_COLOR_ALPHA, UNMAPPED} from "../../shared/constants";
import moment from "moment";
import momentTime from "moment-timezone";
import { logEndDateChange, logStartDateChange, logStatusChange } from "../../services/activity-logs/activity-logs.service";
export async function getTaskCompleteInfo(task: any) {
if (!task) return null;
const q2 = "SELECT get_task_complete_info($1, $2) AS res;";
const result2 = await db.query(q2, [task.id, null]);
const [d2] = result2.rows;
task.completed_count = d2.res.total_completed || 0;
if (task.sub_tasks_count > 0)
task.sub_tasks_count = d2.res.total_tasks;
return task;
}
async function updateCompleteInfo(data: any, model: any) {
const info = await TasksControllerV2.getTaskCompleteRatio(data.task.parent_task_id || data.task.id);
if (info) {
model.complete_ratio = info.ratio;
model.completed_count = info.total_completed;
model.total_tasks_count = info.total_tasks;
}
}
function updatePhaseInfo(model: any, body: any) {
model.phase_id = body.phase_id;
// if (model.phase_name) {
// model.phase_color = model.phase_color;
// }
}
function createGaantTask(body: any) {
const fromStart = Math.floor(body.offset) / 35;
const duration = Math.floor(body.width) / 35;
const chartStartDate = moment(body.chart_start);
body.start_date = chartStartDate.add(fromStart, "days").format("YYYY-MM-DD").trim();
body.end_date = moment(body.start_date).add(duration - 1, "days").format("YYYY-MM-DD").trim();
return body;
}
export async function on_quick_task(_io: Server, socket: Socket, data?: string) {
try {
const q = `SELECT create_quick_task($1) AS task;`;
const body = JSON.parse(data as string);
body.name = (body.name || "").trim();
body.priority_id = body.priority_id?.trim() || null;
body.status_id = body.status_id?.trim() || null;
body.phase_id = body.phase_id?.trim() || null;
body.end_date = body.end_date?.trim() || null;
if (body.priority_id === UNMAPPED) body.priority_id = null;
if (body.phase_id === UNMAPPED) body.phase_id = null;
if (body.status_id === UNMAPPED) body.status_id = null;
if (body.is_dragged) createGaantTask(body);
if (body.name.length > 0) {
body.total_minutes = toMinutes(body.total_hours, body.total_minutes);
const result = await db.query(q, [JSON.stringify(body)]);
const [d] = result.rows;
if (d.task) {
if (body.chart_start) {
d.task.chart_start = moment(body.chart_start).format("YYYY-MM-DD");
}
const model = TasksControllerV2.updateTaskViewModel(d.task);
await updateCompleteInfo(d, model);
updatePhaseInfo(model, body);
socket.emit(SocketEvents.QUICK_TASK.toString(), model);
if (body.is_dragged) {
logStartDateChange({
task_id: d.task.id,
socket,
new_value: body.time_zone && d.task.start_date ? momentTime.tz(d.task.start_date, `${body.time_zone}`) : d.task.start_date,
old_value: null
});
logEndDateChange({
task_id: d.task.id,
socket,
new_value: body.time_zone && d.task.end_date ? momentTime.tz(d.task.end_date, `${body.time_zone}`) : d.task.end_date,
old_value: null
});
}
logStatusChange({
task_id: d.task.id,
socket,
new_value: d.task.status,
old_value: null
});
notifyProjectUpdates(socket, d.task.id);
}
}
} catch (error) {
log_error(error);
}
socket.emit(SocketEvents.QUICK_TASK.toString(), null);
}

View File

@@ -0,0 +1,21 @@
import { Server, Socket } from "socket.io";
import db from "../../config/db";
import { SocketEvents } from "../events";
import { log_error } from "../util";
export async function on_roadmap_sort_order_change(_io: Server, socket: Socket, data?: string) {
try {
const q = `SELECT handle_task_roadmap_sort_order($1, $2, $3);`;
const body = JSON.parse(data as string);
await db.query(q, [body.from_index, body.to_index, body.task_id]);
socket.emit(SocketEvents.ROADMAP_SORT_ORDER_CHANGE.toString(), {});
return;
} catch (error) {
log_error(error);
}
socket.emit(SocketEvents.ROADMAP_SORT_ORDER_CHANGE.toString(), null);
}

View File

@@ -0,0 +1,39 @@
import {Server, Socket} from "socket.io";
import db from "../../config/db";
import {SocketEvents} from "../events";
import {log_error, notifyProjectUpdates} from "../util";
import sanitize from "sanitize-html";
import {getTaskDetails, logDescriptionChange} from "../../services/activity-logs/activity-logs.service";
export async function on_task_description_change(_io: Server, socket: Socket, data?: string) {
try {
const q = `UPDATE tasks
SET description = $2
WHERE id = $1
RETURNING description;`;
const body = JSON.parse(data as string);
const task_data = await getTaskDetails(body.task_id, "description");
const description = (body.description || "").replace(/(^([ ]*<p><br><\/p>)*)|((<p><br><\/p>)*[ ]*$)/gi, "").trim() || null;
await db.query(q, [body.task_id, sanitize(description)]);
socket.emit(SocketEvents.TASK_DESCRIPTION_CHANGE.toString(), {
id: body.task_id,
description,
parent_task: body.parent_task,
});
logDescriptionChange({
task_id: body.task_id,
socket,
new_value: description,
old_value: task_data.description
});
notifyProjectUpdates(socket, body.task_id);
// }
} catch (error) {
log_error(error);
}
}

View File

@@ -0,0 +1,39 @@
import {Server, Socket} from "socket.io";
import db from "../../config/db";
import {SocketEvents} from "../events";
import {log_error, notifyProjectUpdates} from "../util";
import {getTaskDetails, logEndDateChange} from "../../services/activity-logs/activity-logs.service";
import momentTime from "moment-timezone";
export async function on_task_end_date_change(_io: Server, socket: Socket, data?: string) {
try {
const q = `UPDATE tasks SET end_date = $2 WHERE id = $1 RETURNING end_date, start_date;`;
const body = JSON.parse(data as string);
const task_data = await getTaskDetails(body.task_id, "end_date");
const result = await db.query(q, [body.task_id, body.end_date]);
const [d] = result.rows;
socket.emit(SocketEvents.TASK_END_DATE_CHANGE.toString(), {
id: body.task_id,
parent_task: body.parent_task,
end_date: d.end_date,
start_date: d.start_date,
group_id: body.group_id
});
notifyProjectUpdates(socket, body.task_id);
logEndDateChange({
task_id: body.task_id,
socket,
new_value: body.time_zone && d.end_date ? momentTime.tz(d.end_date, `${body.time_zone}`) : d.end_date,
old_value: body.time_zone && task_data.end_date ? momentTime.tz(task_data.end_date, `${body.time_zone}`) : task_data.end_date
});
return;
} catch (error) {
log_error(error);
}
socket.emit(SocketEvents.TASK_END_DATE_CHANGE.toString(), null);
}

View File

@@ -0,0 +1,34 @@
import {Server, Socket} from "socket.io";
import db from "../../config/db";
import WorklenzControllerBase from "../../controllers/worklenz-controller-base";
import {SocketEvents} from "../events";
import {log_error, notifyProjectUpdates} from "../util";
import {logLabelsUpdate} from "../../services/activity-logs/activity-logs.service";
export async function on_task_label_change(_io: Server, socket: Socket, data?: string) {
try {
const body = JSON.parse(data as string);
const q = `SELECT add_or_remove_task_label($1, $2) AS labels;`;
const result = await db.query(q, [body.task_id, body.label_id]);
const [d] = result.rows;
const labels = WorklenzControllerBase.createTagList(d.labels || [], 2);
socket.emit(SocketEvents.TASK_LABELS_CHANGE.toString(), {
id: body.task_id, parent_task: body.parent_task, all_labels: d.labels || [], labels
});
logLabelsUpdate({
task_id: body.task_id,
socket,
new_value: body.label_id,
old_value: null
});
notifyProjectUpdates(socket, body.task_id);
} catch (error) {
log_error(error);
}
}

View File

@@ -0,0 +1,52 @@
import {Server, Socket} from "socket.io";
import db from "../../config/db";
import {NotificationsService} from "../../services/notifications/notifications.service";
import {SocketEvents} from "../events";
import {getLoggedInUserIdFromSocket, log_error, notifyProjectUpdates} from "../util";
import {getTaskDetails, logNameChange} from "../../services/activity-logs/activity-logs.service";
export async function on_task_name_change(_io: Server, socket: Socket, data?: string) {
try {
const body = JSON.parse(data as string);
const userId = getLoggedInUserIdFromSocket(socket);
const name = (body.name || "").trim();
const task_data = await getTaskDetails(body.task_id, "name");
const q = `SELECT handle_task_name_change($1, $2, $3) AS response;`;
const result = await db.query(q, [body.task_id, name, userId]);
const [d] = result.rows;
const response = d.response || {};
for (const member of response.members || []) {
if (member.user_id === userId) continue;
NotificationsService.createNotification({
userId: member.user_id,
teamId: member.team_id,
socketId: member.socket_id,
message: response.message,
taskId: body.task_id,
projectId: response.project_id
});
}
socket.emit(SocketEvents.TASK_NAME_CHANGE.toString(), {
id: body.task_id,
parent_task: body.parent_task,
name: response.name
});
notifyProjectUpdates(socket, body.task_id);
logNameChange({
task_id: body.task_id,
socket,
new_value: response.name,
old_value: task_data.name
});
} catch (error) {
log_error(error);
}
}

View File

@@ -0,0 +1,47 @@
import {Server, Socket} from "socket.io";
import db from "../../config/db";
import {TASK_STATUS_COLOR_ALPHA, UNMAPPED} from "../../shared/constants";
import {SocketEvents} from "../events";
import {log_error, notifyProjectUpdates} from "../util";
import {getColor} from "../../shared/utils";
import { getTaskPhaseDetails, logPhaseChange } from "../../services/activity-logs/activity-logs.service";
export async function on_task_phase_change(_io: Server, socket: Socket, body?: any) {
try {
if (!body?.task_id) return;
const q2 = `SELECT handle_on_task_phase_change($1, $2) AS res;`;
const phaseId = !body.phase_id || (body.phase_id === UNMAPPED) ? null : body.phase_id;
const task_data = await getTaskPhaseDetails(body.task_id);
const result = await db.query(q2, [body.task_id, phaseId]);
const [d] = result.rows;
const changeResponse = d.res;
changeResponse.color_code = changeResponse.color_code
? changeResponse.color_code : getColor(changeResponse.name) + TASK_STATUS_COLOR_ALPHA;
socket.emit(SocketEvents.TASK_PHASE_CHANGE.toString(), {
id: body.phase_id,
task_id: body.task_id,
parent_task: body.parent_task,
color_code: changeResponse.color_code,
status_id: body.status_id
});
// TODO: Log to activity log
logPhaseChange({
task_id: body.task_id,
socket,
new_value: phaseId ? phaseId : null,
old_value: task_data.phase_id ? task_data.phase_id : null
});
void notifyProjectUpdates(socket, body.task_id);
} catch (error) {
log_error(error);
}
}

View File

@@ -0,0 +1,41 @@
import {Server, Socket} from "socket.io";
import db from "../../config/db";
import {PriorityColorCodes, TASK_PRIORITY_COLOR_ALPHA} from "../../shared/constants";
import {SocketEvents} from "../events";
import {log_error, notifyProjectUpdates} from "../util";
import {getTaskDetails, logPriorityChange} from "../../services/activity-logs/activity-logs.service";
export async function on_task_priority_change(_io: Server, socket: Socket, data?: string) {
try {
const body = JSON.parse(data as string);
const task_data = await getTaskDetails(body.task_id, "priority_id");
const q = `UPDATE tasks SET priority_id = $2 WHERE id = $1;`;
await db.query(q, [body.task_id, body.priority_id]);
const q2 = "SELECT value FROM task_priorities WHERE id = $1;";
const result = await db.query(q2, [body.priority_id]);
const [d] = result.rows;
d.color_code = (PriorityColorCodes[d.value] || PriorityColorCodes["0"]) + TASK_PRIORITY_COLOR_ALPHA;
socket.emit(SocketEvents.TASK_PRIORITY_CHANGE.toString(), {
id: body.task_id,
parent_task: body.parent_task,
color_code: d.color_code,
priority_id: body.priority_id
});
logPriorityChange({
task_id: body.task_id,
socket,
new_value: body.priority_id,
old_value: task_data.priority_id
});
notifyProjectUpdates(socket, body.task_id);
} catch (error) {
log_error(error);
}
}

View File

@@ -0,0 +1,134 @@
import {Server, Socket} from "socket.io";
import db from "../../config/db";
import {SocketEvents} from "../events";
import {getLoggedInUserIdFromSocket, log_error, notifyProjectUpdates} from "../util";
import TasksController from "../../controllers/tasks-controller";
import {logPhaseChange, logPriorityChange, logStatusChange} from "../../services/activity-logs/activity-logs.service";
import {GroupBy} from "../../controllers/tasks-controller-base";
import {UNMAPPED} from "../../shared/constants";
import TasksControllerV2 from "../../controllers/tasks-controller-v2";
import { assignMemberIfNot } from "./on-quick-assign-or-remove";
interface ChangeRequest {
from_index: number; // from sort_order
to_index: number; // to sort_order
project_id: string;
from_group: string;
to_group: string;
group_by: string;
to_last_index: boolean;
task: {
id: string;
project_id: string;
status: string;
priority: string;
};
team_id: string;
}
interface Config {
from_index: number;
to_index: number;
task_id: string;
from_group: string | null;
to_group: string | null;
project_id: string;
group_by: string;
to_last_index: boolean;
}
function notifyStatusChange(socket: Socket, config: Config) {
const userId = getLoggedInUserIdFromSocket(socket);
if (userId && config.to_group) {
void TasksController.notifyStatusChange(userId, config.task_id, config.to_group);
}
}
async function emitSortOrderChange(data: ChangeRequest, socket: Socket) {
const q = `
SELECT id, sort_order
FROM tasks
WHERE project_id = $1
ORDER BY sort_order;
`;
const tasks = await db.query(q, [data.project_id]);
socket.emit(SocketEvents.TASK_SORT_ORDER_CHANGE.toString(), tasks.rows);
}
function updateUnmappedStatus(config: Config) {
if (config.to_group === UNMAPPED)
config.to_group = null;
if (config.from_group === UNMAPPED)
config.from_group = null;
}
export async function on_task_sort_order_change(_io: Server, socket: Socket, data: ChangeRequest) {
try {
const q = `SELECT handle_task_list_sort_order_change($1);`;
const config: Config = {
from_index: data.from_index,
to_index: data.to_index,
task_id: data.task.id,
from_group: data.from_group,
to_group: data.to_group,
project_id: data.project_id,
group_by: data.group_by,
to_last_index: Boolean(data.to_last_index)
};
if (config.group_by === GroupBy.STATUS) {
notifyStatusChange(socket, config);
}
if (config.group_by === GroupBy.PHASE) {
updateUnmappedStatus(config);
}
await db.query(q, [JSON.stringify(config)]);
await emitSortOrderChange(data, socket);
if (config.group_by === GroupBy.STATUS) {
const userId = getLoggedInUserIdFromSocket(socket);
const isAlreadyAssigned = await TasksControllerV2.checkUserAssignedToTask(data.task.id, userId as string, data.team_id);
if (!isAlreadyAssigned) {
await assignMemberIfNot(data.task.id, userId as string, data.team_id, _io, socket);
}
}
if (config.group_by === GroupBy.PHASE) {
void logPhaseChange({
task_id: data.task.id,
socket,
new_value: data.to_group,
old_value: data.from_group
});
}
if (config.group_by === GroupBy.STATUS) {
void logStatusChange({
task_id: data.task.id,
socket,
new_value: data.to_group,
old_value: data.from_group
});
}
if (config.group_by === GroupBy.PRIORITY) {
void logPriorityChange({
task_id: data.task.id,
socket,
new_value: data.to_group,
old_value: data.from_group
});
}
void notifyProjectUpdates(socket, config.task_id);
return;
} catch (error) {
log_error(error);
}
socket.emit(SocketEvents.TASK_SORT_ORDER_CHANGE.toString(), []);
}

View File

@@ -0,0 +1,43 @@
import {Server, Socket} from "socket.io";
import db from "../../config/db";
import {SocketEvents} from "../events";
import {log_error, notifyProjectUpdates} from "../util";
import {getTaskDetails, logStartDateChange} from "../../services/activity-logs/activity-logs.service";
import momentTime from "moment-timezone";
export async function on_task_start_date_change(_io: Server, socket: Socket, data?: string) {
try {
const q = `UPDATE tasks
SET start_date = $2
WHERE id = $1
RETURNING start_date, end_date;`;
const body = JSON.parse(data as string);
const task_data = await getTaskDetails(body.task_id, "start_date");
const result = await db.query(q, [body.task_id, body.start_date]);
const [d] = result.rows;
socket.emit(SocketEvents.TASK_START_DATE_CHANGE.toString(), {
id: body.task_id,
start_date: d.start_date,
parent_task: body.parent_task,
end_date: d.end_date,
group_id: body.group_id
});
notifyProjectUpdates(socket, body.task_id);
logStartDateChange({
task_id: body.task_id,
socket,
new_value: body.time_zone && d.start_date ? momentTime.tz(d.start_date, `${body.time_zone}`) : d.start_date,
old_value: body.time_zone && task_data.start_date ? momentTime.tz(task_data.start_date, `${body.time_zone}`) : task_data.start_date
});
return;
} catch (error) {
log_error(error);
}
socket.emit(SocketEvents.TASK_START_DATE_CHANGE.toString(), null);
}

View File

@@ -0,0 +1,77 @@
import {Server, Socket} from "socket.io";
import db from "../../config/db";
import {NotificationsService} from "../../services/notifications/notifications.service";
import {TASK_STATUS_COLOR_ALPHA} from "../../shared/constants";
import {SocketEvents} from "../events";
import {getLoggedInUserIdFromSocket, log_error, notifyProjectUpdates} from "../util";
import TasksControllerV2 from "../../controllers/tasks-controller-v2";
import {getTaskDetails, logStatusChange} from "../../services/activity-logs/activity-logs.service";
import { assignMemberIfNot } from "./on-quick-assign-or-remove";
export async function on_task_status_change(_io: Server, socket: Socket, data?: string) {
try {
const body = JSON.parse(data as string);
const userId = getLoggedInUserIdFromSocket(socket);
const task_data = await getTaskDetails(body.task_id, "status_id");
const q2 = "SELECT handle_on_task_status_change($1, $2, $3) AS res;";
const results1 = await db.query(q2, [userId, body.task_id, body.status_id]);
const [d] = results1.rows;
const changeResponse = d.res;
changeResponse.color_code = changeResponse.color_code + TASK_STATUS_COLOR_ALPHA;
// notify to all task members of the change
for (const member of changeResponse.members || []) {
if (member.user_id === userId) continue;
NotificationsService.createNotification({
userId: member.user_id,
teamId: member.team_id,
socketId: member.socket_id,
message: changeResponse.message,
taskId: body.task_id,
projectId: changeResponse.project_id
});
}
const info = await TasksControllerV2.getTaskCompleteRatio(body.parent_task || body.task_id);
socket.emit(SocketEvents.TASK_STATUS_CHANGE.toString(), {
id: body.task_id,
parent_task: body.parent_task,
color_code: changeResponse.color_code,
complete_ratio: info?.ratio,
completed_count: info?.total_completed,
total_tasks_count: info?.total_tasks,
status_id: body.status_id,
completed_at: changeResponse.completed_at,
statusCategory: changeResponse.status_category
});
socket.emit(SocketEvents.GET_TASK_PROGRESS.toString(), {
id: body.task_id,
parent_task: body.parent_task,
complete_ratio: info?.ratio,
completed_count: info?.total_completed,
total_tasks_count: info?.total_tasks
});
const isAlreadyAssigned = await TasksControllerV2.checkUserAssignedToTask(body.task_id, userId as string, body.team_id);
if (!isAlreadyAssigned) {
await assignMemberIfNot(body.task_id, userId as string, body.team_id, _io, socket);
}
logStatusChange({
task_id: body.task_id,
socket,
new_value: body.status_id,
old_value: task_data.status_id
});
notifyProjectUpdates(socket, body.task_id);
} catch (error) {
log_error(error);
}
}

View File

@@ -0,0 +1,37 @@
import {Server, Socket} from "socket.io";
import db from "../../config/db";
import {SocketEvents} from "../events";
import {log_error} from "../util";
import TasksControllerV2 from "../../controllers/tasks-controller-v2";
interface ITaskSubscribeRequest {
mode: number;
task_id: string;
user_id: string;
team_member_id: string;
}
export async function on_task_subscriber_change(_io: Server, socket: Socket, data?: ITaskSubscribeRequest) {
if (!data) return;
try {
const isSubscribe = data.mode == 0;
const q = isSubscribe
? `INSERT INTO task_subscribers (user_id, task_id, team_member_id, action)
VALUES ($1, $2, $3, 'WHEN_DONE');`
: `DELETE
FROM task_subscribers
WHERE user_id = $1
AND task_id = $2
AND team_member_id = $3;`;
await db.query(q, [data.user_id, data.task_id, data.team_member_id]);
const subscribers = await TasksControllerV2.getTaskSubscribers(data.task_id);
socket.emit(SocketEvents.TASK_SUBSCRIBERS_CHANGE.toString(), subscribers);
return;
} catch (error) {
log_error(error);
}
}

View File

@@ -0,0 +1,33 @@
import moment from "moment";
import {Server, Socket} from "socket.io";
import db from "../../config/db";
import {SocketEvents} from "../events";
import {getLoggedInUserIdFromSocket, log_error, notifyProjectUpdates} from "../util";
export async function on_task_timer_start(_io: Server, socket: Socket, data?: string) {
try {
const q = `
INSERT INTO task_timers (task_id, user_id, start_time)
VALUES ($1, $2, CURRENT_TIMESTAMP)
ON CONFLICT ON CONSTRAINT task_timers_pk DO UPDATE SET start_time = CURRENT_TIMESTAMP
RETURNING start_time;
`;
const body = JSON.parse(data as string);
const userId = getLoggedInUserIdFromSocket(socket);
const result = await db.query(q, [body.task_id, userId]);
const [d] = result.rows;
socket.emit(SocketEvents.TASK_TIMER_START.toString(), {
id: body.task_id,
timer_start_time: moment(d.start_time).valueOf(),
parent_task: body.parent_task,
});
notifyProjectUpdates(socket, body.task_id);
return;
} catch (error) {
log_error(error);
}
socket.emit(SocketEvents.TASK_TIMER_START.toString(), null);
}

View File

@@ -0,0 +1,48 @@
import {Server, Socket} from "socket.io";
import db from "../../config/db";
import {SocketEvents} from "../events";
import {getLoggedInUserIdFromSocket, log_error, notifyProjectUpdates} from "../util";
export async function on_task_timer_stop(_io: Server, socket: Socket, data?: string) {
try {
const body = JSON.parse(data as string);
const userId = getLoggedInUserIdFromSocket(socket);
const q = `
DO
$$
DECLARE
_start_time TIMESTAMPTZ;
_time_spent NUMERIC;
BEGIN
SELECT start_time FROM task_timers WHERE user_id = '${userId}' AND task_id = '${body.task_id}' INTO _start_time;
_time_spent = COALESCE(EXTRACT(EPOCH FROM
(DATE_TRUNC('second', (CURRENT_TIMESTAMP - _start_time::TIMESTAMPTZ)))::INTERVAL),
0);
IF (_time_spent > 0)
THEN
INSERT INTO task_work_log (time_spent, task_id, user_id, logged_by_timer, created_at)
VALUES (_time_spent, '${body.task_id}', '${userId}', TRUE, _start_time);
END IF;
DELETE FROM task_timers WHERE user_id = '${userId}' AND task_id = '${body.task_id}';
END
$$;
`;
await db.query(q, []);
socket.emit(SocketEvents.TASK_TIMER_STOP.toString(), {
id: body.task_id,
parent_task: body.parent_task,
});
notifyProjectUpdates(socket, body.task_id);
return;
} catch (error) {
log_error(error);
}
socket.emit(SocketEvents.TASK_TIMER_STOP.toString(), null);
}

View File

@@ -0,0 +1,45 @@
import { Server, Socket } from "socket.io";
import db from "../../config/db";
import TasksController from "../../controllers/tasks-controller";
import { SocketEvents } from "../events";
import { log_error, notifyProjectUpdates } from "../util";
import { getTaskDetails, logTotalMinutes } from "../../services/activity-logs/activity-logs.service";
export async function on_time_estimation_change(_io: Server, socket: Socket, data?: string) {
try {
// (SELECT SUM(time_spent) FROM task_work_log WHERE task_id = t.id) AS total_minutes_spent,
const q = `UPDATE tasks SET total_minutes = $2 WHERE id = $1 RETURNING total_minutes;`;
const body = JSON.parse(data as string);
const hours = body.total_hours || 0;
const minutes = body.total_minutes || 0;
const totalMinutes = (hours * 60) + minutes;
const task_data = await getTaskDetails(body.task_id, "total_minutes");
const result0 = await db.query(q, [body.task_id, totalMinutes]);
const [data0] = result0.rows;
const result = await db.query("SELECT SUM(time_spent) AS total_minutes_spent FROM task_work_log WHERE task_id = $1;", [body.task_id]);
const [dd] = result.rows;
const d = {
id: body.task_id,
total_minutes: totalMinutes,
total_hours: hours,
parent_task: body.parent_task,
total_minutes_spent: dd.total_minutes_spent || 0
};
socket.emit(SocketEvents.TASK_TIME_ESTIMATION_CHANGE.toString(), TasksController.updateTaskViewModel(d));
notifyProjectUpdates(socket, d.id);
logTotalMinutes({
task_id: body.task_id,
socket,
new_value: totalMinutes,
old_value: task_data.total_minutes
});
} catch (error) {
log_error(error);
}
}

View File

@@ -0,0 +1,54 @@
import { Server, Socket } from "socket.io";
import { log_error, notifyProjectUpdates } from "../util";
import db from "../../config/db";
import { SocketEvents } from "../events";
import moment from "moment";
import momentTime from "moment-timezone";
import { getTaskDetails, logEndDateChange, logStartDateChange } from "../../services/activity-logs/activity-logs.service";
export async function on_gannt_drag_change(_io: Server, socket: Socket, data?: string) {
try {
const body = JSON.parse(data as string);
const chartStartDate = moment(body.chart_start);
const taskStartDate = chartStartDate.add(body.from_start, "days");
const taskEndDate = moment(taskStartDate).add(body.task_duration - 1, "days");
const task_start_date_data = await getTaskDetails(body.task_id, "start_date");
const task_end_date_data = await getTaskDetails(body.task_id, "end_date");
const q = `UPDATE tasks SET start_date = $2, end_date = $3 WHERE id = $1 RETURNING start_date, end_date`;
const result = await db.query(q, [body.task_id, taskStartDate, taskEndDate]);
const [d] = result.rows;
socket.emit(SocketEvents.GANNT_DRAG_CHANGE.toString(), {
task_id: body.task_id,
task_width: body.task_width,
task_offset: body.task_offset,
start_date: d.start_date,
end_date: d.end_date,
group_id: body.group_id
});
notifyProjectUpdates(socket, body.task_id);
logStartDateChange({
task_id: body.task_id,
socket,
new_value: body.time_zone && d.start_date ? momentTime.tz(d.start_date, `${body.time_zone}`) : d.start_date,
old_value: body.time_zone && task_start_date_data.start_date ? momentTime.tz(task_start_date_data.start_date, `${body.time_zone}`) : task_start_date_data.start_date
});
logEndDateChange({
task_id: body.task_id,
socket,
new_value: body.time_zone && d.end_date ? momentTime.tz(d.end_date, `${body.time_zone}`) : d.end_date,
old_value: body.time_zone && task_end_date_data.end_date ? momentTime.tz(task_end_date_data.end_date, `${body.time_zone}`) : task_end_date_data.end_date
});
} catch (e) {
log_error(e);
}
}

View File

@@ -0,0 +1,51 @@
import { Server, Socket } from "socket.io";
import { log_error } from "../util";
import { getRandomColorCode } from "../../shared/utils";
import db from "../../config/db";
import WorklenzControllerBase from "../../controllers/worklenz-controller-base";
import { SocketEvents } from "../events";
export async function on_pt_create_label(_io: Server, socket: Socket, data?: string) {
try {
const body = JSON.parse(data as string);
if (body.label?.length > 30) return;
body.color = getRandomColorCode();
const q = `SELECT assign_or_create_pt_label($1, $2, $3, $4) AS label`;
const result = await db.query(q, [body.team_id, body.task_id, body.label, body.color]);
const [d] = result.rows;
const labelId = d.label?.id;
if (labelId) {
const q2 = `
SELECT cpt_task_labels.label_id AS id,
(SELECT name FROM team_labels WHERE id = cpt_task_labels.label_id) AS name,
(SELECT color_code FROM team_labels WHERE id = cpt_task_labels.label_id)
FROM cpt_task_labels
WHERE task_id = $1
ORDER BY name
`;
const result2 = await db.query(q2, [body.task_id]);
const labels = WorklenzControllerBase.createTagList(result2.rows, 2);
const newLabel = {
id: labelId,
selected: true,
color_code: body.color,
name: body.label.trim()
};
socket.emit(SocketEvents.PT_CREATE_LABEL.toString(), {
id: body.task_id,
parent_task: body.parent_task,
new_label: newLabel,
is_new: !!d.label?.is_new,
all_labels: result2.rows,
labels
});
}
} catch (e) {
log_error(e);
}
}

View File

@@ -0,0 +1,24 @@
import { Server, Socket } from "socket.io";
import { log_error } from "../util";
import db from "../../config/db";
import { SocketEvents } from "../events";
export async function on_pt_name_change(_io: Server, socket: Socket, data?: string) {
try {
const body = JSON.parse(data as string);
const name = (body.template_name || "").trim();
const q = `UPDATE custom_project_templates SET name = $2 WHERE id = $1 RETURNING name`;
const result = await db.query(q, [body.template_id, name]);
const [d] = result.rows;
socket.emit(SocketEvents.PT_NAME_CHANGE.toString(), {
template_id: body.template_id,
template_name: d.name
});
} catch (e) {
log_error(e);
}
}

View File

@@ -0,0 +1,51 @@
import { Server, Socket } from "socket.io";
import { log_error } from "../util";
import { getColor, toMinutes } from "../../shared/utils";
import { TASK_STATUS_COLOR_ALPHA, UNMAPPED } from "../../shared/constants";
import db from "../../config/db";
import { SocketEvents } from "../events";
import PtTasksController from "../../controllers/project-templates/pt-tasks-controller";
function updatePhaseInfo(model: any, body: any) {
model.phase_id = body.phase_id;
if (model.phase_name) {
model.phase_color = getColor(model.phase_name) + TASK_STATUS_COLOR_ALPHA;
}
}
export async function on_pt_quick_task(_io: Server, socket: Socket, data?: string) {
try {
const body = JSON.parse(data as string);
const q = `SELECT create_quick_pt_task($1) AS task`;
body.name = (body.name || "").trim();
body.priority_id = body.priority_id?.trim() || null;
body.status_id = body.status_id?.trim() || null;
body.phase_id = body.phase_id?.trim() || null;
if (body.priority_id === UNMAPPED) body.priority_id = null;
if (body.phase_id === UNMAPPED) body.phase_id = null;
if (body.status_id === UNMAPPED) body.status_id = null;
if (body.name.length > 0) {
body.total_minutes = toMinutes(body.total_hours, body.total_minutes);
const result = await db.query(q, [JSON.stringify(body)]);
const [d] = result.rows;
if (d.task) {
const model = PtTasksController.updateTaskViewModel(d.task);
updatePhaseInfo(model, body);
socket.emit(SocketEvents.PT_QUICK_TASK.toString(), model);
}
}
} catch (e) {
log_error(e);
}
socket.emit(SocketEvents.PT_QUICK_TASK.toString(), null);
}

View File

@@ -0,0 +1,24 @@
import { Server, Socket } from "socket.io";
import { log_error } from "../util";
import db from "../../config/db";
import sanitize from "sanitize-html";
import { SocketEvents } from "../events";
export async function on_pt_task_description_change(_io: Server, socket: Socket, data?: string) {
try {
const body = JSON.parse(data as string);
const q = `UPDATE cpt_tasks SET description = $2 WHERE id = $1 RETURNING description`;
const description = (body.description || "").replace(/(^([ ]*<p><br><\/p>)*)|((<p><br><\/p>)*[ ]*$)/gi, "").trim() || null;
await db.query(q, [body.task_id, sanitize(description)]);
socket.emit(SocketEvents.PT_TASK_DESCRIPTION_CHANGE.toString(), {
id: body.task_id,
description
});
} catch (e) {
log_error(e);
}
}

View File

@@ -0,0 +1,24 @@
import { Server, Socket } from "socket.io";
import { log_error } from "../util";
import db from "../../config/db";
import { SocketEvents } from "../events";
export async function on_pt_task_end_date_change(_io: Server, socket: Socket, data?: string) {
try {
const body = JSON.parse(data as string);
const q = `UPDATE table_name_here SET end_date = $2 WHERE id = $1 RETURNING end_date`;
const result = await db.query(q, [body.task_id, body.end_date]);
const [d] = result.rows;
// socket.emit(SocketEvents.PT_TASK_END_DATE_CHANGE.toString(), {
// id: body.task_id,
// parent_task: body.parent_task,
// end_date: d.end_date
// });
} catch (e) {
log_error(e);
}
}

View File

@@ -0,0 +1,26 @@
import { Server, Socket } from "socket.io";
import { log_error } from "../util";
import WorklenzControllerBase from "../../controllers/worklenz-controller-base";
import db from "../../config/db";
import { SocketEvents } from "../events";
export async function on_pt_task_labels_change(_io: Server, socket: Socket, data?: string) {
try {
const body = JSON.parse(data as string);
const q = `SELECT add_or_remove_pt_task_label($1, $2) AS labels`;
const result = await db.query(q, [body.task_id, body.label_id]);
const [d] = result.rows;
const labels = WorklenzControllerBase.createTagList(d.labels || [], 2);
socket.emit(SocketEvents.PT_TASK_LABELS_CHANGE.toString(), {
id: body.task_id,
parent_task: body.parent_task,
all_labels: d.labels || [], labels
});
} catch (e) {
log_error(e);
}
}

View File

@@ -0,0 +1,25 @@
import { Server, Socket } from "socket.io";
import { log_error } from "../util";
import db from "../../config/db";
import { SocketEvents } from "../events";
export async function on_pt_task_name_change(_io: Server, socket: Socket, data?: string) {
try {
const body = JSON.parse(data as string);
const name = (body.name || "").trim();
const q = `UPDATE cpt_tasks SET name = $2 WHERE id = $1 RETURNING name`;
const result = await db.query(q, [body.task_id, name]);
const [d] = result.rows;
socket.emit(SocketEvents.PT_TASK_NAME_CHANGE.toString(), {
id: body.task_id,
parent_task: body.parent_task,
name: d.name
});
} catch (e) {
log_error(e);
}
}

View File

@@ -0,0 +1,33 @@
import { Server, Socket } from "socket.io";
import { log_error } from "../util";
import { TASK_STATUS_COLOR_ALPHA, UNMAPPED } from "../../shared/constants";
import { getColor } from "../../shared/utils";
import { SocketEvents } from "../events";
import db from "../../config/db";
export async function on_pt_task_phase_change(_io: Server, socket: Socket, data?: string) {
try {
const body = JSON.parse(data as string);
if (!body?.task_id) return;
const q2 = `SELECT handle_on_pt_task_phase_change($1, $2) AS res;`;
const phaseId = !body.phase_id || (body.phase_id === UNMAPPED) ? null : body.phase_id;
const result = await db.query(q2, [body.task_id, phaseId]);
const [d] = result.rows;
const changeResponse = d.res;
socket.emit(SocketEvents.PT_TASK_PHASE_CHANGE.toString(), {
id: body.phase_id,
task_id: body.task_id,
parent_task: body.parent_task,
color_code: changeResponse.color_code + TASK_STATUS_COLOR_ALPHA,
status_id: body.status_id
});
} catch (e) {
log_error(e);
}
}

View File

@@ -0,0 +1,31 @@
import { Server, Socket } from "socket.io";
import { log_error } from "../util";
import db from "../../config/db";
import { PriorityColorCodes, TASK_PRIORITY_COLOR_ALPHA } from "../../shared/constants";
import { SocketEvents } from "../events";
export async function on_pt_task_priority_change(_io: Server, socket: Socket, data?: string) {
try {
const body = JSON.parse(data as string);
const q = `UPDATE cpt_tasks SET priority_id = $2 WHERE id = $1`;
await db.query(q, [body.task_id, body.priority_id]);
const q2 = `SELECT value FROM task_priorities WHERE id = $1`;
const result = await db.query(q2, [body.priority_id]);
const [d] = result.rows;
d.color_code = (PriorityColorCodes[d.value] || PriorityColorCodes["0"]) + TASK_PRIORITY_COLOR_ALPHA;
socket.emit(SocketEvents.PT_TASK_PRIORITY_CHANGE.toString(), {
id: body.task_id,
parent_task: body.parent_task,
color_code: d.color_code,
priority_id: body.priority_id
});
} catch (e) {
log_error(e);
}
}

View File

@@ -0,0 +1,84 @@
import { Server, Socket } from "socket.io";
import { getLoggedInUserIdFromSocket, log_error } from "../util";
import db from "../../config/db";
import { SocketEvents } from "../events";
import { UNMAPPED } from "../../shared/constants";
import { GroupBy } from "../../controllers/project-templates/pt-tasks-controller-base";
import TasksControllerV2 from "../../controllers/tasks-controller-v2";
import { assignMemberIfNot } from "./on-quick-assign-or-remove";
interface ChangeRequest {
from_index: number; // from sort_order
to_index: number; // to sort_order
template_id: string;
from_group: string;
to_group: string;
group_by: string;
to_last_index: boolean;
task: {
id: string;
template_id: string;
status: string;
priority: string;
};
team_id: string
}
interface Config {
from_index: number;
to_index: number;
task_id: string;
from_group: string | null;
to_group: string | null;
template_id: string;
group_by: string;
to_last_index: boolean;
}
async function emitSortOrderChange(data: ChangeRequest, socket: Socket) {
const q = `
SELECT id, sort_order
FROM cpt_tasks
WHERE template_id = $1
ORDER BY sort_order;
`;
const tasks = await db.query(q, [data.template_id]);
socket.emit(SocketEvents.PT_TASK_SORT_ORDER_CHANGE.toString(), tasks.rows);
}
function updateUnmappedStatus(config: Config) {
if (config.to_group === UNMAPPED)
config.to_group = null;
if (config.from_group === UNMAPPED)
config.from_group = null;
}
export async function on_pt_task_sort_order_change(_io: Server, socket: Socket, data: ChangeRequest) {
try {
const q = `SELECT handle_pt_task_list_sort_order_change($1);`;
const config: Config = {
from_index: data.from_index,
to_index: data.to_index,
task_id: data.task.id,
from_group: data.from_group,
to_group: data.to_group,
template_id: data.template_id,
group_by: data.group_by,
to_last_index: Boolean(data.to_last_index)
};
if (config.group_by === GroupBy.PHASE) {
updateUnmappedStatus(config);
}
await db.query(q, [JSON.stringify(config)]);
await emitSortOrderChange(data, socket);
return;
} catch (error) {
log_error(error);
}
socket.emit(SocketEvents.PT_TASK_SORT_ORDER_CHANGE.toString(), []);
}

View File

@@ -0,0 +1,24 @@
import { Server, Socket } from "socket.io";
import { log_error } from "../util";
import db from "../../config/db";
import { SocketEvents } from "../events";
export async function on_pt_task_start_date_change(_io: Server, socket: Socket, data?: string) {
try {
const body = JSON.parse(data as string);
const q = `UPDATE tasks SET start_date = $2 WHERE id = $1 RETURNING start_date, end_date`;
const result = await db.query(q, [body.task_id, body.start_date]);
const [d] = result.rows;
// socket.emit(SocketEvents.PT_TASK_START_DATE_CHANGE.toString(), {
// id: body.task_id,
// start_date: d.start_date,
// parent_task: body.parent_task,
// });
} catch (e) {
log_error(e);
}
}

View File

@@ -0,0 +1,28 @@
import { Server, Socket } from "socket.io";
import { log_error } from "../util";
import db from "../../config/db";
import { TASK_STATUS_COLOR_ALPHA } from "../../shared/constants";
import { SocketEvents } from "../events";
export async function on_pt_task_status_change(_io: Server, socket: Socket, data?: string) {
try {
const body = JSON.parse(data as string);
const q2 = "SELECT handle_on_pt_task_status_change($1, $2) AS res;";
const results1 = await db.query(q2, [body.task_id, body.status_id]);
const [d] = results1.rows;
const changeResponse = d.res;
changeResponse.color_code = changeResponse.color_code + TASK_STATUS_COLOR_ALPHA;
socket.emit(SocketEvents.PT_TASK_STATUS_CHANGE.toString(), {
id: body.task_id,
parent_task: body.parent_task,
color_code: changeResponse.color_code,
status_id: body.status_id,
statusCategory: changeResponse.status_category
});
} catch (e) {
log_error(e);
}
}

View File

@@ -0,0 +1,27 @@
import { Server, Socket } from "socket.io";
import { log_error } from "../util";
import db from "../../config/db";
import { SocketEvents } from "../events";
export async function on_pt_task_time_estimation_change(_io: Server, socket: Socket, data?: string) {
try {
const q = `UPDATE cpt_tasks SET total_minutes = $2 WHERE id = $1 RETURNING total_minutes;`;
const body = JSON.parse(data as string);
const hours = body.total_hours || 0;
const minutes = body.total_minutes || 0;
const totalMinutes = (hours * 60) + minutes;
const result = await db.query(q, [body.task_id, totalMinutes]);
const d = {
id: body.task_id,
total_time_string: `${hours}h ${minutes}m`
};
socket.emit(SocketEvents.PT_TASK_TIME_ESTIMATION_CHANGE.toString(), d);
} catch (e) {
log_error(e);
}
}

View File

@@ -0,0 +1,66 @@
import { Server, Socket } from "socket.io";
import db from "../../config/db";
import { SocketEvents } from "../events";
import { log_error } from "../util";
import momentTime from "moment-timezone";
import moment from "moment-timezone";
async function createAllocation(body: any) {
const fromStart = Math.floor(body.offset) / 35;
const duration = Math.floor(body.width) / 35;
const chartStartDate = moment(body.chart_start);
body.allocated_from = chartStartDate.add(fromStart, "days").format("YYYY-MM-DD").trim();
body.allocated_to = moment(body.allocated_from).add(duration - 1, "days").format("YYYY-MM-DD").trim();
return body;
}
async function checkExists(body: any) {
const getq = `SELECT id, allocated_from, allocated_to FROM project_member_allocations WHERE project_id = $1 AND team_member_id = $2`;
const getResult = await db.query(getq, [body.project_id, body.team_member_id]);
if (getResult.rows.length > 0) {
for (const row of getResult.rows) {
const fAllocatedFrom = momentTime.tz(row.allocated_from, `${body.time_zone}`).format("YYYY-MM-DD");
const fAllocatedTo = momentTime.tz(row.allocated_to, `${body.time_zone}`).format("YYYY-MM-DD");
if (moment(fAllocatedFrom).isSameOrAfter(moment(body.allocated_from)) && moment(fAllocatedTo).isSameOrBefore(moment(body.allocated_to))) {
const deleteq = `DELETE FROM project_member_allocations WHERE id IN ($1)`;
await db.query(deleteq, [row.id]);
}
}
}
}
export async function on_schedule_member_allocation_create(_io: Server, socket: Socket, data?: string) {
try {
const body = JSON.parse(data as string);
await createAllocation(body);
await checkExists(body);
const q = `INSERT INTO project_member_allocations(project_id, team_member_id, allocated_from, allocated_to)
VALUES ($1, $2, $3, $4)`;
await db.query(q, [body.project_id, body.team_member_id, body.allocated_from, body.allocated_to]);
socket.emit(SocketEvents.SCHEDULE_MEMBER_ALLOCATION_CREATE.toString(), {
project_id: body.project_id,
team_member_id: body.team_member_id
});
return;
} catch (error) {
log_error(error);
}
const body = JSON.parse(data as string);
socket.emit(SocketEvents.SCHEDULE_MEMBER_ALLOCATION_CREATE.toString(), {
project_id: body.project_id,
team_member_id: body.team_member_id
});
}

View File

@@ -0,0 +1,36 @@
import {Server, Socket} from "socket.io";
import db from "../../config/db";
import {SocketEvents} from "../events";
import {log_error} from "../util";
export async function on_schedule_member_end_date_change(_io: Server, socket: Socket, data?: string) {
try {
const q = `UPDATE project_member_allocations
SET allocated_to = $4
WHERE id = $3 AND project_id = $1 AND team_member_id = $2`;
const body = JSON.parse(data as string);
const result = await db.query(q, [body.project_id, body.team_member_is, body.allocation_ids[0], body.allocated_to]);
if (result && body.allocation_ids.length > 1) {
for (let i = 1; i < body.allocation_ids.length; i++) {
const dq = `DELETE FROM project_member_allocations WHERE id = $1`;
await db.query(dq, [body.allocation_ids[i]]);
}
}
socket.emit(SocketEvents.SCHEDULE_MEMBER_END_DATE_CHANGE.toString(), {
id : body.allocation_ids[0],
date: body.allocated_to
});
return;
} catch (error) {
log_error(error);
}
socket.emit(SocketEvents.SCHEDULE_MEMBER_END_DATE_CHANGE.toString(), null);
}

View File

@@ -0,0 +1,36 @@
import {Server, Socket} from "socket.io";
import db from "../../config/db";
import {SocketEvents} from "../events";
import {log_error} from "../util";
export async function on_schedule_member_start_date_change(_io: Server, socket: Socket, data?: string) {
try {
const q = `UPDATE project_member_allocations
SET allocated_from = $4
WHERE id = $3 AND project_id = $1 AND team_member_id = $2`;
const body = JSON.parse(data as string);
const result = await db.query(q, [body.project_id, body.team_member_is, body.allocation_ids[0], body.allocated_from]);
if (result && body.allocation_ids.length > 1) {
for (let i = 1; i < body.allocation_ids.length; i++) {
const dq = `DELETE FROM project_member_allocations WHERE id = $1`;
await db.query(dq, [body.allocation_ids[i]]);
}
}
socket.emit(SocketEvents.SCHEDULE_MEMBER_START_DATE_CHANGE.toString(), {
id : body.allocation_ids[0],
date: body.allocated_from
});
return;
} catch (error) {
log_error(error);
}
socket.emit(SocketEvents.SCHEDULE_MEMBER_START_DATE_CHANGE.toString(), null);
}

View File

@@ -0,0 +1,55 @@
// Sync with the client
export enum SocketEvents {
LOGIN,
LOGOUT,
INVITATIONS_UPDATE,
NOTIFICATIONS_UPDATE,
TEAM_MEMBER_REMOVED,
TASK_COMMENTS_UPDATED,
QUICK_TASK,
QUICK_ASSIGNEES_UPDATE,
TASK_STATUS_CHANGE,
TASK_PRIORITY_CHANGE,
TASK_NAME_CHANGE,
TASK_LABELS_CHANGE,
CREATE_LABEL,
TASK_END_DATE_CHANGE,
TASK_START_DATE_CHANGE,
TASK_TIME_ESTIMATION_CHANGE,
TASK_DESCRIPTION_CHANGE,
GET_TASK_PROGRESS,
TASK_TIMER_START,
TASK_TIMER_STOP,
TASK_SORT_ORDER_CHANGE,
JOIN_OR_LEAVE_PROJECT_ROOM,
PROJECT_UPDATES_AVAILABLE,
TASK_SUBSCRIBERS_CHANGE,
PROJECT_SUBSCRIBERS_CHANGE,
TASK_PHASE_CHANGE,
ROADMAP_SORT_ORDER_CHANGE,
PHASE_START_DATE_CHANGE,
PHASE_END_DATE_CHANGE,
NEW_PROJECT_COMMENT_RECEIVED,
PROJECT_HEALTH_CHANGE,
PROJECT_START_DATE_CHANGE,
PROJECT_END_DATE_CHANGE,
PROJECT_STATUS_CHANGE,
PROJECT_CATEGORY_CHANGE,
CREATE_PROJECT_CATEGORY,
PT_QUICK_TASK,
PT_NAME_CHANGE,
PT_TASK_SORT_ORDER_CHANGE,
PT_TASK_NAME_CHANGE,
PT_TASK_TIME_ESTIMATION_CHANGE,
PT_TASK_DESCRIPTION_CHANGE,
PT_TASK_LABELS_CHANGE,
PT_CREATE_LABEL,
PT_TASK_PHASE_CHANGE,
PT_TASK_STATUS_CHANGE,
PT_TASK_PRIORITY_CHANGE,
GANNT_DRAG_CHANGE,
SCHEDULE_MEMBER_ALLOCATION_CREATE,
SCHEDULE_MEMBER_START_DATE_CHANGE,
SCHEDULE_MEMBER_END_DATE_CHANGE,
PROJECT_DATA_CHANGE
}

View File

@@ -0,0 +1,102 @@
import { Socket } from "socket.io";
import { on_login } from "./commands/on-connect";
import { on_create_label } from "./commands/on-create-label";
import { on_disconnect } from "./commands/on-disconnect";
import { on_quick_assign_or_remove } from "./commands/on-quick-assign-or-remove";
import { on_quick_task } from "./commands/on-quick-task";
import { on_task_end_date_change } from "./commands/on-task-end-date-change";
import { on_task_label_change } from "./commands/on-task-labels-change";
import { on_task_name_change } from "./commands/on-task-name-change";
import { on_task_priority_change } from "./commands/on-task-priority-change";
import { on_task_status_change } from "./commands/on-task-status-change";
import { on_task_start_date_change } from "./commands/on-task-start-date-change";
import { SocketEvents } from "./events";
import { log } from "./util";
import { on_time_estimation_change } from "./commands/on-time-estimation-change";
import { on_task_description_change } from "./commands/on-task-description-change";
import { on_get_task_progress } from "./commands/on-get-task-progress";
import { on_task_timer_start } from "./commands/on-task-timer-start";
import { on_task_timer_stop } from "./commands/on-task-timer-stop";
import { on_task_sort_order_change } from "./commands/on-task-sort-order-change";
import { on_join_project_room as on_join_or_leave_project_room } from "./commands/on-join-or-leave-project-room";
import { on_task_subscriber_change } from "./commands/on-task-subscriber-change";
import { on_project_subscriber_change } from "./commands/on-project-subscriber-change";
import { on_task_phase_change } from "./commands/on-task-phase-change";
import { on_roadmap_sort_order_change } from "./commands/on-roadmap-sort-order-change";
import { on_phase_start_date_change } from "./commands/on-phase-start-date-change";
import { on_phase_end_date_change } from "./commands/on-phase-end-date-change";
import { on_project_health_change } from "./commands/on-project-health-change";
import { on_project_start_date_change } from "./commands/on-project-start-date-change";
import { on_project_end_date_change } from "./commands/on-project-end-date-change";
import { on_project_status_change } from "./commands/on-project-status-change";
import { on_project_category_change } from "./commands/on-project-category-change";
import { on_create_project_category } from "./commands/on-create-project-category";
import { on_pt_create_label } from "./commands/on_pt_create_label";
import { on_pt_name_change } from "./commands/on_pt_name_change";
import { on_pt_quick_task } from "./commands/on_pt_quick_task";
import { on_pt_task_description_change } from "./commands/on_pt_task_description_change";
import { on_pt_task_labels_change } from "./commands/on_pt_task_labels_change";
import { on_pt_task_name_change } from "./commands/on_pt_task_name_change";
import { on_pt_task_phase_change } from "./commands/on_pt_task_phase_change";
import { on_pt_task_priority_change } from "./commands/on_pt_task_priority_change";
import { on_pt_task_sort_order_change } from "./commands/on_pt_task_sort_order_change";
import { on_pt_task_status_change } from "./commands/on_pt_task_status_change";
import { on_pt_task_time_estimation_change } from "./commands/on_pt_task_time_estimation_change";
import { on_gannt_drag_change } from "./commands/on_gannt_drag_change";
import { on_schedule_member_start_date_change } from "./commands/on_schedule_member_start_date_change";
import { on_schedule_member_end_date_change } from "./commands/on_schedule_member_end_date_change";
import { on_schedule_member_allocation_create } from "./commands/on_schedule_member_allocation_create";
export function register(io: any, socket: Socket) {
log(socket.id, "client registered");
socket.on(SocketEvents.LOGIN.toString(), id => on_login(io, socket, id));
socket.on(SocketEvents.QUICK_TASK.toString(), data => on_quick_task(io, socket, data));
socket.on(SocketEvents.QUICK_ASSIGNEES_UPDATE.toString(), data => on_quick_assign_or_remove(io, socket, data));
socket.on(SocketEvents.TASK_STATUS_CHANGE.toString(), data => on_task_status_change(io, socket, data));
socket.on(SocketEvents.TASK_PRIORITY_CHANGE.toString(), data => on_task_priority_change(io, socket, data));
socket.on(SocketEvents.TASK_NAME_CHANGE.toString(), data => on_task_name_change(io, socket, data));
socket.on(SocketEvents.TASK_LABELS_CHANGE.toString(), data => on_task_label_change(io, socket, data));
socket.on(SocketEvents.CREATE_LABEL.toString(), data => on_create_label(io, socket, data));
socket.on(SocketEvents.TASK_START_DATE_CHANGE.toString(), data => on_task_start_date_change(io, socket, data));
socket.on(SocketEvents.TASK_END_DATE_CHANGE.toString(), data => on_task_end_date_change(io, socket, data));
socket.on(SocketEvents.TASK_TIME_ESTIMATION_CHANGE.toString(), data => on_time_estimation_change(io, socket, data));
socket.on(SocketEvents.TASK_DESCRIPTION_CHANGE.toString(), data => on_task_description_change(io, socket, data));
socket.on(SocketEvents.GET_TASK_PROGRESS.toString(), data => on_get_task_progress(io, socket, data));
socket.on(SocketEvents.GET_TASK_PROGRESS.toString(), data => on_get_task_progress(io, socket, data));
socket.on(SocketEvents.TASK_TIMER_START.toString(), data => on_task_timer_start(io, socket, data));
socket.on(SocketEvents.TASK_TIMER_STOP.toString(), data => on_task_timer_stop(io, socket, data));
socket.on(SocketEvents.TASK_SORT_ORDER_CHANGE.toString(), data => on_task_sort_order_change(io, socket, data));
socket.on(SocketEvents.JOIN_OR_LEAVE_PROJECT_ROOM.toString(), data => on_join_or_leave_project_room(io, socket, data));
socket.on(SocketEvents.TASK_SUBSCRIBERS_CHANGE.toString(), data => on_task_subscriber_change(io, socket, data));
socket.on(SocketEvents.PROJECT_SUBSCRIBERS_CHANGE.toString(), data => on_project_subscriber_change(io, socket, data));
socket.on(SocketEvents.TASK_PHASE_CHANGE.toString(), data => on_task_phase_change(io, socket, data));
socket.on(SocketEvents.ROADMAP_SORT_ORDER_CHANGE.toString(), data => on_roadmap_sort_order_change(io, socket, data));
socket.on(SocketEvents.PHASE_START_DATE_CHANGE.toString(), data => on_phase_start_date_change(io, socket, data));
socket.on(SocketEvents.PHASE_END_DATE_CHANGE.toString(), data => on_phase_end_date_change(io, socket, data));
socket.on(SocketEvents.PROJECT_HEALTH_CHANGE.toString(), data => on_project_health_change(io, socket, data));
socket.on(SocketEvents.PROJECT_START_DATE_CHANGE.toString(), data => on_project_start_date_change(io, socket, data));
socket.on(SocketEvents.PROJECT_END_DATE_CHANGE.toString(), data => on_project_end_date_change(io, socket, data));
socket.on(SocketEvents.PROJECT_STATUS_CHANGE.toString(), data => on_project_status_change(io, socket, data));
socket.on(SocketEvents.PROJECT_CATEGORY_CHANGE.toString(), data => on_project_category_change(io, socket, data));
socket.on(SocketEvents.CREATE_PROJECT_CATEGORY.toString(), data => on_create_project_category(io, socket, data));
socket.on(SocketEvents.PT_QUICK_TASK.toString(), data => on_pt_quick_task(io, socket, data));
socket.on(SocketEvents.PT_NAME_CHANGE.toString(), data => on_pt_name_change(io, socket, data));
socket.on(SocketEvents.PT_TASK_SORT_ORDER_CHANGE.toString(), data => on_pt_task_sort_order_change(io, socket, data));
socket.on(SocketEvents.PT_TASK_NAME_CHANGE.toString(), data => on_pt_task_name_change(io, socket, data));
socket.on(SocketEvents.PT_TASK_TIME_ESTIMATION_CHANGE.toString(), data => on_pt_task_time_estimation_change(io, socket, data));
socket.on(SocketEvents.PT_TASK_DESCRIPTION_CHANGE.toString(), data => on_pt_task_description_change(io, socket, data));
socket.on(SocketEvents.PT_TASK_LABELS_CHANGE.toString(), data => on_pt_task_labels_change(io, socket, data));
socket.on(SocketEvents.PT_CREATE_LABEL.toString(), data => on_pt_create_label(io, socket, data));
socket.on(SocketEvents.PT_TASK_PHASE_CHANGE.toString(), data => on_pt_task_phase_change(io, socket, data));
socket.on(SocketEvents.PT_TASK_STATUS_CHANGE.toString(), data => on_pt_task_status_change(io, socket, data));
socket.on(SocketEvents.PT_TASK_PRIORITY_CHANGE.toString(), data => on_pt_task_priority_change(io, socket, data));
socket.on(SocketEvents.GANNT_DRAG_CHANGE.toString(), data => on_gannt_drag_change(io, socket, data));
socket.on(SocketEvents.SCHEDULE_MEMBER_ALLOCATION_CREATE.toString(), data => on_schedule_member_allocation_create(io, socket, data));
socket.on(SocketEvents.SCHEDULE_MEMBER_START_DATE_CHANGE.toString(), data => on_schedule_member_start_date_change(io, socket, data));
socket.on(SocketEvents.SCHEDULE_MEMBER_END_DATE_CHANGE.toString(), data => on_schedule_member_end_date_change(io, socket, data));
// socket.io built-in event
socket.on("disconnect", (reason) => on_disconnect(io, socket, reason));
}

View File

@@ -0,0 +1,31 @@
import {Socket} from "socket.io";
import {ISocketSession} from "../interfaces/socket-session";
import db from "../config/db";
import {SocketEvents} from "./events";
/** [Socket IO] Log a socket io debug log */
export function log(id: string, value: any) {
console.log(`[${id}] ${value}`);
}
/** [Socket IO] Log a socket io error */
export function log_error(error: any) {
console.trace(`[SOCKET.IO]`, error);
}
export function getLoggedInUserIdFromSocket(socket: Socket): string | null {
const {session} = socket.request as ISocketSession;
return session?.passport?.user || null;
}
export async function notifyProjectUpdates(socket: Socket, taskId: string) {
try {
const result = await db.query("SELECT project_id FROM tasks WHERE id = $1;", [taskId]);
const [data] = result.rows;
if (data.project_id) {
socket.to(data.project_id).emit(SocketEvents.PROJECT_UPDATES_AVAILABLE.toString());
}
} catch (error) {
// ignore
}
}