Initial commit: Angular frontend and Expressjs backend
This commit is contained in:
0
worklenz-backend/src/models/.gitkeep
Normal file
0
worklenz-backend/src/models/.gitkeep
Normal file
17
worklenz-backend/src/models/auth-response.ts
Normal file
17
worklenz-backend/src/models/auth-response.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import {IPassportSession} from "../interfaces/passport-session";
|
||||
|
||||
export class AuthResponse {
|
||||
private authenticated = false;
|
||||
private user: IPassportSession | null = null;
|
||||
private title: string | null = null;
|
||||
private auth_error: string | null = null;
|
||||
private message: string | null = null;
|
||||
|
||||
constructor(title: string | null, authenticated: boolean, user: IPassportSession | null, auth_error: string | null, message: string | null) {
|
||||
this.title = title;
|
||||
this.authenticated = !!authenticated;
|
||||
this.user = user;
|
||||
this.auth_error = auth_error;
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
166
worklenz-backend/src/models/reporting-export.ts
Normal file
166
worklenz-backend/src/models/reporting-export.ts
Normal file
@@ -0,0 +1,166 @@
|
||||
import moment from "moment";
|
||||
import db from "../config/db";
|
||||
import ReportingOverviewBase from "../controllers/reporting/overview/reporting-overview-base";
|
||||
import { formatDuration, getColor, int } from "../shared/utils";
|
||||
|
||||
export class ReportingExportModel extends ReportingOverviewBase {
|
||||
|
||||
|
||||
public static async getMembersByTeam(teamId: string | null) {
|
||||
const q = `
|
||||
SELECT team_member_id AS id,
|
||||
name,
|
||||
email,
|
||||
(SELECT COUNT(*)
|
||||
FROM project_members
|
||||
WHERE project_members.team_member_id = team_member_info_view.team_member_id) AS projects,
|
||||
(SELECT COUNT(*)
|
||||
FROM tasks_assignees
|
||||
WHERE tasks_assignees.team_member_id = team_member_info_view.team_member_id) AS tasks,
|
||||
(SELECT COUNT(*)
|
||||
FROM tasks_assignees
|
||||
WHERE tasks_assignees.team_member_id = team_member_info_view.team_member_id
|
||||
AND is_overdue(task_id) IS TRUE) AS overdue,
|
||||
(SELECT COUNT(*)
|
||||
FROM tasks_assignees
|
||||
WHERE tasks_assignees.team_member_id = team_member_info_view.team_member_id
|
||||
AND task_id IN (SELECT id
|
||||
FROM tasks
|
||||
WHERE is_completed(tasks.status_id, tasks.project_id))) AS completed,
|
||||
(SELECT COUNT(*)
|
||||
FROM tasks_assignees
|
||||
WHERE tasks_assignees.team_member_id = team_member_info_view.team_member_id
|
||||
AND task_id IN (SELECT id
|
||||
FROM tasks
|
||||
WHERE is_doing(tasks.status_id, tasks.project_id))) AS ongoing
|
||||
FROM team_member_info_view
|
||||
WHERE team_id = $1
|
||||
ORDER BY name;
|
||||
`;
|
||||
|
||||
const result = await db.query(q, [teamId]);
|
||||
return result.rows;
|
||||
}
|
||||
|
||||
|
||||
public static async getProjectMembers(projectId: string) {
|
||||
const q = `
|
||||
SELECT pm.id,
|
||||
pm.team_member_id,
|
||||
(SELECT name FROM team_member_info_view WHERE team_member_id = pm.team_member_id) AS name,
|
||||
COUNT(ta.task_id) AS tasks_count,
|
||||
COUNT(CASE WHEN is_completed(t.status_id, t.project_id) IS TRUE THEN 1 END) AS completed,
|
||||
COUNT(CASE WHEN is_completed(t.status_id, t.project_id) IS FALSE THEN 1 END) AS incompleted,
|
||||
COUNT(CASE WHEN is_overdue(t.id) THEN 1 END) AS overdue,
|
||||
(SELECT SUM(time_spent)
|
||||
FROM task_work_log twl
|
||||
WHERE user_id =
|
||||
(SELECT user_id FROM team_member_info_view WHERE team_member_id = pm.team_member_id)
|
||||
AND twl.task_id IN (SELECT id FROM tasks WHERE project_id = pm.project_id)) AS time_logged
|
||||
FROM project_members pm
|
||||
LEFT JOIN tasks_assignees ta
|
||||
ON pm.id = ta.project_member_id AND ta.team_member_id = pm.team_member_id
|
||||
LEFT JOIN tasks t ON ta.task_id = t.id
|
||||
WHERE pm.project_id = $1
|
||||
GROUP BY pm.id
|
||||
ORDER BY name
|
||||
`;
|
||||
const result = await db.query(q, [projectId]);
|
||||
|
||||
const total = await this.getTotalTasksCount(projectId);
|
||||
|
||||
for (const member of result.rows) {
|
||||
member.tasks_count = int(member.tasks_count);
|
||||
member.completed = int(member.completed);
|
||||
member.incompleted = int(member.incompleted);
|
||||
member.overdue = int(member.overdue);
|
||||
member.contribution = this.getPercentage(member.tasks_count, total);
|
||||
member.progress = this.getPercentage(member.completed, member.tasks_count);
|
||||
member.time_logged = formatDuration(moment.duration(int(member.time_logged) || "0", "seconds"));
|
||||
}
|
||||
|
||||
return result.rows;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static async getMemberTasks(teamMemberId: string, projectId: string | null, onlySingleMember: string, key: string, dateRange: string[] | [], includeArchived: boolean, userId: string) {
|
||||
|
||||
const projectFilter = projectId ? ` AND t.project_id = $2` : "";
|
||||
|
||||
let activityLogDurationFilterClause = ``;
|
||||
let archivedClause = ``;
|
||||
if (onlySingleMember === "true") {
|
||||
activityLogDurationFilterClause = this.activityLogDurationFilter(key, dateRange);
|
||||
archivedClause = includeArchived ? "" : `AND t.project_id NOT IN (SELECT project_id FROM archived_projects WHERE project_id = t.project_id AND archived_projects.user_id = '${userId}')`;
|
||||
}
|
||||
|
||||
|
||||
const q = `
|
||||
WITH work_log AS (SELECT task_id, SUM(time_spent) AS total_time_spent
|
||||
FROM task_work_log
|
||||
GROUP BY task_id)
|
||||
SELECT t.id,
|
||||
t.name,
|
||||
t.project_id,
|
||||
t.parent_task_id,
|
||||
t.parent_task_id IS NOT NULL AS is_sub_task,
|
||||
(SELECT name FROM projects WHERE id = t.project_id) AS project_name,
|
||||
(SELECT name
|
||||
FROM teams
|
||||
WHERE id = (SELECT team_id FROM projects WHERE projects.id = t.project_id)) AS team_name,
|
||||
(CASE
|
||||
WHEN (CURRENT_DATE::DATE > end_date::DATE AND
|
||||
status_id IN (SELECT id
|
||||
FROM task_statuses
|
||||
WHERE project_id = t.project_id
|
||||
AND category_id IN
|
||||
(SELECT id FROM sys_task_status_categories WHERE is_done IS FALSE)))
|
||||
THEN CURRENT_DATE::DATE - end_date::DATE
|
||||
ELSE 0 END) AS days_overdue,
|
||||
tp.name AS priority_name,
|
||||
tp.color_code AS priority_color,
|
||||
ts.name AS status_name,
|
||||
sc.color_code AS status_color,
|
||||
t.end_date,
|
||||
t.completed_at,
|
||||
|
||||
(total_minutes * 60) AS total_minutes,
|
||||
(work_log.total_time_spent - (total_minutes * 60)) AS overlogged_time,
|
||||
|
||||
(SELECT SUM(time_spent)
|
||||
FROM task_work_log twl
|
||||
WHERE team_member_id = ta.team_member_id
|
||||
AND twl.task_id = t.id
|
||||
AND twl.task_id IN
|
||||
(SELECT id FROM tasks WHERE tasks.project_id = t.project_id)) AS time_logged
|
||||
FROM tasks t
|
||||
JOIN tasks_assignees ta ON t.id = ta.task_id
|
||||
LEFT JOIN work_log ON work_log.task_id = t.id
|
||||
LEFT JOIN task_priorities tp ON t.priority_id = tp.id
|
||||
LEFT JOIN task_statuses ts ON t.status_id = ts.id
|
||||
LEFT JOIN sys_task_status_categories sc ON ts.category_id = sc.id
|
||||
WHERE ta.team_member_id = $1 ${projectFilter} ${archivedClause}
|
||||
ORDER BY t.end_date DESC;`;
|
||||
|
||||
const params = projectId ? [teamMemberId, projectId] : [teamMemberId];
|
||||
const result = await db.query(q, params);
|
||||
|
||||
for (const project of result.rows) {
|
||||
project.project_color = getColor(project.project_name);
|
||||
// estimated time
|
||||
project.estimated_string = formatDuration(moment.duration(~~(project.total_minutes), "seconds"));
|
||||
// logged time
|
||||
project.time_spent_string = formatDuration(moment.duration(~~(project.time_logged), "seconds"));
|
||||
// overlogged_time
|
||||
project.overlogged_time = formatDuration(moment.duration(~~(project.overlogged_time), "seconds"));
|
||||
|
||||
project.completed_date = project.completed_at ? project.completed_at : null;
|
||||
}
|
||||
|
||||
return result.rows;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
22
worklenz-backend/src/models/server-response.ts
Normal file
22
worklenz-backend/src/models/server-response.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
export class ServerResponse<T> {
|
||||
public done: boolean;
|
||||
public body: T | null;
|
||||
public title: string | null = null;
|
||||
public message: string | null;
|
||||
|
||||
constructor(done: boolean, body: T, message: string | null = null) {
|
||||
this.done = !!done;
|
||||
this.body = body === null || body === undefined ? null : body;
|
||||
this.message = message?.toString().trim() ?? null;
|
||||
}
|
||||
|
||||
public withTitle(title: string) {
|
||||
this.title = title;
|
||||
return this;
|
||||
}
|
||||
|
||||
public setMessage(message: string) {
|
||||
this.message = message;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user