Source: utils.js

/** @module utils */

const { TokenFactory } = require('./classes/users/Token.js');
const TokenController = require('./controllers/TokenController.js');

/** Default permissions for users */
const defaultUserPermissions = {
    'permission.inference.spine': 'true',
    'permission.search.book': 'true',
    'permission.search.ocr': 'true',
    'permission.contribute.edition': 'true',
    'permission.contribute.verify.get': 'true',
    'permission.contribute.verify.submit': 'true',
};

/**
 * Checks if the user has the required permissions to access the endpoint
 * 
 * @param {string[]} permissions
 * @param {any} req
 * @param {any} res
 * @param {boolean} sendResponse If true, send a response if the user is not authorized
 * @returns {Promise<boolean>}
 */
async function authorize(permissions = [], req, res, sendResponse = true) {
    const tokenString = req.headers['authorization'];
    if (!tokenString) {
        if (sendResponse) res.status(401).send({ message: 'Missing token' });
        return false;
    }

    const tokenDbRecord = await new TokenController().byTokenString(tokenString);
    if (!tokenDbRecord) {
        if (sendResponse) res.status(401).send({ message: 'Invalid token' });
        return false;
    }

    const token = await new TokenFactory().load(tokenDbRecord).create();
    const user = await token.getUser();

    if (!user) {
        if (sendResponse) res.status(401).send({ message: 'Invalid token' });
        return false;
    }

    req.user = user;

    for (const permission of permissions) {
        let userPermission = await user.getMeta('permission.' + permission);
        if (!userPermission) {
            userPermission = defaultUserPermissions['permission.' + permission];
        }
        
        if (userPermission !== 'true') {
            if (sendResponse) res.status(403).send({ message: 'Insufficient permissions' });
            return false;
        }
    }

    return true;
}

/**
 * Split a text using more than one separator
 * 
 * @param {string} text
 * @param {string[]} separators
 * @returns {string[]}
 */
function split(text, separators) {
    const result = [];
    let current = '';
    for (const char of text) {
        if (separators.includes(char)) {
            if (current) {
                result.push(current);
                current = '';
            }
        } else {
            current += char;
        }
    }
    if (current) {
        result.push(current);
    }
    return result;
}

/**
 * Create terms used in the database from text
 * 
 * @param {string} text
 * @returns {string[]}
 */
function createTerms(text) {
    const words = split(text, [' ', ',', '.', '!', '?', ';', ':', '(', ')', '[', ']', '{', '}', '<', '>', '\n', '\t', '-', '_']);
    const result = [];
    for (const word of words) {
        const len = word.length;

        // Iterate through each possible substring
        for (let i = 0; i < len; i++) {
            for (let j = i + 1; j <= len; j++) {
                const substring = word.substring(i, j).toLowerCase();
                result.push(substring);
            }
        }
    }

    return result;
}

/**
 * Generate a temporary image path
 * 
 * @returns {string} path
 */
function generateTempImagePath() {
    return process.env.STORAGE_PATH + `/temp/${Date.now()}-${Math.floor(Math.random() * 100000)}.jpg`;
}


module.exports = {
    defaultUserPermissions,
    authorize,
    createTerms,
    generateTempImagePath,
};