Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
kiloutyg committed Mar 21, 2024
2 parents a95bffe + 9904fc3 commit f6fc5ce
Show file tree
Hide file tree
Showing 20 changed files with 517 additions and 134 deletions.
15 changes: 8 additions & 7 deletions API/controllers/DocumentController.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const router = express.Router();
const DocumentManager = require('../model/Managers/DocumentManager');
const { storeDocument, upload, deleteOriginal } = require('../model/FileStore');
const { handle } = require('./functionHandler');
const requireAuth = require('./authMiddleware');

/**
* Route for getting all documents.
Expand All @@ -31,7 +32,7 @@ router.get('/', handle(async (req, res) => {
* @param {Object} res - Express response object.
* @returns {Promise<void>} - Promise that resolves when the response is sent.
*/
router.get('/archived', handle(async (req, res) => {
router.get('/archived', requireAuth, handle(async (req, res) => {
res.status(200).json(await DocumentManager.getAllArchived());
}));

Expand All @@ -57,7 +58,7 @@ router.get('/:id', handle(async (req, res) => {
* @param {Object} res - Express response object.
* @returns {Promise<void>} - Promise that resolves when the response is sent.
*/
router.post('/', upload.single('file'), storeDocument, deleteOriginal, handle(async (req, res) => {
router.post('/', requireAuth, upload.single('file'), storeDocument, deleteOriginal, handle(async (req, res) => {
req.body.filePath = req.filePath;
await DocumentManager.add(req.body); // Store the document in the database | multer middleware stored the file in Docs folder and the path in req.filePath
res.status(201).send('Document created successfully'); // Send success response
Expand All @@ -73,7 +74,7 @@ router.post('/', upload.single('file'), storeDocument, deleteOriginal, handle(as
* @param {Object} res - Express response object.
* @returns {Promise<void>} - Promise that resolves when the response is sent.
*/
router.put('/:id', handle(async (req, res) => {
router.put('/:id', requireAuth, handle(async (req, res) => {
await DocumentManager.updateTitle(req.params.id, req.body.name);
res.status(200).send('Document updated successfully');
}));
Expand All @@ -87,7 +88,7 @@ router.put('/:id', handle(async (req, res) => {
* @param {Object} res - Express response object.
* @returns {Promise<void>} - Promise that resolves when the response is sent.
*/
router.post('/:id', upload.single('file'), storeDocument, deleteOriginal, handle(async (req, res) => {
router.post('/:id', requireAuth, upload.single('file'), storeDocument, deleteOriginal, handle(async (req, res) => {
await DocumentManager.addVersion(req.params.id, req.body.date, req.filePath);
res.status(200).send('Version added successfully');
}));
Expand All @@ -101,7 +102,7 @@ router.post('/:id', upload.single('file'), storeDocument, deleteOriginal, handle
* @param {Object} res - Express response object.
* @returns {Promise<void>} - Promise that resolves when the response is sent.
*/
router.put('/:id/unarchive', handle(async (req, res) => {
router.put('/:id/unarchive', requireAuth, handle(async (req, res) => {
await DocumentManager.unarchive(req.params.id);
res.status(200).send('Document restored successfully');
}));
Expand All @@ -115,7 +116,7 @@ router.put('/:id/unarchive', handle(async (req, res) => {
* @param {Object} res - Express response object.
* @returns {Promise<void>} - Promise that resolves when the response is sent.
*/
router.delete('/:id', handle(async (req, res) => {
router.delete('/:id', requireAuth, handle(async (req, res) => {
await DocumentManager.archive(req.params.id);
res.status(204).send('Document archived successfully');
}));
Expand All @@ -129,7 +130,7 @@ router.delete('/:id', handle(async (req, res) => {
* @param {Object} res - Express response object.
* @returns {Promise<void>} - Promise that resolves when the response is sent.
*/
router.delete('/:id/archived', handle(async (req, res) => {
router.delete('/:id/archived', requireAuth, handle(async (req, res) => {
await DocumentManager.deleteArchivedDoc(req.params.id);
res.status(204).send('Document deleted successfully');
}));
Expand Down
53 changes: 43 additions & 10 deletions API/controllers/UserController.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const { handle } = require('./functionHandler');
const router = express.Router();
const UserManager = require('../model/Managers/UserManager');
const { getSignedDocument } = require('../model/Managers/SignedDocumentManager');
const requireAuth = require('./authMiddleware');

/**
* GET /users/archived
Expand All @@ -12,7 +13,7 @@ const { getSignedDocument } = require('../model/Managers/SignedDocumentManager')
* @param {Object} res - The response object.
* @returns {Promise<void>} - The promise that resolves when the users are retrieved.
*/
router.get('/archived', handle(async (req, res) => {
router.get('/archived', requireAuth, handle(async (req, res) => {
res.status(200).send(await UserManager.getArchived());
}));

Expand All @@ -34,16 +35,16 @@ router.get('/:id', handle(async (req, res) => {
* @param {Object} res - The response object.
* @returns {Promise<void>} - The promise that resolves when the user is retrieved.
*/
router.get('', handle(async (req, res) => {
router.get('', requireAuth, handle(async (req, res) => {

let data;

if (!req.query.email) {
data = await UserManager.getAll();
res.status(200).send(data);
return;
}

data = await UserManager.getByEmail(req.query.email);
res.status(200).send({ first_name: data.first_name, last_name: data.last_name });
}));
Expand All @@ -67,7 +68,7 @@ router.get('/signingData/:token', handle(async (req, res) => {
* @param {Object} res - The response object.
* @returns {Promise<void>} - The promise that resolves when the user is created.
*/
router.post('/', handle(async (req, res) => {
router.post('/', requireAuth, handle(async (req, res) => {

if (req.body.identifier != undefined) {
req.body.email = req.body.identifier;
Expand All @@ -84,7 +85,7 @@ router.post('/', handle(async (req, res) => {
* @param {Object} res - The response object.
* @returns {Promise<void>} - The promise that resolves when the user is updated.
*/
router.put('/unarchive/:id', handle(async (req, res) => {
router.put('/:id/unarchive', requireAuth, handle(async (req, res) => {
await UserManager.unarchive(req.params.id);
res.status(200).send('User unarchived successfully');
}));
Expand All @@ -96,7 +97,7 @@ router.put('/unarchive/:id', handle(async (req, res) => {
* @param {Object} res - The response object.
* @returns {Promise<void>} - The promise that resolves when the user is archived.
*/
router.delete('/:id', handle(async (req, res) => {
router.delete('/:id', requireAuth, handle(async (req, res) => {
await UserManager.archive(req.params.id);
res.status(200).send('User archived successfully');
}));
Expand All @@ -108,7 +109,7 @@ router.delete('/:id', handle(async (req, res) => {
* @param {Object} res - The response object.
* @returns {Promise<void>} - The promise that resolves when the user is deleted.
*/
router.delete('/archived/:id', handle(async (req, res) => {
router.delete('/:id/archived', requireAuth, handle(async (req, res) => {
await UserManager.deleteArchived(req.params.id);
res.status(200).send('User deleted successfully');
}));
Expand All @@ -120,7 +121,7 @@ router.delete('/archived/:id', handle(async (req, res) => {
* @param {Object} res - The response object.
* @returns {Promise<void>} - The promise that resolves when the signing token is generated.
*/
router.post('/generateSigningToken', handle(async (req, res) => {
router.post('/generateSigningToken', requireAuth, handle(async (req, res) => {
const token = await UserManager.generateSigningToken(req.body, req.body.documentId);
res.status(200).send(token);
}));
Expand All @@ -143,14 +144,46 @@ router.post('/sign/:token', blobUpload.single('blob'), handle(async (req, res) =
res.send(signedDoc.pdf);
}));

/**
* DELETE /users/:userId/deleteAllSignatures/:docId
* @description Delete all signatures for a specific document (not the waiting ones).
* @param {Object} req - The request object.
* @param {Object} res - The response object.
* @returns {Promise<void>} - The promise that resolves when the signatures are deleted.
*/
router.delete('/:userId/deleteAllSignatures/:docId', requireAuth, handle(async (req, res) => {
// delete all signatures for a specific document (not the waiting ones)
await UserManager.deleteSignatureByDocId(
req.params.docId,
req.params.userId
);
res.status(200).send('Signature deleted successfully');
}));

/**
* DELETE /users/:userId/deleteSignaturesToken/:token
* @description Delete a waiting signature by token.
* @param {Object} req - The request object.
* @param {Object} res - The response object.
* @returns {Promise<void>} - The promise that resolves when the waiting signature is deleted.
*/
router.delete('/:userId/deleteSignaturesToken/:token', requireAuth, handle(async (req, res) => {
// delete the waiting signature (by its token)
await UserManager.deleteSignatureByToken(
req.params.token,
req.params.userId
);
res.status(200).send('Signature deleted successfully');
}));

/**
* GET /users/signedDocument/:id
* @description Get a signed document by ID.
* @param {Object} req - The request object.
* @param {Object} res - The response object.
* @returns {Promise<void>} - The promise that resolves when the signed document is retrieved.
*/
router.get('/signedDocument/:id', handle(async (req, res) => {
router.get('/signedDocument/:id', requireAuth, handle(async (req, res) => {
// get the signed document
const signedDoc = await getSignedDocument(req.params.id);

Expand Down
17 changes: 12 additions & 5 deletions API/data/queries/UsersQueries.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,12 @@ async function getAll() {
let signedDocId = await getSignedDocId(user.id);
let waitingDocId = await getWaitingDocId(user.id);
let toUpdateDocId = await getToUpdateDocId(user.id);
toUpdateDocId = toUpdateDocId.map(doc => doc.doc_id);

let toUpdateDocIdList = toUpdateDocId.map(doc => doc.doc_id);

signedDocId = signedDocId.map(doc => {
doc.toUpdate = toUpdateDocId.includes(doc.id);
doc.toUpdate = toUpdateDocIdList.includes(doc.id);
doc.latest_version_id = toUpdateDocId.find(docToUpdate => docToUpdate.doc_id === doc.id) ? toUpdateDocId.find(docToUpdate => docToUpdate.doc_id === doc.id).ver_id : null;
return doc;
});

Expand All @@ -194,6 +196,7 @@ async function getSignedDocId(userId) {
return await query(`
SELECT DISTINCT
v.doc_id id,
uv.id user_version_id,
d.file_name title,
uv.date
FROM
Expand Down Expand Up @@ -254,11 +257,15 @@ async function getToUpdateDocId(userId) {
),
LastVersions AS (
-- Sélectionner la dernière version de chaque document
SELECT v.doc_id, MAX(v.created_date) AS last_created_date
SELECT v.id, v.doc_id, v.created_date AS last_created_date
FROM version v
JOIN document d ON v.doc_id = d.id
WHERE d.archived_date IS NULL
GROUP BY v.doc_id
AND v.created_date = (
SELECT MAX(v2.created_date)
FROM version v2
WHERE v2.doc_id = v.doc_id
)
),
LastSignedVersions AS (
-- Sélectionner les versions signées par l'utilisateur spécifié, pour chaque document
Expand All @@ -268,7 +275,7 @@ async function getToUpdateDocId(userId) {
GROUP BY uv.user_id, v.doc_id
)
-- Sélectionner les documents dont la dernière version n'est pas signée par l'utilisateur spécifié mais où au moins une autre version l'est
SELECT ld.doc_id
SELECT ld.doc_id, lv.id ver_id
FROM SignedDocs ld
JOIN LastSignedVersions lsv ON ld.doc_id = lsv.doc_id AND ld.user_id = lsv.user_id
LEFT JOIN version v ON lsv.doc_id = v.doc_id AND lsv.last_signed_date = v.created_date
Expand Down
71 changes: 65 additions & 6 deletions API/data/queries/UsersVersionsQueries.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const assert = require('./../../model/Asserter')
const executeWithCleanup = require("../databaseCleanup");
const versionQueries = require('./VersionQueries');

// #region CREATE

Expand Down Expand Up @@ -82,12 +83,12 @@ async function getSigningUserData(userId) {
JOIN user u ON uv.user_id = u.id
WHERE uv.id = ?;`;

const result = await query(queryStr, [userId]);
assert(result, '[UserQueries.getSigningUserData] There was a problem querying the database for the signing user data');
assert(result.length > 0, '[UserQueries.getSigningUserData] There was a problem querying the database for the signing user data');
return result[0];
const result = await query(queryStr, [userId]);

assert(result, '[UserQueries.getSigningUserData] There was a problem querying the database for the signing user data');
assert(result.length > 0, '[UserQueries.getSigningUserData] There was a problem querying the database for the signing user data');

return result[0];

});

Expand Down Expand Up @@ -333,6 +334,61 @@ async function signDoc(token, blob) {

// #endregion

// #region Delete

/**
* Deletes the signature by document ID.
*
* @param {string} docId - The document ID.
* @param {string} userId - The user ID.
* @returns {Promise<void>} - A Promise that resolves when the signature is deleted.
* @throws {Error} - If the document ID is not provided.
*/
async function deleteSignatureByDocId(docId, userId) {
assert(docId, '[UserQueries.deleteSignature] The document ID is required');

return await executeWithCleanup(async (query) => {

// get all versions of the document
const versions = await versionQueries.getAll(docId);

for (let i = 0; i < versions.length; i++) {

// delete the signature
let queryStr = `
DELETE FROM user_version
WHERE version_id = ? AND user_id = ?;`;

await query(queryStr, [versions[i].id, userId]);
}

});

}

/**
* Deletes the signature by token.
*
* @param {string} token - The signing token.
* @param {string} userId - The user ID.
* @returns {Promise<void>} - A promise that resolves when the signature is deleted.
*/
async function deleteSignatureByToken(token, userId) {
assert(token, '[UserQueries.deleteSignature] The token is required');

return await executeWithCleanup(async (query) => {

let queryStr = `
DELETE FROM user_version
WHERE signing_token = ? AND user_id = ?;`;

await query(queryStr, [token, userId]);

});
}

// #endregion


module.exports = {
addSigningToken,
Expand All @@ -349,4 +405,7 @@ module.exports = {
getById,

signDoc,

deleteSignatureByDocId,
deleteSignatureByToken
};
30 changes: 29 additions & 1 deletion API/model/Managers/UserManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,32 @@ async function autoDeleteArchivedUsers() {
console.log(`[${new Date().toLocaleString()}] - Finished checking for archived users`);
}

/**
* Deletes a signature by document ID.
*
* @param {string} docId - The ID of the document.
* @returns {Promise} A promise that resolves when the signature is deleted.
* @throws {Error} If the document ID is not provided.
*/
async function deleteSignatureByDocId(docId, userId) {
assert(docId, '[UserManager.deleteSignatureByDocId] The document ID is required');
assert(userId, '[UserManager.deleteSignatureByDocId] The user ID is required');
return await UserVersionQueries.deleteSignatureByDocId(docId, userId);
}

/**
* Deletes a signature by token.
*
* @param {string} token - The token of the signature to delete.
* @param {number} userId - The ID of the user.
* @returns {Promise} A promise that resolves when the signature is deleted.
*/
async function deleteSignatureByToken(token, userId) {
assert(token, '[UserManager.deleteSignature] The token is required');
assert(userId, '[UserManager.deleteSignature] The user ID is required');
return await UserVersionQueries.deleteSignatureByToken(token, userId);
}

module.exports = {
add,
generateSigningToken,
Expand All @@ -347,5 +373,7 @@ module.exports = {
sign,

deleteArchived,
autoDeleteArchivedUsers
autoDeleteArchivedUsers,
deleteSignatureByDocId,
deleteSignatureByToken
}
Loading

0 comments on commit f6fc5ce

Please sign in to comment.