/** @module routes/v1 */
// Register router
const { authorize } = require('../../utils.js');
const fs = require('fs');
const express = require('express');
const router = express.Router();
const SpineImageController = require('../../controllers/SpineImageController.js');
const TokenController = require('../../controllers/TokenController.js');
const { SpineImageFactory } = require('../../classes/books/SpineImage.js');
const { TokenFactory } = require('../../classes/users/Token.js');
/** Route for getting spine images to verify */
router.get('/contribute/verify/get', async (req, res) => {
if (!await authorize(['contribute.verify.get'], req, res)) {
return;
}
const imageInfo = [];
const spineImagesUnconfirmed = await new SpineImageController().byCrowdApproved(5, false);
for (const spineImageDb of spineImagesUnconfirmed) {
if (imageInfo.length >= 3) {
break;
}
const spineImage = await new SpineImageFactory().load(spineImageDb).create();
const edition = await spineImage.getEdition();
const book = await edition.getBook();
const spineFullPath = process.env.STORAGE_PATH + '/spine-images/' + spineImage.filepath;
if (!fs.existsSync(spineFullPath)) {
await spineImage.delete();
continue;
}
imageInfo.push({
id: spineImage.id,
name: book.title,
image: base64_encode(spineFullPath),
});
}
res.send({ "image_info": imageInfo });
});
/** Route for submitting verification */
router.post('/contribute/verify/submit', async (req, res) => {
if (!await authorize(['contribute.verify.submit'], req, res)) {
return;
}
if (req.body.confirmed !== 'true' && req.body.confirmed !== 'false') {
res.status(400).send({ message: 'Invalid confirmed' });
return;
}
const imageId = req.body.image_id;
const confirmed = req.body.confirmed === 'true';
const adminForce = req.body.admin_force === 'true';
if (!imageId) {
res.status(400).send({ message: 'Missing image_id' });
return;
} else if (isNaN(imageId)) {
res.status(400).send({ message: 'Invalid image_id' });
return;
}
const spineImageDbRecord = await new SpineImageController().byId(parseInt(imageId));
if (!spineImageDbRecord) {
res.status(400).send({ message: 'Image not found' });
return;
}
const spineImage = await new SpineImageFactory().load(spineImageDbRecord).create();
const user = await (await new TokenFactory().load(await new TokenController().byTokenString(req.headers['authorization'])).create()).getUser();
user.addContribution('VERIFY_SPINE_IMAGE', spineImage.id);
if (adminForce) {
const isAdmin = await user.getMeta('flag.admin') === 'true';
if (!isAdmin) {
res.status(403).send({ message: 'Insufficient permissions' });
return;
}
if (confirmed) {
await spineImage.setMeta('crowdApproved', true);
} else {
await spineImage.delete();
}
res.send({ message: 'Verification submitted' });
return;
}
let crowdConfirmations = await spineImage.getMeta('crowdConfirmations');
let crowdRejections = await spineImage.getMeta('crowdRejections');
if (confirmed) {
crowdConfirmations++;
await spineImage.setMeta('crowdConfirmations', crowdConfirmations);
} else {
crowdRejections++;
await spineImage.setMeta('crowdRejections', crowdRejections);
}
if (crowdConfirmations / (crowdConfirmations + crowdRejections) >= 0.6 && crowdConfirmations >= 8) {
await spineImage.setMeta('crowdApproved', true);
}
if (crowdRejections / (crowdConfirmations + crowdRejections) >= 0.6 && crowdRejections >= 8) {
await spineImage.delete();
}
res.send({ message: 'Verification submitted' });
});
module.exports = router;
// Functions
/**
* Encodes a file to base64
*
* @param {string} filePath
* @returns {string}
*/
function base64_encode(filePath) {
const bitmap = fs.readFileSync(filePath);
return bitmap.toString('base64');
}