Newer
Older
import express from 'express';
import { v4 as uuid, validate } from 'uuid';
import database from '../database';
import { isOfType } from '../util';
import { requireVerification, Token } from './auth';
import { generateFromFlatResult } from './task';
const project = express();
project.use(requireVerification);
project.get('/', async (req, res) => {
try {
const projects = await database('team_members')
.innerJoin('team_projects', 'team_members.team_id', 'team_projects.team_id')
.innerJoin('projects', 'team_projects.project_id', 'projects.id')
.select({
id: 'projects.id',
name: 'projects.name',
text: 'projects.text',
color: 'projects.color',
status: 'projects.status',
deadline: 'projects.deadline',
'team_members.user_id': req.body.token.id,
})
.groupBy('projects.id');
res.status(200).json({
status: 'success',
projects: projects,
});
} catch (e) {
res.status(400).json({
status: 'error',
message: 'failed to get project',
});
}
});
project.get('/:uuid', async (req, res) => {
try {
const id = req.params.uuid;
if (validate(id)) {
const projects = await database('team_members')
.innerJoin('team_projects', 'team_members.team_id', 'team_projects.team_id')
.innerJoin('projects', 'team_projects.project_id', 'projects.id')
.innerJoin({ 'tms': 'team_projects' }, 'projects.id', 'tms.project_id')
.select({
id: 'projects.id',
name: 'projects.name',
text: 'projects.text',
color: 'projects.color',
status: 'projects.status',
deadline: 'projects.deadline',
})
.where({
'team_members.user_id': req.body.token.id,
'projects.id': id,
})
.groupBy('tms.team_id');
if (projects.length >= 1) {
res.status(200).json({
status: 'success',
project: {
id: projects[0].id,
name: projects[0].name,
status: projects[0].status,
color: projects[0].color,
deadline: projects[0].deadline,
teams: projects.map(task => task.team_id),
}
});
} else {
res.status(404).json({
status: 'error',
message: 'project not found',
});
}
} else {
res.status(400).json({
status: 'error',
message: 'malformed uuid',
});
}
} catch (e) {
res.status(400).json({
status: 'error',
message: 'failed to get project',
});
}
});
project.get('/:uuid/tasks', async (req, res) => {
try {
const id = req.params.uuid;
if (validate(id)) {
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',
assigned_finished: 'task_assignees.finished',
dependentcy: 'task_dependencies.requires_id',
})
.where({
'team_members.user_id': req.body.token.id,
'team_projects.project_id': id,
});
res.status(200).json({
status: 'success',
tasks: generateFromFlatResult(tasks),
});
} else {
res.status(400).json({
status: 'error',
message: 'malformed uuid',
});
}
} catch (e) {
res.status(400).json({
status: 'error',
message: 'failed to get tasks',
});
}
});
project.get('/:uuid/assigned', async (req, res) => {
try {
const id = req.params.uuid;
if (validate(id)) {
const users = 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('task_assignees', 'tasks.id', 'task_assignees.task_id')
.innerJoin('users', 'task_assignees.user_id', 'users.id')
.select({
id: 'users.id',
username: 'users.user_name',
email: 'users.email',
realname: 'users.real_name',
})
.sum({ time: 'task_assignees.time' })
.where({
'team_members.user_id': req.body.token.id,
'team_projects.project_id': id,
})
.groupBy('users.id');
res.status(200).json({
status: 'success',
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
});
} else {
res.status(400).json({
status: 'error',
message: 'malformed uuid',
});
}
} catch (e) {
res.status(400).json({
status: 'error',
message: 'failed to get assignees',
});
}
});
project.get('/:uuid/work', async (req, res) => {
try {
const id = req.params.uuid;
if (validate(id)) {
const since = (req.query.since ?? 0) as number;
const work = await database({ ut: 'team_members' })
.innerJoin('team_projects', 'ut.team_id', 'team_projects.team_id')
.innerJoin('tasks', 'team_projects.project_id', 'tasks.project_id')
.innerJoin('workhours', 'tasks.id', 'workhours.task_id')
.select({
id: 'workhours.id',
task: 'workhours.task_id',
user: 'workhours.user_id',
started: 'workhours.started',
finished: 'workhours.finished',
})
.where({
'ut.user_id': req.body.token.id,
'team_projects.project_id': id,
})
.andWhere('workhours.started', '>=', since)
.groupBy('workhours.id');
res.status(200).json({
status: 'success',
work: work,
});
} else {
res.status(400).json({
status: 'error',
message: 'malformed uuid',
});
}
} catch (e) {
res.status(400).json({
status: 'error',
message: 'failed get work',
});
}
});
interface AddProjectBody {
teams: Array<string>;
name: string;
color: string;
token: Token;
}
project.post('/', async (req, res) => {
if (isOfType<AddProjectBody>(req.body, [['teams', 'object'], ['name', 'string'], ['text', 'string'], ['color', 'string']])) {
try {
const team_ids = req.body.teams;
for (const team_id of team_ids) {
if (!validate(team_id)) {
res.status(400).json({
status: 'error',
message: 'malformed uuid',
});
return;
}
}
const color = req.body.color;
if (!color.match(/^#[0-9a-fA-F]{6}$/)) {
res.status(400).json({
status: 'error',
message: 'malformed color',
} else {
const project_id = uuid();
const team = await database('team_members')
.select({ id: 'team_members.team_id' })
.where({
'team_members.user_id': req.body.token.id,
})
.whereIn('team_members.team_id', team_ids);
if (team.length === team_ids.length) {
await database.transaction(async transaction => {
await transaction('projects').insert({
id: project_id,
name: req.body.name,
text: req.body.text,
color: req.body.color,
deadline: req.body.deadline ? new Date(req.body.deadline) : null,
await transaction('team_projects').insert(
team_ids.map(team_id => ({
project_id: project_id,
team_id: team_id,
}))
);
});
res.status(200).json({
status: 'success',
id: project_id,
});
} else {
res.status(404).json({
status: 'error',
message: 'team not found',
});
}
}
} catch (e) {
res.status(400).json({
status: 'error',
message: 'failed to create project',
});
}
} else {
res.status(400).json({
status: 'error',
message: 'missing request fields',
});
}
});
interface UpdateProjectBody {
remove_teams?: Array<string>;
add_teams?: Array<string>;
name?: string;
color?: string;
token: Token;
}
project.put('/:uuid', async (req, res) => {
if (isOfType<UpdateProjectBody>(req.body, [])) {
try {
const id = req.params.uuid;
if (validate(id)) {
const add_team_ids = req.body.add_teams ?? [];
const remove_team_ids = req.body.remove_teams ?? [];
for (const team_id of add_team_ids.concat(remove_team_ids)) {
if (!validate(team_id)) {
res.status(400).json({
status: 'error',
message: 'malformed uuid',
});
return;
}
}
const projects = await database('team_members')
.innerJoin('team_projects', 'team_members.team_id', 'team_projects.team_id')
.innerJoin('projects', 'team_projects.project_id', 'projects.id')
.select({ id: 'projects.id' })
'team_members.user_id': req.body.token.id,
'projects.id': id,
});
if (projects.length >= 1) {
await database.transaction(async transaction => {
if (req.body.name || req.body.text || req.body.color || req.body.status || req.body.deadline) {
await transaction('projects')
.update({
name: req.body.name,
text: req.body.text,
color: req.body.color,
status: req.body.status,
deadline: req.body.deadline,
}).where({
id: id,
});
}
if (remove_team_ids.length !== 0) {
await transaction('team_projects')
.delete()
.where({
'project_id': id,
})
.whereIn('team_id', remove_team_ids);
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
}
if (add_team_ids.length !== 0) {
await transaction('team_projects').insert(
add_team_ids.map(team_id => ({
project_id: id,
team_id: team_id,
}))
);
}
});
res.status(200).json({
status: 'success',
});
} else {
res.status(400).json({
status: 'error',
message: 'project not found',
});
}
} else {
res.status(400).json({
status: 'error',
message: 'malformed uuid',
});
}
} catch (e) {
res.status(400).json({
status: 'error',
message: 'failed to create project',
});
}
} else {
res.status(400).json({
status: 'error',
message: 'missing request fields',
});
}
});
export default project;