<commit_before>const logger = require('../../logger');
const sequelize = require('../../db');
const { ConnectionInformation, Barman, Kommission, Role, Service } = require('../models');
const { createUserError, createServerError, cleanObject, hash } = require('../../utils');

/**
 * Return all barmen of the app.
 *
 * @returns {Promise<Array>} Barmen
 */
async function getAllBarmen() {

    logger.verbose('Barman service: get all barmen');
    return await Barman.findAll();
}

/**
 * Create a Barman.
 *
 * @param newBarman {Barman} partial member
 * @param _embedded {Object} Object containing associations to update, see swagger for more information.
 * @return {Promise<Barman>} The created barman with its id
 */
async function createBarman(newBarman, _embedded) {

    logger.verbose('Barman service: creating a new barman named %s %s', newBarman.firstName, newBarman.lastName);

    const transaction = await sequelize.transaction();
    try {
        await newBarman.save({ transaction });

        // If connection information is changed
        if (newBarman.connection) {
            await newBarman.getConnection();

            const coData = {
                username: newBarman.connection.username,
                password: <PASSWORD>)
            };

            await newBarman.createConnection(cleanObject(coData), { transaction });

        }
    } catch (err) {
        logger.warn('Barman service: Error while creating barman', err);
        await transaction.rollback();
        throw createServerError('ServerError', 'Error while creating barman');
    }

    // Associations
    if (_embedded) {
        for (const associationKey of Object.keys(_embedded)) {
            const value = _embedded[associationKey];

            if (associationKey === 'godFather') {
                const wantedGodFather = await Barman.findById(value);

                if (!wantedGodFather) {
                    await transaction.rollback();
                    throw createUserError('UnknownBarman', `Unable to find god father with id ${wantedGodFather}`);
                }

                await newBarman.setGodFather(wantedGodFather, { transaction });

            } else if (associationKey === 'kommissions') {
                if (value.add && value.add.length > 0) {
                    try {
                        await newBarman.addKommissions(value.add, { transaction });
                    } catch (err) {
                        await transaction.rollback();
                        throw createUserError('UnknownKommission', 'Unable to associate barman with provided kommissions');
                    }
                }
                if (value.remove && value.remove.length > 0) {
                    throw createUserError('RemovedValueProhibited', 'When creating a barman, impossible to add removed value');
                }
            } else if (associationKey === 'roles') {
                if (value.add && value.add.length > 0) {
                    try {
                        await newBarman.addRoles(value.add, { transaction });
                    } catch (err) {
                        await transaction.rollback();
                        throw createUserError('UnknownRole', 'Unable to associate barman with provided roles');
                    }
                }
                if (value.remove && value.remove.length > 0) {
                    throw createUserError('RemovedValueProhibited', 'When creating a barman, impossible to add removed value');
                }
            } else {
                throw createUserError('BadRequest', `Unknown association '${associationKey}', aborting!`);
            }
        }
    }

    await transaction.commit();
    return newBarman;
}

/**
 * Get a Barman by his id.
 * @param barmanId {number} Barman Id
 * @returns {Promise<Barman>} Barmen
 */
async function getBarmanById(barmanId) {

    logger.verbose('Barman service: get a barman by his id %d', barmanId);

    const barman = await Barman.findById(barmanId, {
        include: [
            {
                model: ConnectionInformation,
                as: 'connection',
                attributes: [ 'id', 'username' ]
            },
            {
                model: Barman,
                as: 'godFather'
            },
            {
                model: Kommission,
                as: 'kommissions'
            },
            {
                model: Role,
                as: 'roles'
            }
        ]
    });

    if (!barman) throw createUserError('UnknownBarman', 'This Barman does not exist');

    return await barman;
}

/**
 * Update a barman
 * This will copy only the allowed changes from the `updatedBarman`
 * into the current barman.
 * This means, with this function, you can not change everything like
 * the `createdAt` field or others.
 *
 * @param barmanId {number} barman id
 * @param updatedBarman {Barman} Updated barman, constructed from the request.
 * @param _embedded {Object} Object containing associations to update, see swagger for more information.
 * @return {Promise<Barman>} The updated barman
 */
async function updateBarmanById(barmanId, updatedBarman, _embedded) {
    const currentBarman = await Barman.findById(barmanId, {
        include: [
            {
                model: Kommission,
                as: 'kommissions'
            },
            {
                model: Role,
                as: 'roles'
            }
        ]
    });

    if (!currentBarman) throw createUserError('UnknownBarman', 'This Barman does not exist');

    logger.verbose('Barman service: updating barman named %s %s', currentBarman.firstName, currentBarman.lastName);

    const transaction = await sequelize.transaction();

    try {
        await currentBarman.update(cleanObject({
            firstName: updatedBarman.firstName,
            lastName: updatedBarman.lastName,
            nickname: updatedBarman.nickname,
            facebook: updatedBarman.facebook,
            dateOfBirth: updatedBarman.dateOfBirth,
            flow: updatedBarman.flow,
            active: updatedBarman.active
        }), { transaction });


        // If connection information is changed
        if (updatedBarman.connection) {
            const co = await currentBarman.getConnection();

            const coData = {
                username: updatedBarman.connection.username,
                password: <PASSWORD>(<PASSWORD>)
            };

            // If there is no connection yet, create one
            if (!co) {
                await currentBarman.createConnection(cleanObject(coData), { transaction });
            } else {
                await co.update(cleanObject(coData), { transaction });
            }
        }
    } catch (err) {
        logger.warn('Barman service: Error while updating barman', err);
        await transaction.rollback();
        throw createServerError('ServerError', 'Error while updating barman');
    }

    // Associations
    if (_embedded) {
        for (const associationKey of Object.keys(_embedded)) {
            const value = _embedded[associationKey];

            if (associationKey === 'godFather') {
                const wantedGodFather = await Barman.findById(value);

                if (!wantedGodFather) {
                    await transaction.rollback();
                    throw createUserError('UnknownBarman', `Unable to find god father with id ${wantedGodFather}`);
                }

                await currentBarman.setGodFather(wantedGodFather, { transaction });

            } else if (associationKey === 'kommissions') {
                try {
                    if (value.add && value.add.length > 0) {
                        await currentBarman.addKommissions(value.add, { transaction });
                    }
                    if (value.remove && value.remove.length > 0) {
                        await currentBarman.removeKommissions(value.remove, { transaction });
                    }
                } catch (err) {
                    await transaction.rollback();
                    throw createUserError('UnknownKommission', 'Unable to associate barman with provided kommissions');
                }
            } else if (associationKey === 'roles') {
                try {
                    if (value.add && value.add.length > 0) {
                        await currentBarman.addRoles(value.add, { transaction });
                    }
                    if (value.remove && value.remove.length > 0) {
                        await currentBarman.removeRoles(value.remove, { transaction });
                    }
                } catch (err) {
                    await transaction.rollback();
                    throw createUserError('UnknownRole', 'Unable to associate barman with provided roles');
                }
            } else {
                await transaction.rollback();
                throw createUserError('BadRequest', `Unknown association '${associationKey}', aborting!`);
            }
        }
    }

    await transaction.commit();
    return currentBarman;
}

/**
 * Delete a Barman.
 *
 * @param barmanId {number} barman id
 * @returns {Promise<Barman>} The deleted barman
 */
async function deleteBarmanById(barmanId) {

    logger.verbose('Barman service: deleting member with id %d', barmanId);

    const barman = await Barman.findById(barmanId);

    if (!barman) throw createUserError('UnknownBarman', 'This Barman does not exist');

    await barman.destroy();

    return barman;
}

/**
 * Get the services of a barman
 *
 * @param barmanId {number} barman id
 * @param startDate {Date} starting date for services
 * @param endDate {Date} ending date for services
 * @returns {Promise<Array>} Barmen's services
 */
async function getBarmanServices(barmanId, startDate, endDate) {

    logger.verbose('Barman service: retreive services of the barman ', barmanId );

    const barman = await Barman.findById(barmanId);

    if (!barman) throw createUserError('UnknownBarman', 'This Barman does not exist');
    const Op = sequelize.Op;
    const services = await barman.getServices({
        where: {
            startAt : {
                [Op.gte]: startDate,
            }, endAt : {
                [Op.lte]: endDate
            }
        }
    });

    return services;
}

/**
* Create a service for a barman
*
* @param barmanID {number} barman id
* @param serviceId {number<Array>} service ids
* @returns {Promise<Errors.ValidationError>} an error or nothing
*/
async function createServiceBarman(barmanId, servicesId) {

    logger.verbose('Barman service: create a Service for the barman ', barmanId, servicesId);

    const barman = await Barman.findById(barmanId);

    if (!barman) throw createUserError('UnknownBarman', 'This Barman does not exist');

    for (const id of servicesId) {
        const service = await Service.findById(id);
        if (!service) throw createUserError('UnknownService', 'This service does not exist');
        await barman.addService(servicesId);
    }
}

/**
* Delete a Service of a barman
*
* @param barmanId {number} barman id
* @param serviceId {number} service id
*
* @returns {Promise<Errors.ValidationError>} an error or nothing
*/
async function deleteServiceBarman(barmanId, servicesId) {

    const barman = await Barman.findById(barmanId);

    if (!barman) throw createUserError('UnknownBarman', 'This Barman does not exist');

    for (const id of servicesId) {
        const service = await Service.findById(id);
        if (!service) throw createUserError('UnknownService', 'This service does not exist');
        await service.destroy({
            include: [{
                model: Barman,
                where: {id: barmanId}
            }]
        });
    }
}

module.exports = {
    getAllBarmen,
    createBarman,
    getBarmanById,<commit_msg>fix mistakes and add transcation when creating or deleting an association between barman and services<commit_after>const logger = require('../../logger');
const sequelize = require('../../db');
const { Op } = require('sequelize');
const { ConnectionInformation, Barman, Kommission, Role } = require('../models');
const { createUserError, createServerError, cleanObject, hash } = require('../../utils');

/**
 * Return all barmen of the app.
 *
 * @returns {Promise<Array>} Barmen
 */
async function getAllBarmen() {

    logger.verbose('Barman service: get all barmen');
    return await Barman.findAll();
}

/**
 * Create a Barman.
 *
 * @param newBarman {Barman} partial member
 * @param _embedded {Object} Object containing associations to update, see swagger for more information.
 * @return {Promise<Barman>} The created barman with its id
 */
async function createBarman(newBarman, _embedded) {

    logger.verbose('Barman service: creating a new barman named %s %s', newBarman.firstName, newBarman.lastName);

    const transaction = await sequelize.transaction();
    try {
        await newBarman.save({ transaction });

        // If connection information is changed
        if (newBarman.connection) {
            await newBarman.getConnection();

            const coData = {
                username: newBarman.connection.username,
                password: hash(newBarman.connection.password)
            };

            await newBarman.createConnection(cleanObject(coData), { transaction });

        }
    } catch (err) {
        logger.warn('Barman service: Error while creating barman', err);
        await transaction.rollback();
        throw createServerError('ServerError', 'Error while creating barman');
    }

    // Associations
    if (_embedded) {
        for (const associationKey of Object.keys(_embedded)) {
            const value = _embedded[associationKey];

            if (associationKey === 'godFather') {
                const wantedGodFather = await Barman.findById(value);

                if (!wantedGodFather) {
                    await transaction.rollback();
                    throw createUserError('UnknownBarman', `Unable to find god father with id ${wantedGodFather}`);
                }

                await newBarman.setGodFather(wantedGodFather, { transaction });

            } else if (associationKey === 'kommissions') {
                if (value.add && value.add.length > 0) {
                    try {
                        await newBarman.addKommissions(value.add, { transaction });
                    } catch (err) {
                        await transaction.rollback();
                        throw createUserError('UnknownKommission', 'Unable to associate barman with provided kommissions');
                    }
                }
                if (value.remove && value.remove.length > 0) {
                    throw createUserError('RemovedValueProhibited', 'When creating a barman, impossible to add removed value');
                }
            } else if (associationKey === 'roles') {
                if (value.add && value.add.length > 0) {
                    try {
                        await newBarman.addRoles(value.add, { transaction });
                    } catch (err) {
                        await transaction.rollback();
                        throw createUserError('UnknownRole', 'Unable to associate barman with provided roles');
                    }
                }
                if (value.remove && value.remove.length > 0) {
                    throw createUserError('RemovedValueProhibited', 'When creating a barman, impossible to add removed value');
                }
            } else {
                throw createUserError('BadRequest', `Unknown association '${associationKey}', aborting!`);
            }
        }
    }

    await transaction.commit();
    return newBarman;
}

/**
 * Get a Barman by his id.
 * @param barmanId {number} Barman Id
 * @returns {Promise<Barman>} Barmen
 */
async function getBarmanById(barmanId) {

    logger.verbose('Barman service: get a barman by his id %d', barmanId);

    const barman = await Barman.findById(barmanId, {
        include: [
            {
                model: ConnectionInformation,
                as: 'connection',
                attributes: [ 'id', 'username' ]
            },
            {
                model: Barman,
                as: 'godFather'
            },
            {
                model: Kommission,
                as: 'kommissions'
            },
            {
                model: Role,
                as: 'roles'
            }
        ]
    });

    if (!barman) throw createUserError('UnknownBarman', 'This Barman does not exist');

    return await barman;
}

/**
 * Update a barman
 * This will copy only the allowed changes from the `updatedBarman`
 * into the current barman.
 * This means, with this function, you can not change everything like
 * the `createdAt` field or others.
 *
 * @param barmanId {number} barman id
 * @param updatedBarman {Barman} Updated barman, constructed from the request.
 * @param _embedded {Object} Object containing associations to update, see swagger for more information.
 * @return {Promise<Barman>} The updated barman
 */
async function updateBarmanById(barmanId, updatedBarman, _embedded) {
    const currentBarman = await Barman.findById(barmanId, {
        include: [
            {
                model: Kommission,
                as: 'kommissions'
            },
            {
                model: Role,
                as: 'roles'
            }
        ]
    });

    if (!currentBarman) throw createUserError('UnknownBarman', 'This Barman does not exist');

    logger.verbose('Barman service: updating barman named %s %s', currentBarman.firstName, currentBarman.lastName);

    const transaction = await sequelize.transaction();

    try {
        await currentBarman.update(cleanObject({
            firstName: updatedBarman.firstName,
            lastName: updatedBarman.lastName,
            nickname: updatedBarman.nickname,
            facebook: updatedBarman.facebook,
            dateOfBirth: updatedBarman.dateOfBirth,
            flow: updatedBarman.flow,
            active: updatedBarman.active
        }), { transaction });


        // If connection information is changed
        if (updatedBarman.connection) {
            const co = await currentBarman.getConnection();

            const coData = {
                username: updatedBarman.connection.username,
                password: <PASSWORD>(<PASSWORD>)
            };

            // If there is no connection yet, create one
            if (!co) {
                await currentBarman.createConnection(cleanObject(coData), { transaction });
            } else {
                await co.update(cleanObject(coData), { transaction });
            }
        }
    } catch (err) {
        logger.warn('Barman service: Error while updating barman', err);
        await transaction.rollback();
        throw createServerError('ServerError', 'Error while updating barman');
    }

    // Associations
    if (_embedded) {
        for (const associationKey of Object.keys(_embedded)) {
            const value = _embedded[associationKey];

            if (associationKey === 'godFather') {
                const wantedGodFather = await Barman.findById(value);

                if (!wantedGodFather) {
                    await transaction.rollback();
                    throw createUserError('UnknownBarman', `Unable to find god father with id ${wantedGodFather}`);
                }

                await currentBarman.setGodFather(wantedGodFather, { transaction });

            } else if (associationKey === 'kommissions') {
                try {
                    if (value.add && value.add.length > 0) {
                        await currentBarman.addKommissions(value.add, { transaction });
                    }
                    if (value.remove && value.remove.length > 0) {
                        await currentBarman.removeKommissions(value.remove, { transaction });
                    }
                } catch (err) {
                    await transaction.rollback();
                    throw createUserError('UnknownKommission', 'Unable to associate barman with provided kommissions');
                }
            } else if (associationKey === 'roles') {
                try {
                    if (value.add && value.add.length > 0) {
                        await currentBarman.addRoles(value.add, { transaction });
                    }
                    if (value.remove && value.remove.length > 0) {
                        await currentBarman.removeRoles(value.remove, { transaction });
                    }
                } catch (err) {
                    await transaction.rollback();
                    throw createUserError('UnknownRole', 'Unable to associate barman with provided roles');
                }
            } else {
                await transaction.rollback();
                throw createUserError('BadRequest', `Unknown association '${associationKey}', aborting!`);
            }
        }
    }

    await transaction.commit();
    return currentBarman;
}

/**
 * Delete a Barman.
 *
 * @param barmanId {number} barman id
 * @returns {Promise<Barman>} The deleted barman
 */
async function deleteBarmanById(barmanId) {

    logger.verbose('Barman service: deleting member with id %d', barmanId);

    const barman = await Barman.findById(barmanId);

    if (!barman) throw createUserError('UnknownBarman', 'This Barman does not exist');

    await barman.destroy();

    return barman;
}

/**
 * Get the services of a barman
 *
 * @param barmanId {number} barman id
 * @param startDate {Date} starting date for services
 * @param endDate {Date} ending date for services
 * @returns {Promise<Array>} Barmen's services
 */
async function getBarmanServices(barmanId, startDate, endDate) {

    logger.verbose('Barman service: retreive services of the barman ', barmanId );

    const barman = await Barman.findById(barmanId);

    if (!barman) throw createUserError('UnknownBarman', 'This Barman does not exist');
    const services = await barman.getServices({
        where: {
            startAt : {
                [Op.gte]: startDate,
            }, endAt : {
                [Op.lte]: endDate
            }
        }
    });

    return services;
}

/**
* Create a service for a barman
*
* @param barmanID {number} barman id
* @param serviceId {number<Array>} service ids
* @returns {Promise<Errors.ValidationError>} an error or nothing
*/
async function createServiceBarman(barmanId, servicesId) {

    logger.verbose('Barman service: create a Service for the barman ', barmanId, servicesId);

    const transaction = await sequelize.transaction();

    const barman = await Barman.findById(barmanId);

    if (!barman) throw createUserError('UnknownBarman', 'This Barman does not exist');

    try {
        await barman.addService(servicesId, {transaction});
    } catch (err) {
        await transaction.rollback();
        throw createUserError('UnknownServices', 'Unable to associate barman with provided services');
    }

    await transaction.commit();
}

/**
* Delete a Service of a barman
*
* @param barmanId {number} barman id
* @param serviceId {number} service id
*
* @returns {Promise<Errors.ValidationError>} an error or nothing
*/
async function deleteServiceBarman(barmanId, servicesId) {

    logger.verbose('Barman service: delete a Service for the barman ', barmanId, servicesId);

    const transaction = await sequelize.transaction();

    const barman = await Barman.findById(barmanId);

    if (!barman) throw createUserError('UnknownBarman', 'This Barman does not exist');

    try {
        await barman.removeServices(servicesId, {transaction});
    } catch (err) {
        await transaction.rollback();
        throw createUserError('UnknownServices', 'Unable to associate barman with provided services');
    }

    await transaction.commit();
}

module.exports = {
    getAllBarmen,
    createBarman,
    getBarmanById,
{'fraction_non_alphanumeric': 0.10327561026496974, 'fraction_numerical': 0.0006676403087836428, 'mean_word_length': 2.067451683092282, 'pattern_counts': {'":': 0, '<': 26, '<?xml version=': 0, '>': 42, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6120952', 'n_tokens_mistral': 6356, 'n_tokens_neox': 6059, 'n_words': 1724}