Skip to content
Snippets Groups Projects
team.ts 19 KiB
Newer Older
import { v4 as uuid, validate } from 'uuid';
import database from '../database';
import { requireVerification, Token } from './auth';
import { isOfType } from '../util';

const team = express();

team.use(requireVerification);

interface TeamCreateBody {
    name: string;
    token: Token;
}
team.post('/', async (req, res) => {
    if (isOfType<TeamCreateBody>(req.body, [['name', 'string']])) {
        const team_id = uuid();
        const team_name = req.body.name.trim();
        const role_id = uuid();
        if (team_name.length >= 4) {
            try {
                await database.transaction(async transaction => {
                    await transaction('teams').insert({
                        id: team_id,
                        name: team_name,
                    });
                    await transaction('roles').insert({
                        id: role_id,
                        team_id: team_id,
                        name: 'Default',
                    });
                    await transaction('team_members').insert({
                        user_id: req.body.token.id,
                        team_id: team_id,
                        role_id: role_id,
                    });
                });
                res.status(200).json({
                    status: 'success',
                    id: team_id,
                });
            } catch (e) {
                res.status(400).json({
                    status: 'error',
                    message: 'failed create team',
                });
            }
        } else {
            res.status(400).json({
                status: 'error',
                message: 'team names must be four letters or longer',
            });
        }
    } else {
        res.status(400).json({
            status: 'error',
            message: 'missing request fields',
        });
    }
});

team.get('/', async (req, res) => {
    try {
        const teams = await database('team_members')
            .innerJoin('teams', 'team_members.team_id', 'teams.id')
            .select({
                id: 'teams.id',
                name: 'teams.name',
                role: 'team_members.role_id'
                'team_members.user_id': req.body.token.id
            });
        res.status(200).json({
            status: 'success',
            teams: teams,
        });
    } catch (e) {
        res.status(400).json({
            status: 'error',
            message: 'failed to get teams',
        });
    }
});

team.get('/:uuid/', async (req, res) => {
    try {
        const id = req.params.uuid;
        if (validate(id)) {
            const team = await database('teams')
                .leftJoin('team_members', 'teams.id', 'team_members.team_id')
                .select({
                    id: 'teams.id',
                    name: 'teams.name',
                    role: 'team_members.role_id',
                    'team_members.user_id': req.body.token.id,
                })
                .orWhere({
                    'team_members.user_id': null,
                    'teams.id': id,
                })
            if (team.length === 1) {
                res.status(200).json({
                    status: 'success',
                    team: team[0],
                });
            } else {
                res.status(404).json({
                    status: 'error',
                    message: 'team not found',
                });
            }
        } else {
            res.status(400).json({
                status: 'error',
                message: 'malformed uuid',
            });
        }
    } catch (e) {
        res.status(400).json({
            status: 'error',
            message: 'failed get team',
        });
    }
});

team.get('/:uuid/members', async (req, res) => {
    try {
        const id = req.params.uuid;
        if (validate(id)) {
            const members = await database({ ut: 'team_members'})
                .innerJoin({ tm: 'team_members'}, 'ut.team_id', 'tm.team_id')
                .innerJoin({ members: 'users'}, 'tm.user_id', 'members.id')
                .innerJoin('roles', 'tm.role_id', 'roles.id')
                .select({
                    id: 'members.id',
                    name: 'members.user_name',
                    email: 'members.email',
                    realname: 'members.real_name',
                    role_id: 'roles.id',
                    role_name: 'roles.name',
                    'ut.user_id': req.body.token.id,
                    'ut.team_id': id,
                });
            if (members.length >= 1) {
                res.status(200).json({
                    status: 'success',
                    members: members.map(member => ({
                        id: member.id,
                        name: member.name,
                        email: member.email,
                        realname: member.realname,
                        role: {
                            id: member.role_id,
                            name: member.role_name,
                        },
                    })),
                res.status(404).json({
                    status: 'error',
                    message: 'team not found',
                });
            }
        } else {
            res.status(400).json({
                status: 'error',
                message: 'malformed uuid',
            });
        }
    } catch (e) {
        res.status(400).json({
            status: 'error',
team.delete('/:teamid/members/:userid', async (req, res) => {
    try {
        const team_id = req.params.teamid;
        const user_id = req.params.userid;
        if (validate(team_id) && validate(user_id)) {
            const team = await database('team_members')
                .select({ id: 'team_members.team_id' })
                .where({
                    'team_members.user_id': req.body.token.id,
                    'team_members.team_id': team_id,
                });
            if (team.length === 1) {
                const deleted = await database('team_members')
                    .delete()
                    .where({
                        'team_members.user_id': user_id,
                        'team_members.team_id': team_id,
                    });
                if (deleted >= 1) {
                    res.status(200).json({
                        status: 'success',
                    });
                } else {
                    res.status(404).json({
                        status: 'error',
                        message: 'role not found',
                    });
                }
            } else {
                res.status(404).json({
                    status: 'error',
                    message: 'team not found',
                });
            }
        } else {
            res.status(400).json({
                status: 'error',
                message: 'malformed uuid',
            });
        }
    } catch (e) {
        res.status(400).json({
            status: 'error',
            message: 'failed remove members',
        });
    }
});


team.get('/:uuid/roles', async (req, res) => {
    try {
        const id = req.params.uuid;
        if (validate(id)) {
            const roles = await database('team_members')
                .innerJoin('roles', 'team_members.team_id', 'roles.team_id')
                .select({
                    id: 'roles.id',
                    name: 'roles.name',
                })
                .where({
                    'team_members.user_id': req.body.token.id,
                    'team_members.team_id': id,
                });
            if (roles.length >= 1) {
                res.status(200).json({
                    status: 'success',
                    roles: roles,
                });
            } else {
                // All teams have at least one role
                res.status(404).json({
                    status: 'error',
                    message: 'team not found',
                });
            }
        } else {
            res.status(400).json({
                status: 'error',
                message: 'malformed uuid',
            });
        }
    } catch (e) {
        res.status(400).json({
            status: 'error',
            message: 'failed get roles',
        });
    }
});

team.get('/:uuid/projects', 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')
                .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,
                    'team_members.team_id': id,
                });
            res.status(200).json({
                status: 'success',
                projects: projects,
            });
        } else {
            res.status(400).json({
                status: 'error',
                message: 'malformed uuid',
            });
        }
    } catch (e) {
        res.status(400).json({
            status: 'error',
            message: 'failed get projects',
        });
    }
});

team.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_members', 'ut.team_id', 'team_members.team_id')
                .innerJoin('workhours', 'team_members.user_id', 'workhours.user_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,
                    'ut.team_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 AddRoleBody {
    name: string;
    token: Token;
}

team.post('/:uuid/roles', async (req, res) => {
    if (isOfType<AddRoleBody>(req.body, [['name', 'string']])) {
        try {
            const team_id = req.params.uuid;
            if (validate(team_id)) {
                const team = await database('team_members')
                    .select({ id: 'team_members.team_id' })
                    .where({
                        'team_members.user_id': req.body.token.id,
                        'team_members.team_id': team_id,
                    });
                if (team.length === 1) {
                    const role_id = uuid();
                    const role_name = req.body.name;
                    await database('roles').insert({
                        id: role_id,
                        name: role_name,
                        team_id: team_id,
                    });
                    res.status(200).json({
                        status: 'success',
                        role: {
                            id: role_id,
                            name: role_name,
                        },
                    });
                } else {
                    res.status(404).json({
                        status: 'error',
                        message: 'team not found',
                    });
                }
            } else {
                res.status(400).json({
                    status: 'error',
                    message: 'malformed uuid',
                });
            }
        } catch (e) {
            res.status(400).json({
                status: 'error',
                message: 'failed to add role',
            });
        }
    } else {
        res.status(400).json({
            status: 'error',
            message: 'missing request fields',
        });
    }
});

team.delete('/:teamid/roles/:roleid', async (req, res) => {
    try {
        const team_id = req.params.teamid;
        const role_id = req.params.roleid;
        if (validate(team_id) && validate(role_id)) {
            const team = await database('team_members')
                .select({ id: 'team_members.team_id' })
                .where({
                    'team_members.user_id': req.body.token.id,
                    'team_members.team_id': team_id,
                });
            if (team.length === 1) {
                const deleted = await database('roles')
                    .delete()
                    .where({
                        id: role_id,
                        team_id: team_id,
                    });
                if (deleted >= 1) {
                    res.status(200).json({
                        status: 'success',
                    });
                } else {
                    res.status(404).json({
                        status: 'error',
                        message: 'role not found',
                    });
                }
            } else {
                res.status(404).json({
                    status: 'error',
                    message: 'team not found',
                });
            }
        } else {
            res.status(400).json({
                status: 'error',
                message: 'malformed uuid',
            });
        }
    } catch (e) {
        res.status(400).json({
            status: 'error',
            message: 'failed to delete role',
        });
    }
});

interface AddMemberBody {
    user: string;
    role: string;
    token: Token;
}

team.post('/:uuid/members', async (req, res) => {
    if (isOfType<AddMemberBody>(req.body, [['user', 'string'], ['role', 'string']])) {
        try {
            const team_id = req.params.uuid;
            const user_id = req.body.user;
            const role_id = req.body.role;
            if (validate(team_id) && validate(user_id) && validate(role_id)) {
                const role = await database('team_members')
                    .innerJoin('roles', 'team_members.team_id', 'roles.team_id')
                    .select({ id: 'roles.id' })
                    .where({
                        'team_members.user_id': req.body.token.id,
                        'team_members.team_id': team_id,
                        'roles.id': role_id,
                    });
                if (role.length === 1) {
                    await database('team_members').insert({
                        user_id: user_id,
                        team_id: team_id,
                        role_id: role_id,
                    });
                    res.status(200).json({
                        status: 'success',
                    });
                } else {
                    res.status(404).json({
                        status: 'error',
                        message: 'role not found',
                    });
                }
            } else {
                res.status(400).json({
                    status: 'error',
                    message: 'malformed uuid',
                });
            }
        } catch (e) {
            res.status(400).json({
                status: 'error',
                message: 'failed to add member',
            });
        }
    } else {
        res.status(400).json({
            status: 'error',
            message: 'missing request fields',
        });
    }
});

interface UpdateMemberBody {
    user: string;
    role: string;
    token: Token;
}

team.put('/:uuid/members', async (req, res) => {
    if (isOfType<UpdateMemberBody>(req.body, [['user', 'string'], ['role', 'string']])) {
        try {
            const team_id = req.params.uuid;
            const user_id = req.body.user;
            const role_id = req.body.role;
            if (validate(team_id) && validate(user_id) && validate(role_id)) {
                const role = await database('team_members')
                    .innerJoin('roles', 'team_members.team_id', 'roles.team_id')
                    .select({ id: 'roles.id' })
                    .where({
                        'team_members.user_id': req.body.token.id,
                        'team_members.team_id': team_id,
                        'roles.id': role_id,
                    });
                if (role.length === 1) {
                    await database('team_members')
                    .update({ role_id: role_id })
                    .where({
                        user_id: user_id,
                        team_id: team_id,
                    });
                    res.status(200).json({
                        status: 'success',
                    });
                } else {
                    res.status(404).json({
                        status: 'error',
                        message: 'role not found',
                    });
                }
            } else {
                res.status(400).json({
                    status: 'error',
                    message: 'malformed uuid',
                });
            }
        } catch (e) {
            res.status(400).json({
                status: 'error',
                message: 'failed to update member',
            });
        }
    } else {
        res.status(400).json({
            status: 'error',
            message: 'missing request fields',
        });
    }
});

team.delete('/:uuid/', async (req, res) => {
    try {
        const id = req.params.uuid;
        if (validate(id)) {
            const deleted = await database('team_members')
                .delete()
                .where({
                    'team_members.user_id': req.body.token.id,
                    'team_members.team_id': id,
                });
            if (deleted >= 1) {
                res.status(200).json({
                    status: 'success',
                });
            } else {
                res.status(404).json({
                    status: 'error',
                    message: 'team not found',
                });
            }
        } else {
            res.status(400).json({
                status: 'error',
                message: 'malformed uuid',
            });
        }
    } catch (e) {
        res.status(400).json({
            status: 'error',
            message: 'failed leave team',