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,88 @@
export interface IProjectTemplateLabel {
label_id?: string;
name?: string;
color_code?: string;
}
export interface IProjectTemplate {
name?: string;
id?: string;
key?: string;
description?: string;
phase_label?: string;
phases?: any;
tasks?: any;
status?: any;
}
export interface IProjectTemplatePhase {
id?: string;
name?: string;
color_code?: string;
}
export interface IProjectTemplateStatus {
id?: string;
name?: string;
category_id?: string;
category_name?: string;
sort_order?: string;
}
export interface IProjectTaskPhase {
name?: string;
}
export interface IProjectTemplateTask {
id?: string;
name?: string;
description?: string | null;
total_minutes?: number;
sort_order?: number;
priority_id?: string;
priority_name?: string;
new?: number;
parent_task_id?: string | null;
status_id?: string;
status_name?: string;
phase_id?: string;
phase_name?: string;
phases?: IProjectTaskPhase[];
labels?: IProjectTemplateLabel[];
task_no?: number;
original_task_id?: string;
}
export interface ITaskIncludes {
status?: boolean;
phase?: boolean;
labels?: boolean;
estimation?: boolean;
description?: boolean;
subtasks?: boolean;
}
export interface ICustomProjectTemplate {
name?: string;
phase_label?: string;
color_code?: string;
notes?: string;
team_id?: string;
}
export interface ICustomTemplatePhase {
name?: string;
color_code?: string;
template_id?: string;
}
export interface ICustomTemplateTask {
name?: string;
description: string;
total_minutes: string;
sort_order: string;
priority_id: string;
template_id: string;
parent_task_id: string;
status_id?: string;
}

View File

@@ -0,0 +1,521 @@
import { Socket } from "socket.io";
import db from "../../config/db";
import HandleExceptions from "../../decorators/handle-exceptions";
import { logStatusChange } from "../../services/activity-logs/activity-logs.service";
import { getColor, int, log_error } from "../../shared/utils";
import { generateProjectKey } from "../../utils/generate-project-key";
import WorklenzControllerBase from "../worklenz-controller-base";
import { ICustomProjectTemplate, ICustomTemplatePhase, IProjectTemplate, IProjectTemplateLabel, IProjectTemplatePhase, IProjectTemplateStatus, IProjectTemplateTask, ITaskIncludes } from "./interfaces";
export default abstract class ProjectTemplatesControllerBase extends WorklenzControllerBase {
@HandleExceptions()
protected static async insertProjectTemplate(body: IProjectTemplate) {
const { name, key, description, phase_label } = body;
const q = `INSERT INTO pt_project_templates(name, key, description, phase_label) VALUES ($1, $2, $3, $4) RETURNING id;`;
const result = await db.query(q, [name, key, description, phase_label]);
const [data] = result.rows;
return data.id;
}
@HandleExceptions()
protected static async insertTemplateProjectPhases(body: IProjectTemplatePhase[], template_id: string) {
for await (const phase of body) {
const { name, color_code } = phase;
const q = `INSERT INTO pt_phases(name, color_code, template_id) VALUES ($1, $2, $3);`;
await db.query(q, [name, color_code, template_id]);
}
}
@HandleExceptions()
protected static async insertTemplateProjectStatuses(body: IProjectTemplateStatus[], template_id: string) {
for await (const status of body) {
const { name, category_name, category_id } = status;
const q = `INSERT INTO pt_statuses(name, template_id, category_id)
VALUES ($1, $2, (SELECT id FROM sys_task_status_categories WHERE sys_task_status_categories.name = $3));`;
await db.query(q, [name, template_id, category_name]);
}
}
@HandleExceptions()
protected static async insertTemplateProjectTasks(body: IProjectTemplateTask[], template_id: string) {
for await (const template_task of body) {
const { name, description, total_minutes, sort_order, priority_name, parent_task_id, phase_name, status_name } = template_task;
const q = `INSERT INTO pt_tasks(name, description, total_minutes, sort_order, priority_id, template_id, parent_task_id, status_id)
VALUES ($1, $2, $3, $4, (SELECT id FROM task_priorities WHERE task_priorities.name = $5), $6, $7,
(SELECT id FROM pt_statuses WHERE pt_statuses.name = $8 AND pt_statuses.template_id = $6)) RETURNING id;`;
const result = await db.query(q, [name, description, total_minutes, sort_order, priority_name, template_id, parent_task_id, status_name]);
const [task] = result.rows;
await this.insertTemplateTaskPhases(task.id, template_id, phase_name);
if (template_task.labels) await this.insertTemplateTaskLabels(task.id, template_task.labels);
}
}
@HandleExceptions()
protected static async insertTemplateTaskPhases(task_id: string, template_id: string, phase_name = "") {
const q = `INSERT INTO pt_task_phases (task_id, phase_id) VALUES ($1, (SELECT id FROM pt_phases WHERE template_id = $2 AND name = $3));`;
await db.query(q, [task_id, template_id, phase_name]);
}
@HandleExceptions()
protected static async insertTemplateTaskLabels(task_id: string, labels: IProjectTemplateLabel[]) {
for await (const label of labels) {
const q = `INSERT INTO pt_task_labels(task_id, label_id) VALUES ($1, (SELECT id FROM pt_labels WHERE name = $2));`;
await db.query(q, [task_id, label.name]);
}
}
@HandleExceptions()
protected static async getTemplateData(template_id: string) {
const q = `SELECT id,
name,
description,
phase_label,
image_url,
color_code,
(SELECT COALESCE(ARRAY_TO_JSON(ARRAY_AGG(ROW_TO_JSON(rec))), '[]'::JSON)
FROM (SELECT name, color_code FROM pt_phases WHERE template_id = pt.id) rec) AS phases,
(SELECT COALESCE(ARRAY_TO_JSON(ARRAY_AGG(ROW_TO_JSON(rec))), '[]'::JSON)
FROM (SELECT name,
category_id,
(SELECT color_code
FROM sys_task_status_categories
WHERE sys_task_status_categories.id = pt_statuses.category_id)
FROM pt_statuses
WHERE template_id = pt.id) rec) AS status,
(SELECT COALESCE(ARRAY_TO_JSON(ARRAY_AGG(ROW_TO_JSON(rec))), '[]'::JSON)
FROM (SELECT name, pt_labels.color_code
FROM pt_labels
WHERE id IN (SELECT label_id
FROM pt_task_labels pttl
WHERE task_id IN (SELECT id
FROM pt_tasks
WHERE pt_tasks.template_id = pt.id))) rec) AS labels,
(SELECT COALESCE(ARRAY_TO_JSON(ARRAY_AGG(ROW_TO_JSON(rec))), '[]'::JSON)
FROM (SELECT name,
color_code
FROM task_priorities) rec) AS priorities,
(SELECT COALESCE(ARRAY_TO_JSON(ARRAY_AGG(ROW_TO_JSON(rec))), '[]'::JSON)
FROM (SELECT name,
(SELECT name FROM pt_statuses WHERE status_id = pt_statuses.id) AS status_name,
(SELECT name FROM task_priorities tp WHERE priority_id = tp.id ) AS priority_name,
(SELECT COALESCE(ARRAY_TO_JSON(ARRAY_AGG(ROW_TO_JSON(rec))), '[]'::JSON)
FROM (SELECT name
FROM pt_phases pl
WHERE pl.id =
(SELECT phase_id FROM pt_task_phases WHERE task_id = pt_tasks.id)) rec) AS phases,
(SELECT COALESCE(ARRAY_TO_JSON(ARRAY_AGG(ROW_TO_JSON(rec))), '[]'::JSON)
FROM (SELECT name
FROM pt_labels pl
LEFT JOIN pt_task_labels pttl ON pl.id = pttl.label_id
WHERE pttl.task_id = pt_tasks.id) rec) AS labels
FROM pt_tasks
WHERE template_id = pt.id) rec) AS tasks
FROM pt_project_templates pt
WHERE id = $1;`;
const result = await db.query(q, [template_id]);
const [data] = result.rows;
for (const phase of data.phases) {
phase.color_code = getColor(phase.name);
}
return data;
}
@HandleExceptions()
protected static async getCustomTemplateData(template_id: string) {
const q = `SELECT id,
name,
notes AS description,
phase_label,
color_code,
(SELECT COALESCE(ARRAY_TO_JSON(ARRAY_AGG(ROW_TO_JSON(rec))), '[]'::JSON)
FROM (SELECT name, color_code FROM cpt_phases WHERE template_id = pt.id) rec) AS phases,
(SELECT COALESCE(ARRAY_TO_JSON(ARRAY_AGG(ROW_TO_JSON(rec))), '[]'::JSON)
FROM (SELECT name,
category_id,
(SELECT color_code
FROM sys_task_status_categories
WHERE sys_task_status_categories.id = cpts.category_id)
FROM cpt_task_statuses cpts
WHERE template_id = pt.id ORDER BY sort_order) rec) AS status,
(SELECT COALESCE(ARRAY_TO_JSON(ARRAY_AGG(ROW_TO_JSON(rec))), '[]'::JSON)
FROM (SELECT name, tl.color_code
FROM team_labels tl
WHERE id IN (SELECT label_id
FROM cpt_task_labels ctl
WHERE task_id IN (SELECT id
FROM cpt_tasks
WHERE cpt_tasks.template_id = pt.id))) rec) AS labels,
(SELECT COALESCE(ARRAY_TO_JSON(ARRAY_AGG(ROW_TO_JSON(rec))), '[]'::JSON)
FROM (SELECT name,
color_code
FROM task_priorities) rec) AS priorities,
(SELECT COALESCE(ARRAY_TO_JSON(ARRAY_AGG(ROW_TO_JSON(rec))), '[]'::JSON)
FROM (SELECT id AS original_task_id,
name,
parent_task_id,
description,
total_minutes,
(SELECT name FROM cpt_task_statuses cts WHERE status_id = cts.id) AS status_name,
(SELECT name FROM task_priorities tp WHERE priority_id = tp.id) AS priority_name,
(SELECT COALESCE(ARRAY_TO_JSON(ARRAY_AGG(ROW_TO_JSON(rec))), '[]'::JSON)
FROM (SELECT name
FROM cpt_phases pl
WHERE pl.id =
(SELECT phase_id FROM cpt_task_phases WHERE task_id = cpt_tasks.id)) rec) AS phases,
(SELECT COALESCE(ARRAY_TO_JSON(ARRAY_AGG(ROW_TO_JSON(rec))), '[]'::JSON)
FROM (SELECT name
FROM team_labels pl
LEFT JOIN cpt_task_labels cttl ON pl.id = cttl.label_id
WHERE cttl.task_id = cpt_tasks.id) rec) AS labels
FROM cpt_tasks
WHERE template_id = pt.id
ORDER BY parent_task_id NULLS FIRST) rec) AS tasks
FROM custom_project_templates pt
WHERE id = $1;`;
const result = await db.query(q, [template_id]);
const [data] = result.rows;
return data;
}
private static async getAllKeysByTeamId(teamId?: string) {
if (!teamId) return [];
try {
const result = await db.query("SELECT key FROM projects WHERE team_id = $1;", [teamId]);
return result.rows.map((project: any) => project.key).filter((key: any) => !!key);
} catch (error) {
return [];
}
}
private static async checkProjectNameExists(project_name: string, teamId?: string) {
if (!teamId) return;
try {
const result = await db.query("SELECT count(*) FROM projects WHERE name = $1 AND team_id = $2;", [project_name, teamId]);
const [data] = result.rows;
return int(data.count) || 0;
} catch (error) {
return [];
}
}
@HandleExceptions()
protected static async importTemplate(body: any) {
const q = `SELECT create_project($1) AS project`;
const count = await this.checkProjectNameExists(body.name, body.team_id);
const keys = await this.getAllKeysByTeamId(body.team_id as string);
body.key = generateProjectKey(body.name, keys) || null;
if (count !== 0) body.name = `${body.name} - ${body.key}`;
const result = await db.query(q, [JSON.stringify(body)]);
const [data] = result.rows;
return data.project.id;
}
@HandleExceptions()
protected static async insertTeamLabels(labels: IProjectTemplateLabel[], team_id = "") {
if (!team_id) return;
for await (const label of labels) {
const q = `INSERT INTO team_labels(name, color_code, team_id)
VALUES ($1, $2, $3)
ON CONFLICT (name, team_id) DO NOTHING;`;
await db.query(q, [label.name, label.color_code, team_id]);
}
}
@HandleExceptions()
protected static async insertProjectPhases(phases: IProjectTemplatePhase[], project_id = "",) {
if (!project_id) return;
let i = 0;
for await (const phase of phases) {
const q = `INSERT INTO project_phases(name, color_code, project_id, sort_index) VALUES ($1, $2, $3, $4);`;
await db.query(q, [phase.name, phase.color_code, project_id, i]);
i++;
}
}
protected static async insertProjectStatuses(statuses: IProjectTemplateStatus[], project_id = "", team_id = "") {
if (!project_id || !team_id) return;
try {
for await (const status of statuses) {
const q = `INSERT INTO task_statuses(name, project_id, team_id, category_id) VALUES($1, $2, $3, $4);`;
await db.query(q, [status.name, project_id, team_id, status.category_id]);
}
} catch (error) {
log_error(error);
}
}
@HandleExceptions()
protected static async insertTaskPhase(task_id: string, phase_name: string, project_id: string) {
const q = `INSERT INTO task_phase(task_id, phase_id)
VALUES ($1, (SELECT id FROM project_phases WHERE name = $2 AND project_id = $3));`;
await db.query(q, [task_id, phase_name, project_id]);
}
@HandleExceptions()
protected static async insertTaskLabel(task_id: string, label_name: string, team_id: string) {
const q = `INSERT INTO task_labels(task_id, label_id)
VALUES ($1, (SELECT id FROM team_labels WHERE name = $2 AND team_id = $3));`;
await db.query(q, [task_id, label_name, team_id]);
}
protected static async insertProjectTasks(tasks: IProjectTemplateTask[], team_id: string, project_id = "", user_id = "", socket: Socket | null) {
if (!project_id) return;
try {
for await (const [key, task] of tasks.entries()) {
const q = `INSERT INTO tasks(name, project_id, status_id, priority_id, reporter_id, sort_order)
VALUES ($1, $2, (SELECT id FROM task_statuses ts WHERE ts.name = $3 AND ts.project_id = $2),
(SELECT id FROM task_priorities tp WHERE tp.name = $4), $5, $6)
RETURNING id, status_id;`;
const result = await db.query(q, [task.name, project_id, task.status_name, task.priority_name, user_id, key]);
const [data] = result.rows;
if (task.phases) {
for await (const phase of task.phases) {
await this.insertTaskPhase(data.id, phase.name as string, project_id);
}
}
if (task.labels) {
for await (const label of task.labels) {
await this.insertTaskLabel(data.id, label.name as string, team_id);
}
}
if (socket) {
logStatusChange({
task_id: data.id,
socket,
new_value: data.status_id,
old_value: null
});
}
}
} catch (error) {
log_error(error);
}
}
// custom templates
@HandleExceptions()
protected static async getProjectData(project_id: string) {
const q = `SELECT phase_label, notes, color_code FROM projects WHERE id = $1;`;
const result = await db.query(q, [project_id]);
const [data] = result.rows;
return data;
}
@HandleExceptions()
protected static async getProjectStatus(project_id: string) {
const q = `SELECT name, category_id, sort_order FROM task_statuses WHERE project_id = $1;`;
const result = await db.query(q, [project_id]);
return result.rows;
}
@HandleExceptions()
protected static async getProjectPhases(project_id: string) {
const q = `SELECT name, color_code FROM project_phases WHERE project_id = $1 ORDER BY sort_index ASC;`;
const result = await db.query(q, [project_id]);
return result.rows;
}
@HandleExceptions()
protected static async getProjectLabels(team_id: string, project_id: string) {
const q = `SELECT COALESCE(ARRAY_TO_JSON(ARRAY_AGG(DISTINCT JSONB_BUILD_OBJECT('name', name))), '[]'::JSON) AS labels
FROM team_labels
WHERE team_id = $1
AND id IN (SELECT label_id
FROM task_labels
WHERE task_id IN (SELECT id
FROM tasks
WHERE project_id = $2));`;
const result = await db.query(q, [team_id, project_id]);
const [data] = result.rows;
return data.labels;
}
@HandleExceptions()
protected static async getTasksByProject(project_id: string, taskIncludes: ITaskIncludes) {
let taskIncludesClause = "";
if (taskIncludes.description) taskIncludesClause += " description,";
if (taskIncludes.estimation) taskIncludesClause += " total_minutes,";
if (taskIncludes.status) taskIncludesClause += ` (SELECT name FROM task_statuses WHERE status_id = id) AS status_name,`;
if (taskIncludes.labels) {
taskIncludesClause += ` (SELECT COALESCE(ARRAY_TO_JSON(ARRAY_AGG(ROW_TO_JSON(rec))), '[]'::JSON)
FROM (SELECT (SELECT name FROM team_labels WHERE id = task_labels.label_id)
FROM task_labels
WHERE task_id = t.id) rec) AS labels,`;
}
if (taskIncludes.phase) {
taskIncludesClause += ` (SELECT name
FROM project_phases
WHERE project_phases.id = (SELECT phase_id FROM task_phase WHERE task_id = t.id)) AS phase_name,`;
}
if (taskIncludes.subtasks) {
taskIncludesClause += ` parent_task_id,`;
}
const q = `SELECT id,
name,
sort_order,
task_no,
${taskIncludesClause}
priority_id
FROM tasks t
WHERE project_id = $1
AND archived IS FALSE ORDER BY parent_task_id NULLS FIRST;`;
const result = await db.query(q, [project_id]);
return result.rows;
}
@HandleExceptions()
protected static async insertCustomTemplate(body: ICustomProjectTemplate) {
const q = `SELECT create_project_template($1)`;
const result = await db.query(q, [JSON.stringify(body)]);
const [data] = result.rows;
return data.id;
}
@HandleExceptions()
protected static async insertCustomTemplatePhases(body: ICustomTemplatePhase[], template_id: string) {
for await (const phase of body) {
const { name, color_code } = phase;
const q = `INSERT INTO cpt_phases(name, color_code, template_id) VALUES ($1, $2, $3);`;
await db.query(q, [name, color_code, template_id]);
}
}
@HandleExceptions()
protected static async insertCustomTemplateStatus(body: IProjectTemplateStatus[], template_id: string, team_id: string) {
for await (const status of body) {
const { name, category_id, sort_order } = status;
const q = `INSERT INTO cpt_task_statuses(name, template_id, team_id, category_id, sort_order)
VALUES ($1, $2, $3, $4, $5);`;
await db.query(q, [name, template_id, team_id, category_id, sort_order]);
}
}
@HandleExceptions()
protected static async insertCustomTemplateTasks(body: IProjectTemplateTask[], template_id: string, team_id: string, status = true) {
for await (const task of body) {
const { name, description, total_minutes, sort_order, priority_id, status_name, task_no, parent_task_id, id, phase_name } = task;
const q = `INSERT INTO cpt_tasks(name, description, total_minutes, sort_order, priority_id, template_id, status_id, task_no,
parent_task_id, original_task_id)
VALUES ($1, $2, $3, $4, $5, $6, (SELECT id FROM cpt_task_statuses cts WHERE cts.name = $7 AND cts.template_id = $6), $8,
(SELECT id FROM cpt_tasks WHERE original_task_id = $9 AND template_id = $6), $10)
RETURNING id;`;
const result = await db.query(q, [name, description, total_minutes || 0, sort_order, priority_id, template_id, status_name, task_no, parent_task_id, id]);
const [data] = result.rows;
if (data.id) {
if (phase_name) await this.insertCustomTemplateTaskPhases(data.id, template_id, phase_name);
if (task.labels) await this.insertCustomTemplateTaskLabels(data.id, task.labels, team_id);
}
}
}
@HandleExceptions()
protected static async insertCustomTemplateTaskPhases(task_id: string, template_id: string, phase_name = "") {
const q = `INSERT INTO cpt_task_phases (task_id, phase_id)
VALUES ($1, (SELECT id FROM cpt_phases WHERE template_id = $2 AND name = $3));`;
await db.query(q, [task_id, template_id, phase_name]);
}
@HandleExceptions()
protected static async insertCustomTemplateTaskLabels(task_id: string, labels: IProjectTemplateLabel[], team_id: string) {
for await (const label of labels) {
const q = `INSERT INTO cpt_task_labels(task_id, label_id)
VALUES ($1, (SELECT id FROM team_labels WHERE name = $2 AND team_id = $3));`;
await db.query(q, [task_id, label.name, team_id]);
}
}
@HandleExceptions()
protected static async updateTeamName(name: string, team_id: string, user_id: string) {
const q = `UPDATE teams SET name = TRIM($1::TEXT) WHERE id = $2 AND user_id = $3;`;
const result = await db.query(q, [name, team_id, user_id]);
return result.rows;
}
@HandleExceptions()
protected static async deleteDefaultStatusForProject(task_id: string) {
const q = `DELETE FROM task_statuses WHERE project_id = $1;`;
await db.query(q, [task_id]);
}
@HandleExceptions()
protected static async handleAccountSetup(project_id: string, user_id: string, team_name: string) {
// update user setup status
await db.query(`UPDATE users SET setup_completed = TRUE WHERE id = $1;`, [user_id]);
await db.query(`INSERT INTO organizations (user_id, organization_name, contact_number, contact_number_secondary, trial_in_progress,
trial_expire_date, subscription_status)
VALUES ($1, TRIM($2::TEXT), NULL, NULL, TRUE, CURRENT_DATE + INTERVAL '14 days', 'trialing')
ON CONFLICT (user_id) DO UPDATE SET organization_name = TRIM($2::TEXT);`, [user_id, team_name]);
}
protected static async insertProjectTasksFromCustom(tasks: IProjectTemplateTask[], team_id: string, project_id = "", user_id = "", socket: Socket | null) {
if (!project_id) return;
try {
for await (const [key, task] of tasks.entries()) {
const q = `INSERT INTO tasks(name, project_id, status_id, priority_id, reporter_id, sort_order, parent_task_id, description, total_minutes)
VALUES ($1, $2, (SELECT id FROM task_statuses ts WHERE ts.name = $3 AND ts.project_id = $2),
(SELECT id FROM task_priorities tp WHERE tp.name = $4), $5, $6, $7, $8, $9)
RETURNING id, status_id;`;
const parent_task: IProjectTemplateTask = tasks.find(t => t.original_task_id === task.parent_task_id) || {};
const result = await db.query(q, [task.name, project_id, task.status_name, task.priority_name, user_id, key, parent_task.id, task.description, task.total_minutes ? task.total_minutes : 0]);
const [data] = result.rows;
task.id = data.id;
if (task.phases) {
for await (const phase of task.phases) {
await this.insertTaskPhase(data.id, phase.name as string, project_id);
}
}
if (task.labels) {
for await (const label of task.labels) {
await this.insertTaskLabel(data.id, label.name as string, team_id);
}
}
if (socket) {
logStatusChange({
task_id: data.id,
socket,
new_value: data.status_id,
old_value: null
});
}
}
} catch (error) {
log_error(error);
}
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,104 @@
import db from "../../config/db";
import HandleExceptions from "../../decorators/handle-exceptions";
import { IWorkLenzRequest } from "../../interfaces/worklenz-request";
import { IWorkLenzResponse } from "../../interfaces/worklenz-response";
import { ServerResponse } from "../../models/server-response";
import { TASK_STATUS_COLOR_ALPHA } from "../../shared/constants";
import { getColor } from "../../shared/utils";
import WorklenzControllerBase from "../worklenz-controller-base";
export default class PtTaskPhasesController extends WorklenzControllerBase {
private static readonly DEFAULT_PHASE_COLOR = "#fbc84c";
@HandleExceptions()
public static async create(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> {
if (!req.query.id)
return res.status(400).send(new ServerResponse(false, null, "Invalid request"));
const q = `
INSERT INTO cpt_phases (name, color_code, template_id)
VALUES (CONCAT('Untitled Phase (', (SELECT COUNT(*) FROM cpt_phases WHERE template_id = $2) + 1, ')'), $1,
$2)
RETURNING id, name, color_code;
`;
req.body.color_code = this.DEFAULT_PHASE_COLOR;
const result = await db.query(q, [req.body.color_code, req.query.id]);
const [data] = result.rows;
data.color_code = data.color_code + TASK_STATUS_COLOR_ALPHA;
return res.status(200).send(new ServerResponse(true, data));
}
@HandleExceptions()
public static async get(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> {
const q = `
SELECT id, name, color_code, (SELECT COUNT(*) FROM cpt_task_phases WHERE phase_id = cpt_phases.id) AS usage
FROM cpt_phases
WHERE template_id = $1
ORDER BY created_at DESC;
`;
const result = await db.query(q, [req.query.id]);
for (const phase of result.rows)
phase.color_code = phase.color_code + TASK_STATUS_COLOR_ALPHA;
return res.status(200).send(new ServerResponse(true, result.rows));
}
@HandleExceptions({
raisedExceptions: {
"PHASE_EXISTS_ERROR": `Phase name "{0}" already exists. Please choose a different name.`
}
})
public static async update(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> {
const q = `SELECT update_phase_name($1, $2, $3);`;
const result = await db.query(q, [req.params.id, req.body.name.trim(), req.query.id]);
const [data] = result.rows;
data.update_phase_name.color_code = data.update_phase_name.color_code + TASK_STATUS_COLOR_ALPHA;
return res.status(200).send(new ServerResponse(true, data.update_phase_name));
}
@HandleExceptions()
public static async updateLabel(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> {
const q = `
UPDATE custom_project_templates
SET phase_label = $2
WHERE id = $1;
`;
const result = await db.query(q, [req.params.id, req.body.name.trim()]);
const [data] = result.rows;
return res.status(200).send(new ServerResponse(true, data));
}
@HandleExceptions()
public static async updateColor(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> {
const q = `UPDATE cpt_phases SET color_code = $3 WHERE id = $1 AND template_id = $2 RETURNING id, name, color_code;`;
const result = await db.query(q, [req.params.id, req.query.id, req.body.color_code.substring(0, req.body.color_code.length - 2)]);
const [data] = result.rows;
return res.status(200).send(new ServerResponse(true, data));
}
@HandleExceptions()
public static async deleteById(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> {
const q = `
DELETE
FROM cpt_phases
WHERE id = $1
AND template_id = $2
`;
const result = await db.query(q, [req.params.id, req.query.id]);
return res.status(200).send(new ServerResponse(true, result.rows));
}
}

View File

@@ -0,0 +1,146 @@
import db from "../../config/db";
import HandleExceptions from "../../decorators/handle-exceptions";
import { IWorkLenzRequest } from "../../interfaces/worklenz-request";
import { IWorkLenzResponse } from "../../interfaces/worklenz-response";
import { ServerResponse } from "../../models/server-response";
import WorklenzControllerBase from "../worklenz-controller-base";
const existsErrorMessage = "At least one status should exists under each category.";
export default class PtTaskStatusesController extends WorklenzControllerBase {
@HandleExceptions()
public static async create(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> {
const q = `
INSERT INTO cpt_task_statuses (name, template_id, team_id, category_id, sort_order)
VALUES ($1, $2, $3, $4, (SELECT MAX(sort_order) FROM cpt_task_statuses WHERE template_id = $2) + 1);
`;
const result = await db.query(q, [req.body.name, req.body.template_id, req.user?.team_id, req.body.category_id]);
const [data] = result.rows;
return res.status(200).send(new ServerResponse(true, data));
}
@HandleExceptions()
public static async getCreated(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> {
const team_id = req.user?.team_id;
const q = `SELECT create_pt_task_status($1, $2)`;
const result = await db.query(q, [JSON.stringify(req.body), team_id]);
const data = result.rows[0].create_pt_task_status[0];
return res.status(200).send(new ServerResponse(true, data));
}
@HandleExceptions()
public static async get(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> {
if (!req.query.template_id)
return res.status(400).send(new ServerResponse(false, null));
const q = `
SELECT cpt_task_statuses.id,
cpt_task_statuses.name,
stsc.color_code,
stsc.name AS category_name,
cpt_task_statuses.category_id,
stsc.description
FROM cpt_task_statuses
INNER JOIN sys_task_status_categories stsc ON cpt_task_statuses.category_id = stsc.id
WHERE template_id = $1
AND team_id = $2
ORDER BY cpt_task_statuses.sort_order;
`;
const result = await db.query(q, [req.query.template_id, req.user?.team_id]);
return res.status(200).send(new ServerResponse(true, result.rows));
}
@HandleExceptions()
public static async getCategories(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> {
const q = `SELECT id, name, color_code, description
FROM sys_task_status_categories
ORDER BY index;`;
const result = await db.query(q, []);
return res.status(200).send(new ServerResponse(true, result.rows));
}
@HandleExceptions()
public static async getById(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> {
const q = `
SELECT cpt_task_statuses.id, cpt_task_statuses.name, stsc.color_code
FROM cpt_task_statuses
INNER JOIN sys_task_status_categories stsc ON cpt_task_statuses.category_id = stsc.id
WHERE cpt_task_statuses.id = $1
AND template_id = $2;
`;
const result = await db.query(q, [req.params.id, req.query.template_id]);
const [data] = result.rows;
return res.status(200).send(new ServerResponse(true, data));
}
private static async hasMoreCategories(statusId: string, templateId: string) {
if (!statusId || !templateId)
return false;
const q = `
SELECT COUNT(*) AS count
FROM cpt_task_statuses
WHERE category_id = (SELECT category_id FROM cpt_task_statuses WHERE id = $1)
AND template_id = $2;
`;
const result = await db.query(q, [statusId, templateId]);
const [data] = result.rows;
return +data.count >= 2;
}
@HandleExceptions()
public static async update(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> {
const hasMoreCategories = await PtTaskStatusesController.hasMoreCategories(req.params.id, req.body.template_id);
if (!hasMoreCategories)
return res.status(200).send(new ServerResponse(false, null, existsErrorMessage).withTitle("Status update failed!"));
const q = `
UPDATE cpt_task_statuses
SET name = $2,
category_id = COALESCE($4, (SELECT id FROM sys_task_status_categories WHERE is_todo IS TRUE))
WHERE id = $1
AND template_id = $3
RETURNING (SELECT color_code FROM sys_task_status_categories WHERE id = cpt_task_statuses.category_id);
`;
const result = await db.query(q, [req.params.id, req.body.name, req.body.template_id, req.body.category_id]);
const [data] = result.rows;
return res.status(200).send(new ServerResponse(true, data));
}
@HandleExceptions({
raisedExceptions: {
"STATUS_EXISTS_ERROR": `Status name "{0}" already exists. Please choose a different name.`
}
})
public static async updateName(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> {
const q = `DO
$$
BEGIN
-- check whether the status name is already in
IF EXISTS(SELECT name
FROM cpt_task_statuses
WHERE name = '${req.body.name}'::TEXT
AND template_id = '${req.body.template_id}'::UUID)
THEN
RAISE 'STATUS_EXISTS_ERROR:%', ('${req.body.name}')::TEXT;
END IF;
UPDATE cpt_task_statuses
SET name = '${req.body.name}'::TEXT
WHERE id = '${req.params.id}'::UUID
AND template_id = '${req.body.template_id}'::UUID;
END
$$;`;
const result = await db.query(q, []);
const [data] = result.rows;
return res.status(200).send(new ServerResponse(true, data));
}
}

View File

@@ -0,0 +1,56 @@
import WorklenzControllerBase from "../worklenz-controller-base";
import { getColor } from "../../shared/utils";
import { PriorityColorCodes, TASK_PRIORITY_COLOR_ALPHA, TASK_STATUS_COLOR_ALPHA } from "../../shared/constants";
export const GroupBy = {
STATUS: "status",
PRIORITY: "priority",
LABELS: "labels",
PHASE: "phase"
};
export interface ITaskGroup {
id?: string;
name: string;
start_date?: string;
end_date?: string;
color_code: string;
category_id: string | null;
old_category_id?: string;
todo_progress?: number;
doing_progress?: number;
done_progress?: number;
tasks: any[];
}
export default class PtTasksControllerBase extends WorklenzControllerBase {
public static updateTaskViewModel(task: any) {
task.time_spent = {hours: ~~(task.total_minutes_spent / 60), minutes: task.total_minutes_spent % 60};
if (typeof task.sub_tasks_count === "undefined") task.sub_tasks_count = "0";
task.is_sub_task = !!task.parent_task_id;
task.total_time_string = `${~~(task.total_minutes / 60)}h ${(task.total_minutes % 60)}m`;
task.priority_color = PriorityColorCodes[task.priority_value] || PriorityColorCodes["0"];
task.show_sub_tasks = false;
if (task.phase_id) {
task.phase_color = task.phase_color
? task.phase_color + TASK_PRIORITY_COLOR_ALPHA : getColor(task.phase_name) + TASK_PRIORITY_COLOR_ALPHA;
}
task.all_labels = task.labels;
task.labels = PtTasksControllerBase.createTagList(task.labels, 2);
task.status_color = task.status_color + TASK_STATUS_COLOR_ALPHA;
task.priority_color = task.priority_color + TASK_PRIORITY_COLOR_ALPHA;
return task;
}
}

View File

@@ -0,0 +1,249 @@
import { ParsedQs } from "qs";
import db from "../../config/db";
import HandleExceptions from "../../decorators/handle-exceptions";
import { IWorkLenzRequest } from "../../interfaces/worklenz-request";
import { IWorkLenzResponse } from "../../interfaces/worklenz-response";
import { ServerResponse } from "../../models/server-response";
import { TASK_PRIORITY_COLOR_ALPHA, TASK_STATUS_COLOR_ALPHA, UNMAPPED } from "../../shared/constants";
import { getColor } from "../../shared/utils";
import PtTasksControllerBase, { GroupBy, ITaskGroup } from "./pt-tasks-controller-base";
export class PtTaskListGroup implements ITaskGroup {
name: string;
category_id: string | null;
color_code: string;
tasks: any[];
constructor(group: any) {
this.name = group.name;
this.category_id = group.category_id || null;
this.color_code = group.color_code + TASK_STATUS_COLOR_ALPHA;
this.tasks = [];
}
}
export default class PtTasksController extends PtTasksControllerBase {
private static isCountsOnly(query: ParsedQs) {
return query.count === "true";
}
public static isTasksOnlyReq(query: ParsedQs) {
return PtTasksController.isCountsOnly(query) || query.parent_task;
}
private static flatString(text: string) {
return (text || "").split(" ").map(s => `'${s}'`).join(",");
}
private static getFilterByTemplatsWhereClosure(text: string) {
return text ? `template_id IN (${this.flatString(text)})` : "";
}
private static getQuery(userId: string, options: ParsedQs) {
const searchField = options.search ? "cptt.name" : "sort_order";
const { searchQuery, sortField } = PtTasksController.toPaginationOptions(options, searchField);
const sortFields = sortField.replace(/ascend/g, "ASC").replace(/descend/g, "DESC") || "sort_order";
const isSubTasks = !!options.parent_task;
const subTasksFilter = isSubTasks ? "parent_task_id = $2" : "parent_task_id IS NULL";
return `
SELECT id,
name,
cptt.template_id AS template_id,
cptt.parent_task_id,
cptt.parent_task_id IS NOT NULL AS is_sub_task,
(SELECT COUNT(*)
FROM cpt_tasks
WHERE parent_task_id = cptt.id)::INT AS sub_tasks_count,
cptt.status_id AS status,
cptt.description,
cptt.sort_order,
(SELECT phase_id FROM cpt_task_phases WHERE task_id = cptt.id) AS phase_id,
(SELECT name
FROM cpt_phases
WHERE id = (SELECT phase_id FROM cpt_task_phases WHERE task_id = cptt.id)) AS phase_name,
(SELECT color_code
FROM cpt_phases
WHERE id = (SELECT phase_id FROM cpt_task_phases WHERE task_id = cptt.id)) AS phase_color,
(SELECT color_code
FROM sys_task_status_categories
WHERE id = (SELECT category_id FROM cpt_task_statuses WHERE id = cptt.status_id)) AS status_color,
(SELECT COALESCE(ROW_TO_JSON(r), '{}'::JSON)
FROM (SELECT is_done, is_doing, is_todo
FROM sys_task_status_categories
WHERE id = (SELECT category_id FROM cpt_task_statuses WHERE id = cptt.status_id)) r) AS status_category,
(SELECT COALESCE(JSON_AGG(r), '[]'::JSON)
FROM (SELECT cpt_task_labels.label_id AS id,
(SELECT name FROM team_labels WHERE id = cpt_task_labels.label_id),
(SELECT color_code FROM team_labels WHERE id = cpt_task_labels.label_id)
FROM cpt_task_labels
WHERE task_id = cptt.id) r) AS labels,
(SELECT id FROM task_priorities WHERE id = cptt.priority_id) AS priority,
(SELECT value FROM task_priorities WHERE id = cptt.priority_id) AS priority_value,
total_minutes
FROM cpt_tasks cptt
WHERE cptt.template_id=$1 AND ${subTasksFilter} ${searchQuery}
ORDER BY ${sortFields}
`;
}
public static async getGroups(groupBy: string, templateId: string): Promise<ITaskGroup[]> {
let q = "";
let params: any[] = [];
switch (groupBy) {
case GroupBy.STATUS:
q = `
SELECT id,
name,
(SELECT color_code FROM sys_task_status_categories WHERE id = cpt_task_statuses.category_id),
category_id
FROM cpt_task_statuses
WHERE template_id = $1
ORDER BY sort_order;
`;
params = [templateId];
break;
case GroupBy.PRIORITY:
q = `SELECT id, name, color_code
FROM task_priorities
ORDER BY value DESC;`;
break;
case GroupBy.LABELS:
q = `
SELECT id, name, color_code
FROM team_labels
WHERE team_id = $2
AND EXISTS(SELECT 1
FROM cpt_tasks
WHERE template_id = $1
AND EXISTS(SELECT 1 FROM cpt_task_labels WHERE task_id = cpt_tasks.id AND label_id = team_labels.id))
ORDER BY name;
`;
break;
case GroupBy.PHASE:
q = `
SELECT id, name, color_code
FROM cpt_phases
WHERE template_id = $1
ORDER BY created_at DESC;
`;
params = [templateId];
break;
default:
break;
}
const result = await db.query(q, params);
return result.rows;
}
@HandleExceptions()
public static async getList(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> {
const isSubTasks = !!req.query.parent_task;
const groupBy = (req.query.group || GroupBy.STATUS) as string;
const q = PtTasksController.getQuery(req.user?.id as string, req.query);
const params = isSubTasks ? [req.params.id || null, req.query.parent_task] : [req.params.id || null];
const result = await db.query(q, params);
const tasks = [...result.rows];
const groups = await this.getGroups(groupBy, req.params.id);
const map = groups.reduce((g: { [x: string]: ITaskGroup }, group) => {
if (group.id)
g[group.id] = new PtTaskListGroup(group);
return g;
}, {});
this.updateMapByGroup(tasks, groupBy, map);
const updatedGroups = Object.keys(map).map(key => {
const group = map[key];
return {
id: key,
...group
};
});
return res.status(200).send(new ServerResponse(true, updatedGroups));
}
public static updateMapByGroup(tasks: any[], groupBy: string, map: { [p: string]: ITaskGroup }) {
let index = 0;
const unmapped = [];
for (const task of tasks) {
task.index = index++;
PtTasksController.updateTaskViewModel(task);
if (groupBy === GroupBy.STATUS) {
map[task.status]?.tasks.push(task);
} else if (groupBy === GroupBy.PRIORITY) {
map[task.priority]?.tasks.push(task);
} else if (groupBy === GroupBy.PHASE && task.phase_id) {
map[task.phase_id]?.tasks.push(task);
} else {
unmapped.push(task);
}
const totalMinutes = task.total_minutes;
const hours = Math.floor(totalMinutes / 60);
const minutes = totalMinutes % 60;
task.total_hours = hours;
task.total_minutes = minutes;
}
if (unmapped.length) {
map[UNMAPPED] = {
name: UNMAPPED,
category_id: null,
color_code: "#fbc84c69",
tasks: unmapped
};
}
}
@HandleExceptions()
public static async getTasksOnly(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> {
const isSubTasks = !!req.query.parent_task;
const q = PtTasksController.getQuery(req.user?.id as string, req.query);
const params = isSubTasks ? [req.params.id || null, req.query.parent_task] : [req.params.id || null];
const result = await db.query(q, params);
let data: any[] = [];
// if true, we only return the record count
if (this.isCountsOnly(req.query)) {
[data] = result.rows;
} else { // else we return a flat list of tasks
data = [...result.rows];
for (const task of data) {
PtTasksController.updateTaskViewModel(task);
}
}
return res.status(200).send(new ServerResponse(true, data));
}
@HandleExceptions()
public static async bulkDelete(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> {
const deletedTasks = req.body.tasks.map((t: any) => t.id);
const result: any = {deleted_tasks: deletedTasks};
const q = `SELECT bulk_delete_pt_tasks($1) AS task;`;
await db.query(q, [JSON.stringify(req.body)]);
return res.status(200).send(new ServerResponse(true, result));
}
}

View File

@@ -0,0 +1,233 @@
import { IWorkLenzRequest } from "../../interfaces/worklenz-request";
import { IWorkLenzResponse } from "../../interfaces/worklenz-response";
import db from "../../config/db";
import { ServerResponse } from "../../models/server-response";
import HandleExceptions from "../../decorators/handle-exceptions";
import { templateData } from "./project-templates";
import ProjectTemplatesControllerBase from "./project-templates-base";
import { LOG_DESCRIPTIONS, TASK_PRIORITY_COLOR_ALPHA, TASK_STATUS_COLOR_ALPHA } from "../../shared/constants";
import { IO } from "../../shared/io";
export default class ProjectTemplatesController extends ProjectTemplatesControllerBase {
@HandleExceptions()
public static async getTemplates(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> {
const q = `SELECT id, name FROM pt_project_templates ORDER BY name;`;
const result = await db.query(q, []);
return res.status(200).send(new ServerResponse(true, result.rows));
}
@HandleExceptions()
public static async getCustomTemplates(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> {
const { searchQuery } = this.toPaginationOptions(req.query, "name");
const q = `SELECT id, name, created_at, FALSE AS selected FROM custom_project_templates WHERE team_id = $1 ${searchQuery} ORDER BY name;`;
const result = await db.query(q, [req.user?.team_id]);
return res.status(200).send(new ServerResponse(true, result.rows));
}
@HandleExceptions()
public static async deleteCustomTemplate(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> {
const { id } = req.params;
const q = `DELETE FROM custom_project_templates WHERE id = $1;`;
await db.query(q, [id]);
return res.status(200).send(new ServerResponse(true, [], "Template deleted successfully."));
}
@HandleExceptions()
public static async getDefaultProjectStatus() {
const q = `SELECT id FROM sys_project_statuses WHERE is_default IS TRUE;`;
const result = await db.query(q, []);
const [data] = result.rows;
return data.id;
}
@HandleExceptions()
public static async getDefaultProjectHealth() {
const q = `SELECT id FROM sys_project_healths WHERE is_default IS TRUE`;
const result = await db.query(q, []);
const [data] = result.rows;
return data.id;
}
@HandleExceptions()
public static async getTemplateById(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> {
const { id } = req.params;
const data = await this.getTemplateData(id);
for (const phase of data.phases) {
phase.color_code = phase.color_code + TASK_STATUS_COLOR_ALPHA;
}
for (const status of data.status) {
status.color_code = status.color_code + TASK_STATUS_COLOR_ALPHA;
}
for (const priority of data.priorities) {
priority.color_code = priority.color_code + TASK_PRIORITY_COLOR_ALPHA;
}
for (const label of data.labels) {
label.color_code = label.color_code + TASK_STATUS_COLOR_ALPHA;
}
return res.status(200).send(new ServerResponse(true, data));
}
@HandleExceptions()
public static async createTemplates(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> {
for (const template of templateData) {
let template_id: string | null = null;
template_id = await this.insertProjectTemplate(template);
if (template_id) {
await this.insertTemplateProjectPhases(template.phases, template_id);
await this.insertTemplateProjectStatuses(template.status, template_id);
await this.insertTemplateProjectTasks(template.tasks, template_id);
}
}
return res.status(200).send(new ServerResponse(true, []));
}
@HandleExceptions()
public static async importTemplates(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> {
const { template_id } = req.body;
let project_id: string | null = null;
const data = await this.getTemplateData(template_id);
if (data) {
data.team_id = req.user?.team_id || null;
data.user_id = req.user?.id || null;
data.folder_id = null;
data.category_id = null;
data.status_id = await this.getDefaultProjectStatus();
data.project_created_log = LOG_DESCRIPTIONS.PROJECT_CREATED;
data.project_member_added_log = LOG_DESCRIPTIONS.PROJECT_MEMBER_ADDED;
data.health_id = await this.getDefaultProjectHealth();
data.working_days = 0;
data.man_days = 0;
data.hours_per_day = 8;
project_id = await this.importTemplate(data);
await this.insertTeamLabels(data.labels, req.user?.team_id);
await this.insertProjectPhases(data.phases, project_id as string);
await this.insertProjectTasks(data.tasks, data.team_id, project_id as string, data.user_id, IO.getSocketById(req.user?.socket_id as string));
return res.status(200).send(new ServerResponse(true, { project_id }));
}
return res.status(200).send(new ServerResponse(true, { project_id }));
}
@HandleExceptions({
raisedExceptions: {
"TEMPLATE_EXISTS_ERROR": `A template with the name "{0}" already exists. Please choose a different name.`
}
})
public static async createCustomTemplate(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> {
const { project_id, templateName, projectIncludes, taskIncludes } = req.body;
const team_id = req.user?.team_id || null;
if (!team_id || !project_id) return res.status(400).send(new ServerResponse(false, {}));
let status, labels, phases = [];
const data = await this.getProjectData(project_id);
if (projectIncludes.statuses) {
status = await this.getProjectStatus(project_id);
}
if (projectIncludes.phases) {
phases = await this.getProjectPhases(project_id);
}
if (projectIncludes.labels) {
labels = await this.getProjectLabels(team_id, project_id);
}
const tasks = await this.getTasksByProject(project_id, taskIncludes);
data.name = templateName;
data.team_id = team_id;
const q = `SELECT create_project_template($1);`;
const result = await db.query(q, [JSON.stringify(data)]);
const [obj] = result.rows;
const template_id = obj.create_project_template.id;
if (template_id) {
if (phases) await this.insertCustomTemplatePhases(phases, template_id);
if (status) await this.insertCustomTemplateStatus(status, template_id, team_id);
if (tasks) await this.insertCustomTemplateTasks(tasks, template_id, team_id);
}
return res.status(200).send(new ServerResponse(true, {}, "Project template created successfully."));
}
@HandleExceptions()
public static async setupAccount(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> {
const { template_id, team_name } = req.body;
let project_id: string | null = null;
await this.updateTeamName(team_name, req.user?.team_id as string, req.user?.id as string);
const data = await this.getTemplateData(template_id);
if (data) {
data.team_id = req.user?.team_id || null;
data.user_id = req.user?.id || null;
data.folder_id = null;
data.category_id = null;
data.status_id = await this.getDefaultProjectStatus();
data.project_created_log = LOG_DESCRIPTIONS.PROJECT_CREATED;
data.project_member_added_log = LOG_DESCRIPTIONS.PROJECT_MEMBER_ADDED;
data.health_id = await this.getDefaultProjectHealth();
data.working_days = 0;
data.man_days = 0;
data.hours_per_day = 8;
project_id = await this.importTemplate(data);
await this.insertTeamLabels(data.labels, req.user?.team_id);
await this.insertProjectPhases(data.phases, project_id as string);
await this.insertProjectTasks(data.tasks, data.team_id, project_id as string, data.user_id, IO.getSocketById(req.user?.socket_id as string));
await this.handleAccountSetup(project_id as string, data.user_id, team_name);
return res.status(200).send(new ServerResponse(true, { id: project_id }));
}
return res.status(200).send(new ServerResponse(true, { id: project_id }));
}
@HandleExceptions()
public static async importCustomTemplate(req: IWorkLenzRequest, res: IWorkLenzResponse): Promise<IWorkLenzResponse> {
const { template_id } = req.body;
let project_id: string | null = null;
const data = await this.getCustomTemplateData(template_id);
if (data) {
data.team_id = req.user?.team_id || null;
data.user_id = req.user?.id || null;
data.folder_id = null;
data.category_id = null;
data.status_id = await this.getDefaultProjectStatus();
data.project_created_log = LOG_DESCRIPTIONS.PROJECT_CREATED;
data.project_member_added_log = LOG_DESCRIPTIONS.PROJECT_MEMBER_ADDED;
data.working_days = 0;
data.man_days = 0;
data.hours_per_day = 8;
project_id = await this.importTemplate(data);
await this.deleteDefaultStatusForProject(project_id as string);
await this.insertTeamLabels(data.labels, req.user?.team_id);
await this.insertProjectPhases(data.phases, project_id as string);
await this.insertProjectStatuses(data.status, project_id as string, data.team_id );
await this.insertProjectTasksFromCustom(data.tasks, data.team_id, project_id as string, data.user_id, IO.getSocketById(req.user?.socket_id as string));
return res.status(200).send(new ServerResponse(true, { project_id }));
}
return res.status(200).send(new ServerResponse(true, { project_id }));
}
}