const express = require('express');
const auth = require('../middleware/authenticator.js');
const mysql = require("../db/mysql.js");
const router = express.Router();
const verify = require('../middleware/verifier.js');
/**
* @typedef {object} MemberGetGetsFeedbackPackage
* @property {boolean} gets_feedback Whether the user gets feedback or not
*/
/**
* Route for checking if this user gets feedback on sheet music if they are verified to be in the choir attached to the sheet music
* @name member/get/gets-feedback
* @function
* @inner
* @param {*} req
* @param {string} req.body.choirId The choir ID to be accessed. NOTE: Only need to pass choirId in body or query not both
* @param {string} req.query.choirId The choir ID to be accessed. NOTE: Only need to pass choirId in body or query not both
* @param {*} res
* @returns {MemberGetGetsFeedbackPackage|string} On success, returns whether or not the user should get feedback. Otherwise, an error message.
* @async
*/
router.get('/gets-feedback', auth.token, async(req,res) => {
verify.userIsVerified(req, res).then((isVerified) => {
if (!isVerified) {
res.status(403).send('Unauthorized');
} else {
const choirId = req.query.choirId;
if (!choirId) {
choirId = req.body.choirId;
}
const errorMessage = "Unable to get if gets feedback";
if (choirId) {
mysql.getClient().then((client) => {
client.query("SELECT gets_feedback FROM tma.member WHERE person_id=? AND choir_id=unhex(?)", [res.locals.uid, choirId], function(error, results, fields) {
if (error) {
res.status(503).send(errorMessage);
} else if (results.length === 0) {
res.status(204).send(errorMessage);
} else {
let sum = 0;
for (let i = 0; i < results.length; i++) {
sum += results[i]["gets_feedback"];
}
let gets_feedback = sum > 0 ? true : false;
res.status(200).json({ gets_feedback });
}
});
});
} else {
res.status(400).send(errorMessage);
}
}
}).catch((error) => {
res.status(403).send('Unauthorized');
});
});
/**
* @typedef {MemberGetPendingReturnPackage[]} MemberGetPendingPackage List of information about the pending members
*/
/**
* @typedef {object} MemberGetPendingReturnPackage
* @property {string} member_id The ID of the member
* @property {string} first_name The first name of the member
* @property {string} email The email of the member
* @property {string} member_type The type of the member
* @property {string} member_role The role of the member
* @property {boolean} has_picture Whether the person attached to the member has a profile picture
*/
/**
* Route for getting all members which are still pending to be added to the choir which this user is an admin to
* @name member/get/pending
* @function
* @inner
* @param {*} req
* @param {string} req.query.choirId The choir ID to be accessed.
* @param {*} res
* @returns {MemberGetPendingPackage|string} On success then information about the members who are pending. Otherwise, an error message.
* @async
*/
router.get('/pending', auth.token, async(req,res) => {
verify.admin(req,res).then((isVerified) => {
if (!isVerified) {
res.status(403).send('Unauthorized');
} else {
let choirId = req.query.choirId;
const errorMessage = "Unable to get pending users";
if (choirId) {
mysql.getClient().then((client) => {
client.query("SELECT member_id, first_name, last_name, email, member_type, member_role, has_picture FROM tma.member INNER JOIN tma.person ON person.person_id = member.person_id WHERE member_status = 'pending' AND choir_id=unhex(?)", [choirId], function(error, results, fields) {
if (error) {
res.status(503).send(errorMessage);
} else {
res.status(200).json(results);
}
});
});
} else {
res.status(400).send(errorMessage);
}
}
}).catch((error) => {
res.status(403).send('Unauthorized');
});
});
/**
* Route for a non-admin attempting to join a choir. They are added as a pending member until an admin approves them
* @name member/post
* @function
* @inner
* @param {*} req
* @param {string} req.body.memberType The type of the member to be created
* @param {string} req.body.memberRole The role of the member to be created
* @param {string} req.body.accessCode The access code of the choir to which to add the member
* @param {*} res
* @returns {string} An error message if an error occured
* @async
*/
router.post('/', auth.token, async(req,res) => {
let memberType = req.body.memberType;
let memberRole = req.body.memberRole;
let accessCode = req.body.accessCode;
const errorMessage = "Unable to add member";
if (memberType && memberRole && accessCode) {
let client = await mysql.getClient();
client.query("SELECT hex(choir_id) FROM tma.choir WHERE access_code=?", [accessCode], function(error, results, fields) {
if (error) {
res.status(503).send(errorMessage);
} else if (results.length === 0) {
res.status(400).send(errorMessage);
} else {
let choirId = results[0]["hex(choir_id)"];
client.query("SELECT COUNT(*) FROM tma.member WHERE choir_id= unhex(?) AND person_id=? AND member_type=? AND member_role=?", [choirId, res.locals.uid, memberType, memberRole], function(error, results, fields) {
if (error) {
res.status(503).send(errorMessage);
} else if (results.length === 0) {
res.status(204).send(errorMessage);
} else if (parseInt(results[0]["COUNT(*)"],10) > 0) {
res.status(208).send(errorMessage);
} else {
client.query("INSERT INTO tma.member (member_id, member_type, member_role, choir_id, person_id, member_status) values(unhex(replace(uuid(),'-','')), ?, ?, unhex(?), ?, 'pending')", [memberType, memberRole, choirId, res.locals.uid], function(error, results, fields) {
if (error) {
res.status(503).send(errorMessage);
} else {
res.status(200).send();
}
});
}
});
}
});
} else {
res.status(400).send(errorMessage);
}
});
/**
* Route for an admin approving a pending member to joining a choir
* @name member/put/accept
* @function
* @inner
* @param {*} req
* @param {string} req.body.choirId The choir ID to be accessed.
* @param {string} req.body.memberId The member ID to be accepted.
* @param {*} res
* @returns {string} An error message if an error occured
* @async
*/
router.put('/accept', auth.token, async(req, res) => {
verify.admin(req,res).then((isVerified) => {
if (!isVerified) {
res.status(403).send('Unauthorized');
} else {
let choirId = req.body.choirId;
let memberId = req.body.memberId;
const errorMessage = "Unable to accept user";
if (choirId && memberId) {
mysql.getClient().then((client) => {
client.query("UPDATE tma.member SET member_status='verified' WHERE member_id=unhex(?) AND choir_id=unhex(?) AND member_status='pending'", [memberId, choirId], function(error, results, fields) {
if (error) {
res.status(503).send(errorMessage);
} else {
res.status(200).send();
}
});
});
} else {
res.status(400).send(errorMessage);
}
}
}).catch((error) => {
res.status(403).send('Unauthorized');
});
});
/**
* Route for an admin rejecting a pending member to joining a choir. This doesn't remove them from the list of members
* @name member/put/reject
* @function
* @inner
* @param {*} req
* @param {string} req.body.choirId The choir ID to be accessed.
* @param {string} req.body.memberId The member ID to be rejected.
* @param {*} res
* @returns {string} An error message if an error occured
* @async
*/
router.put('/reject', auth.token, async(req, res) => {
verify.admin(req,res).then((isVerified) => {
if (!isVerified) {
res.status(403).send('Unauthorized');
} else {
let choirId = req.body.choirId;
let memberId = req.body.memberId;
const errorMessage = "Unable to reject user";
if (choirId && memberId) {
mysql.getClient().then((client) => {
client.query("UPDATE tma.member SET member_status='rejected' WHERE member_id=unhex(?) AND choir_id=unhex(?) AND member_status='pending'", [memberId, choirId], function(error, results, fields) {
if (error) {
res.status(503).send(errorMessage);
} else {
res.status(200).send();
}
});
});
} else {
res.status(400).send(errorMessage);
}
}
}).catch((error) => {
res.status(403).send('Unauthorized');
});
});
/**
* Route for updating a member's information by an admin
* @name member/put/update
* @function
* @inner
* @param {*} req
* @param {string} req.body.memberId The member ID to be accessed.
* @param {string} req.body.memberType The new member type for the member
* @param {string} req.body.memberRole The new member role for the member
* @param {*} res
* @returns {string} An error message if an error occured
* @async
*/
router.put('/update', auth.token, async(req, res) => {
verify.adminOfMember(req,res).then((choirId) => {
if (choirId === null) {
res.status(403).send('Unauthorized');
} else {
let memberId = req.body.memberId;
let memberType = req.body.memberType;
let memberRole = req.body.memberRole;
const errorMessage = "Unable to update user";
if (memberId && memberType, memberRole) {
mysql.getClient().then((client) => {
client.query("UPDATE tma.member SET member_type=?, member_role=? WHERE member_id=unhex(?)", [memberType, memberRole, memberId], function(error, results, fields) {
if (error) {
res.status(503).send(errorMessage);
} else {
res.status(200).send();
}
});
});
} else {
res.status(400).send(errorMessage);
}
}
}).catch((error) => {
res.status(403).send('Unauthorized');
});
});
/**
* Route for deleting a member from a choir by an admin
* @name member/delete
* @function
* @inner
* @param {*} req
* @param {string} req.body.memberId The member ID to be deleted.
* @param {*} res
* @returns {string} An error message if an error occured
* @async
*/
router.delete('/', auth.token, async(req, res) => {
verify.adminOfMember(req,res).then((choirId) => {
if (choirId === null) {
res.status(403).send('Unauthorized');
} else {
let memberId = req.body.memberId;
const errorMessage = "Unable to delete user";
if (memberId) {
mysql.getClient().then((client) => {
client.query("UPDATE tma.member SET member_status='admin_removed' WHERE member_id=unhex(?)", [memberId], function(error, results, fields) {
if (error) {
res.status(503).send(errorMessage);
} else {
res.status(200).send();
}
});
});
} else {
res.status(400).send(errorMessage);
}
}
}).catch((error) => {
res.status(403).send('Unauthorized');
});
});
module.exports = router;