mongaku/mongaku

View on GitHub
src/schemas/Source.js

Summary

Maintainability
A
1 hr
Test Coverage
const path = require("path");

const async = require("async");

const record = require("../lib/record");
const models = require("../lib/models");
const db = require("../lib/db");
const config = require("../lib/config");
const options = require("../lib/options");
const urls = require("../lib/urls")(options);
const defaultConverter = require("../lib/default-converter");

let sourceCache = [];

const Source = new db.schema({
    // A short ID (e.g. "frick")
    _id: String,

    // The type of the record
    type: {
        type: String,
        required: true,
    },

    // The URL to associate with the source
    url: String,

    // The full name of the source (e.g. "Frick Art Reference Library")
    name: {
        type: String,
        required: true,
    },

    // A short name (e.g. "Frick")
    shortName: {
        type: String,
        required: true,
    },

    // The name of the converter to use on the data when importing
    converter: {
        type: String,
        default: "default",
    },

    // Is the soure marked as private and not visible to logged-out users?
    private: {
        type: Boolean,
        default: false,
    },
});

Source.methods = {
    getURL(lang) {
        return urls.gen(lang, `/${this.type}/source/${this._id}`);
    },

    getAdminURL(lang) {
        return `${this.getURL(lang)}/admin`;
    },

    getDirBase() {
        return path.resolve(config.BASE_DATA_DIR, this._id);
    },

    getFullName() {
        return this.name;
    },

    getShortName() {
        return this.shortName;
    },

    getConverter() {
        const converter = this.converter || "default";
        const converters = Object.assign(
            {
                default: defaultConverter,
            },
            options.converters,
        );

        /* istanbul ignore if */
        if (!converters[converter]) {
            throw new Error(`Error: Converter not found: ${converter}`);
        }

        // Return the converter module
        return converters[converter];
    },

    getExpectedFiles() {
        return this.getConverter().files;
    },

    processFiles(files, callback) {
        this.getConverter().processFiles(files, callback);
    },

    cacheTotals(callback) {
        record(this.type).aggregate(
            [
                {
                    $match: {
                        source: this._id,
                    },
                },
                {
                    $group: {
                        _id: null,
                        total: {$sum: 1},
                        totalImages: {$sum: {$size: "$images"}},
                    },
                },
            ],
            (err, results) => {
                if (results && results[0]) {
                    this.numRecords = results[0].total;
                    this.numImages = results[0].totalImages;
                } else {
                    this.numRecords = 0;
                    this.numImages = 0;
                }
                callback();
            },
        );
    },

    canView(user) {
        if (!this.private) {
            return true;
        }

        if (!user) {
            return false;
        }

        return user.canViewPrivateSources || user.canEditSource(this._id);
    },
};

Source.statics = {
    cacheSources(callback) {
        models("Source").find({}, (err, sources) => {
            sourceCache = sources;

            async.eachLimit(
                sources,
                2,
                (source, callback) => {
                    source.cacheTotals(callback);
                },
                () => {
                    callback(err, sources);
                },
            );
        });
    },

    getSources() {
        return sourceCache;
    },

    getSourcesByViewable(user) {
        return this.getSources().filter(source => source.canView(user));
    },

    getSourcesByViewableType(user, type) {
        return this.getSources().filter(
            source => source.canView(user) && source.type === type,
        );
    },

    getSource(sourceName) {
        const sources = this.getSources();

        for (const source of sources) {
            if (source._id === sourceName) {
                return source;
            }
        }

        throw new Error(`Source not found: ${sourceName}`);
    },
};

module.exports = Source;