From a67303087ab496321eb5b9069ee0ae6d0f67a983 Mon Sep 17 00:00:00 2001
From: Roland Bernard <rolbernard@unibz.it>
Date: Sat, 1 May 2021 20:13:40 +0200
Subject: [PATCH] Added comment creation/updating API paths

---
 server/src/v1/comment.ts | 156 ++++++++++++++++++++++++++++++++++-
 server/src/v1/task.ts    | 174 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 329 insertions(+), 1 deletion(-)

diff --git a/server/src/v1/comment.ts b/server/src/v1/comment.ts
index 664dea1..f7739b9 100644
--- a/server/src/v1/comment.ts
+++ b/server/src/v1/comment.ts
@@ -1,13 +1,167 @@
 
 import express from 'express';
+import { v4 as uuid, validate } from 'uuid';
 
-import { requireVerification } from './auth';
+import database from '../database';
+import { requireVerification, Token } from './auth';
+import { isOfType } from '../util';
 
 const comment = express();
 
 comment.use(requireVerification);
 
+interface AddCommentBody {
+    task: string;
+    text: string;
+    token: Token;
+}
 
+comment.post('/', async (req, res) => {
+    if (isOfType<AddCommentBody>(req.body, [['task', 'string'], ['text', 'string']])) {
+        try {
+            const task_id = req.body.task;
+            if (validate(task_id)) {
+                const comment_id = uuid();
+                const task = await database('team_members')
+                    .innerJoin('team_projects', 'team_members.team_id', 'team_projects.team_id')
+                    .innerJoin('tasks', 'team_projects.project_id', 'tasks.project_id')
+                    .select({ id: 'tasks.id' })
+                    .where({
+                        'team_members.user_id': req.body.token.id,
+                        'tasks.id': task_id,
+                    });
+                if (task.length >= 1) {
+                    await database('comments').insert({
+                        id: comment_id,
+                        task_id: task_id,
+                        user_id: req.body.token.id,
+                        text: req.body.text,
+                        created: new Date(),
+                        edited: new Date(),
+                    });
+                    res.status(200).json({
+                        status: 'success',
+                        id: comment_id,
+                    });
+                } else {
+                    res.status(404).json({
+                        status: 'error',
+                        message: 'task not found',
+                    });
+                }
+            } else {
+                res.status(400).json({
+                    status: 'error',
+                    message: 'malformed uuid',
+                });
+            }
+        } catch (e) {
+            res.status(400).json({
+                status: 'error',
+                message: 'failed to create comment',
+            });
+        }
+    } else {
+        res.status(400).json({
+            status: 'error',
+            message: 'missing request fields',
+        });
+    }
+});
+
+interface UpdateCommentBody {
+    text?: string;
+    token: Token;
+}
+
+comment.put('/:uuid', async (req, res) => {
+    if (isOfType<UpdateCommentBody>(req.body, [])) {
+        try {
+            const comment_id = req.params.uuid;
+            if (validate(comment_id)) {
+                const comment = await database('comments')
+                        .update({
+                            text: req.body.text,
+                            edited: new Date(),
+                        })
+                        .where({
+                            'comments.user_id': req.body.token.id,
+                            'comments.id': comment_id,
+                        });
+                if (comment >= 1) {
+                    res.status(200).json({
+                        status: 'success',
+                    });
+                } else {
+                    res.status(404).json({
+                        status: 'error',
+                        message: 'comment not found',
+                    });
+                }
+            } else {
+                res.status(400).json({
+                    status: 'error',
+                    message: 'malformed uuid',
+                });
+            }
+        } catch (e) {
+            res.status(400).json({
+                status: 'error',
+                message: 'failed to update comment',
+            });
+        }
+    } else {
+        res.status(400).json({
+            status: 'error',
+            message: 'missing request fields',
+        });
+    }
+});
+
+comment.get('/:uuid', async (req, res) => {
+    try {
+        const comment_id = req.params.uuid;
+        if (validate(comment_id)) {
+            const comment = await database('team_members')
+                .innerJoin('team_projects', 'team_members.team_id', 'team_projects.team_id')
+                .innerJoin('tasks', 'team_projects.project_id', 'tasks.project_id')
+                .innerJoin('comments', 'tasks.id', 'comments.task_id')
+                .select({
+                    id: 'comments.id',
+                    task: 'comments.task_id',
+                    user: 'comments.user_id',
+                    text: 'comments.text',
+                    created: 'comments.created',
+                    edited: 'comments.edited',
+                })
+                .where({
+                    'team_members.user_id': req.body.token.id,
+                    'comments.id': comment_id,
+                });
+            if (comment.length >= 1) {
+                res.status(200).json({
+                    status: 'success',
+                    comment: comment[0],
+                });
+            } else {
+                res.status(404).json({
+                    status: 'error',
+                    message: 'comment not found',
+                });
+            }
+        } else {
+            res.status(400).json({
+                status: 'error',
+                message: 'malformed uuid',
+            });
+        }
+    } catch (e) {
+        res.status(400).json({
+            status: 'error',
+            message: 'failed to update comment',
+        });
+    }
+});
 
 export default comment;
 
diff --git a/server/src/v1/task.ts b/server/src/v1/task.ts
index 4b13037..c849bbd 100644
--- a/server/src/v1/task.ts
+++ b/server/src/v1/task.ts
@@ -33,6 +33,7 @@ export interface Task {
 
 export function generateFromFlatResult(results: any[]): Task[] {
     const grouped_tasks: Record<string, Task> = { };
+    const to_remove: Array<string> = [];
     for (const row of results) {
         if (!grouped_tasks[row.id]) {
             grouped_tasks[row.id] = {
@@ -75,6 +76,12 @@ export function generateFromFlatResult(results: any[]): Task[] {
                 grouped_tasks[row.id].dependentcies.push(row.dependentcy);
             }
         }
+        if (row.dependentcy_status && row.dependentcy_status !== 'closed') {
+            to_remove.push(row.id);
+        }
+    }
+    for (const remove of to_remove) {
+        delete grouped_tasks[remove];
     }
     return Object.values(grouped_tasks);
 }
@@ -83,6 +90,173 @@ const task = express();
 
 task.use(requireVerification);
 
+task.get('/', async (req, res) => {
+    try {
+        const tasks = await database('team_members')
+            .innerJoin('team_projects', 'team_members.team_id', 'team_projects.team_id')
+            .innerJoin('tasks', 'team_projects.project_id', 'tasks.project_id')
+            .leftJoin('task_requirements', 'tasks.id', 'task_requirements.task_id')
+            .leftJoin('task_dependencies', 'tasks.id', 'task_dependencies.task_id')
+            .leftJoin('task_assignees', 'tasks.id', 'task_assignees.task_id')
+            .select({
+                id: 'tasks.id',
+                project: 'tasks.project_id',
+                name: 'tasks.name',
+                text: 'tasks.text',
+                icon: 'tasks.icon',
+                status: 'tasks.status',
+                priority: 'tasks.priority',
+                created: 'tasks.created',
+                edited: 'tasks.edited',
+                requirement_role: 'task_requirements.role_id', 
+                requirement_time: 'task_requirements.time', 
+                assigned_user: 'task_assignees.user_id', 
+                assigned_time: 'task_assignees.time', 
+                dependentcy: 'task_dependencies.requires_id', 
+            })
+            .where({
+                'team_members.user_id': req.body.token.id,
+            });
+        res.status(200).json({
+            status: 'success',
+            tasks: generateFromFlatResult(tasks),
+        });
+    } catch (e) {
+        res.status(400).json({
+            status: 'error',
+            message: 'failed get tasks',
+        });
+    }
+});
+
+task.get('/open', async (req, res) => {
+    try {
+        const tasks = await database('team_members')
+            .innerJoin('team_projects', 'team_members.team_id', 'team_projects.team_id')
+            .innerJoin('tasks', 'team_projects.project_id', 'tasks.project_id')
+            .leftJoin('task_requirements', 'tasks.id', 'task_requirements.task_id')
+            .leftJoin('task_dependencies', 'tasks.id', 'task_dependencies.task_id')
+            .leftJoin('task_assignees', 'tasks.id', 'task_assignees.task_id')
+            .select({
+                id: 'tasks.id',
+                project: 'tasks.project_id',
+                name: 'tasks.name',
+                text: 'tasks.text',
+                icon: 'tasks.icon',
+                status: 'tasks.status',
+                priority: 'tasks.priority',
+                created: 'tasks.created',
+                edited: 'tasks.edited',
+                requirement_role: 'task_requirements.role_id', 
+                requirement_time: 'task_requirements.time', 
+                assigned_user: 'task_assignees.user_id', 
+                assigned_time: 'task_assignees.time', 
+                dependentcy: 'task_dependencies.requires_id', 
+            })
+            .where({
+                'team_members.user_id': req.body.token.id,
+                'tasks.status': 'open',
+            });
+        res.status(200).json({
+            status: 'success',
+            tasks: generateFromFlatResult(tasks),
+        });
+    } catch (e) {
+        res.status(400).json({
+            status: 'error',
+            message: 'failed get tasks',
+        });
+    }
+});
+
+task.get('/possible', async (req, res) => {
+    try {
+        const tasks = await database('team_members')
+            .innerJoin('team_projects', 'team_members.team_id', 'team_projects.team_id')
+            .innerJoin('tasks', 'team_projects.project_id', 'tasks.project_id')
+            .leftJoin('task_requirements', 'tasks.id', 'task_requirements.task_id')
+            .leftJoin('task_dependencies', 'tasks.id', 'task_dependencies.task_id')
+            .leftJoin({ 'require': 'tasks' }, 'task_dependencies.requires_id', 'require.id')
+            .leftJoin('task_assignees', 'tasks.id', 'task_assignees.task_id')
+            .select({
+                id: 'tasks.id',
+                project: 'tasks.project_id',
+                name: 'tasks.name',
+                text: 'tasks.text',
+                icon: 'tasks.icon',
+                status: 'tasks.status',
+                priority: 'tasks.priority',
+                created: 'tasks.created',
+                edited: 'tasks.edited',
+                requirement_role: 'task_requirements.role_id', 
+                requirement_time: 'task_requirements.time', 
+                assigned_user: 'task_assignees.user_id', 
+                assigned_time: 'task_assignees.time', 
+                dependentcy: 'task_dependencies.requires_id', 
+                dependentcy_status: 'require.status',
+            })
+            .where({
+                'team_members.user_id': req.body.token.id,
+                'tasks.status': 'open',
+            });
+        res.status(200).json({
+            status: 'success',
+            tasks: generateFromFlatResult(tasks),
+        });
+    } catch (e) {
+        console.log(e);
+        res.status(400).json({
+            status: 'error',
+            message: 'failed get tasks',
+        });
+    }
+});
+
+task.get('/:uuid/comments', async (req, res) => {
+    try {
+        const id = req.params.uuid;
+        if (validate(id)) {
+            const comments = await database('team_members')
+                .innerJoin('team_projects', 'team_members.team_id', 'team_projects.team_id')
+                .innerJoin('tasks', 'team_projects.project_id', 'tasks.project_id')
+                .innerJoin('comments', 'tasks.id', 'comments.task_id')
+                .select({
+                    id: 'comments.id',
+                    task: 'comments.task_id',
+                    user: 'comments.user_id',
+                    text: 'comments.text',
+                    created: 'comments.created',
+                    edited: 'comments.edited',
+                })
+                .where({
+                    'team_members.user_id': req.body.token.id,
+                    'tasks.id': id,
+                });
+            if (task.length >= 1) {
+                res.status(200).json({
+                    status: 'success',
+                    comments: comments,
+                });
+            } else {
+                res.status(404).json({
+                    status: 'error',
+                    message: 'task not found',
+                });
+            }
+        } else {
+            res.status(400).json({
+                status: 'error',
+                message: 'malformed uuid',
+            });
+        }
+    } catch (e) {
+        res.status(400).json({
+            status: 'error',
+            message: 'failed get comments',
+        });
+    }
+});
+
 task.get('/:uuid', async (req, res) => {
     try {
         const id = req.params.uuid;
-- 
GitLab