resource-watch/rw_metadata

View on GitHub
app/src/services/metadata.service.js

Summary

Maintainability
C
1 day
Test Coverage
B
88%
const logger = require('logger');
const isNil = require('lodash/isNil');
const Metadata = require('models/metadata.model');
const MetadataNotFound = require('errors/metadataNotFound.error');
const MetadataDuplicated = require('errors/metadataDuplicated.error');
const InvalidSortParameter = require('errors/invalidSortParameter.error');

class MetadataService {

    static getFilter(filter) {
        let finalFilter = {};
        if (filter && filter.application) {
            finalFilter.application = { $in: filter.application.split(',') };
        }
        if (filter && filter.language) {
            finalFilter.language = { $in: filter.language.split(',') };
        }
        if (filter && filter.search && filter.search.length > 0) {
            const tempFilter = {
                $and: [
                    { $text: { $search: filter.search.join(' ') } }
                ]
            };
            if (Object.keys(finalFilter).length > 0) {
                tempFilter.$and.push({
                    $and: Object.keys(finalFilter).map((key) => {
                        const q = {};
                        q[key] = finalFilter[key];
                        return q;
                    }) || []
                });
            }
            finalFilter = tempFilter;
        }
        return finalFilter;
    }

    static async get(dataset, resource, filter) {
        const query = {
            dataset,
            'resource.id': resource.id,
            'resource.type': resource.type
        };
        const finalQuery = Object.assign(query, MetadataService.getFilter(filter));
        const limit = (Number.isNaN(parseInt(filter.limit, 10))) ? 0 : parseInt(filter.limit, 10);
        logger.debug('Getting metadata');
        return Metadata.find(finalQuery).limit(limit).exec();
    }

    static async create(user, dataset, resource, body) {
        logger.debug('Checking if metadata exists');
        const currentMetadata = await Metadata.findOne({
            dataset,
            'resource.id': resource.id,
            'resource.type': resource.type,
            application: body.application,
            language: body.language
        }).exec();
        if (currentMetadata) {
            logger.error('Error creating metadata');
            throw new MetadataDuplicated(`Metadata of resource ${resource.type}: ${resource.id}, application: ${body.application} and language: ${body.language} already exists`);
        }
        logger.debug('Creating metadata');
        const metadata = new Metadata({
            dataset,
            resource,
            application: body.application,
            language: body.language,
            userId: user.id,
            name: body.name,
            description: body.description,
            source: body.source,
            citation: body.citation,
            license: body.license,
            units: body.units,
            info: body.info,
            columns: body.columns,
            applicationProperties: body.applicationProperties
        });
        return metadata.save();
    }

    static async createSome(user, metadatas, dataset, resource) {
        const results = [];
        for (let i = 0; i < metadatas.length; i++) {
            results.push(MetadataService.create(user, dataset, resource, metadatas[i]));
        }
        await Promise.all(results);

        return MetadataService.get(dataset, resource, {});
    }

    static async update(dataset, resource, body) {
        const metadata = await Metadata.findOne({
            dataset,
            'resource.id': resource.id,
            'resource.type': resource.type,
            application: body.application,
            language: body.language
        }).exec();
        if (!metadata) {
            logger.error('Error updating metadata');
            throw new MetadataNotFound(`Metadata of resource ${resource.type}: ${resource.id} doesn't exist`);
        }

        logger.debug('Updating metadata');
        metadata.name = body.name ? body.name : metadata.name;
        metadata.description = !isNil(body.description) ? body.description : metadata.description;
        metadata.source = !isNil(body.source) ? body.source : metadata.source;
        metadata.citation = !isNil(body.citation) ? body.citation : metadata.citation;
        metadata.license = !isNil(body.license) ? body.license : metadata.license;
        metadata.info = body.info ? body.info : metadata.info;
        metadata.columns = body.columns ? body.columns : metadata.columns;
        metadata.status = body.status ? body.status : metadata.status;
        metadata.applicationProperties = body.applicationProperties ? body.applicationProperties : metadata.applicationProperties;
        metadata.updatedAt = new Date();
        return metadata.save();
    }

    static async delete(dataset, resource, filter) {
        const query = {
            dataset,
            'resource.id': resource.id,
            'resource.type': resource.type
        };
        const finalQuery = Object.assign(query, MetadataService.getFilter(filter));
        const metadata = await Metadata.findOne(query).exec();
        if (!metadata) {
            logger.error('Error deleting metadata');
            throw new MetadataNotFound(`Metadata of resource ${resource.type}: ${resource.id} doesn't exist`);
        }
        logger.debug('Deleting metadata');
        await Metadata.deleteMany(finalQuery).exec();
        return metadata;
    }

    static async getAll(filter, extendedFilter) {
        const finalFilter = MetadataService.getFilter(filter);
        let projection = null;
        const options = {};
        if (filter.sort) {
            options.sort = {};
            filter.sort.split(',').forEach((el) => {
                let [sign] = el;
                let key = el;
                if (sign === '-' || sign === '+') {
                    key = el.slice(1);
                } else {
                    sign = '+';
                }

                if (key === 'relevance') {
                    if (el === '+relevance') {
                        throw new InvalidSortParameter('Sort by relevance ascending not supported');
                    }
                    projection = { score: { $meta: 'textScore' } };
                    options.sort.score = { $meta: 'textScore' };
                } else {
                    options.sort[key] = sign === '+' ? 1 : -1;
                }
            });
        }
        if (extendedFilter && extendedFilter.type) {
            finalFilter['resource.type'] = extendedFilter.type;
        }

        const limit = (Number.isNaN(parseInt(filter.limit, 10))) ? 0 : parseInt(filter.limit, 10);
        logger.debug('Getting metadata');
        const result = await Metadata.find(finalFilter, projection, options).limit(limit).exec();
        return result;
    }

    static async getByIds(resource, filter) {
        logger.debug(`Getting metadata with ids ${resource.ids}`);
        const query = {
            'resource.id': { $in: resource.ids },
            'resource.type': resource.type
        };
        const finalQuery = Object.assign(query, MetadataService.getFilter(filter));
        logger.debug('Getting metadata');
        return Metadata.find(finalQuery).exec();
    }

    static async clone(user, dataset, resource, body) {
        logger.debug('Checking if metadata exists');
        let metadatas = await MetadataService.get(dataset, resource, {});
        metadatas = metadatas.map((metadata) => metadata.toObject());
        if (metadatas.length === 0) {
            throw new MetadataNotFound(`No metadata of resource ${resource.type}: ${resource.id}`);
        }
        return MetadataService.createSome(user, metadatas, body.newDataset, {
            type: 'dataset',
            id: body.newDataset
        });
    }

    /*
    * @returns: hasPermission: <Boolean>
    */
    static async hasPermission(user, dataset, resource, body) {
        let permission = true;
        const metadata = await Metadata.findOne({
            dataset,
            'resource.id': resource.id,
            'resource.type': resource.type,
            application: body.application,
            language: body.language
        }).exec();
        if (metadata) {
            if (metadata.userId !== 'legacy' && metadata.userId !== user.id) {
                permission = false;
            }
        }
        return permission;
    }

}

module.exports = MetadataService;