{"size": 10576, "ext": "js", "max_stars_repo_path": "dev/bin/setup.js", "max_stars_repo_name": "xtremespb/zoia", "max_stars_repo_stars_event_min_datetime": "2017-10-05T10:15:56.000Z", "max_stars_repo_stars_event_max_datetime": "2021-12-14T12:30:08.000Z", "max_issues_repo_path": "dev/bin/setup.js", "max_issues_repo_name": "xtremespb/zoia3", "max_issues_repo_issues_event_min_datetime": "2017-10-13T09:00:25.000Z", "max_issues_repo_issues_event_max_datetime": "2022-03-08T09:17:38.000Z", "max_forks_repo_path": "dev/bin/setup.js", "max_forks_repo_name": "xtremespb/zoia", "max_forks_repo_forks_event_min_datetime": "2017-10-12T18:07:15.000Z", "max_forks_repo_forks_event_max_datetime": "2021-12-14T12:30:12.000Z"}
{"max_stars_count": 84, "max_issues_count": 58, "max_forks_count": 12, "avg_line_length": 49.6525821596, "max_line_length": 510, "alphanum_fraction": 0.4064863843}
/* eslint-disable no-restricted-syntax */
/* eslint-disable no-await-in-loop */
/* eslint-disable no-console */
const fs = require("fs-extra");
const path = require("path");
const {
    MongoClient
} = require("mongodb");
const commandLineArgs = require("command-line-args");
const colors = require("colors/safe");

let packageJson;
try {
    packageJson = require(path.resolve(`${__dirname}/../../package.json`));
} catch {
    console.log(colors.brightRed("Fatal: could not load package.json"));
    console.log(colors.grey(`Please get this file from Github, you won't be able to run ZOIA otherwise.\n`));
    process.exit(1);
}

const options = commandLineArgs([{
    name: "module",
    alias: "m",
    type: String
}, {
    name: "all",
    alias: "a",
    type: Boolean
}, {
    name: "defaults",
    alias: "d",
    type: Boolean
}]);

console.log(colors.bgGrey(colors.black(`                            \n  ZOIA Installation Script  \n                            \n`)));
console.log(`${colors.cyan("Version")}: ${colors.brightWhite(packageJson.version)}\n`);

if (!Object.keys(options).length || (!options.module && !options.all)) {
    console.log(`   Usage: ${colors.brightWhite("npm run setup -- [--all] [--module name] [--defaults]")}\n\n          --all (-a): install all modules\n          --module (-m): install specified module\n          --defaults (-d): install default(s) for specified module(s)\n\nExamples: ${colors.brightWhite("npm run setup -- -ad")} (install all modules and defaults)\n          ${colors.brightWhite(`npm run setup -- --module ${colors.grey("users")} --defaults`)} (install "users" module and its defaults)\n`);
    process.exit(0);
}

let config;
let modules;
try {
    config = {
        ...fs.readJSONSync(path.resolve(`${__dirname}/../../etc/system.json`)),
        ...fs.readJSONSync(path.resolve(`${__dirname}/../../etc/zoia.json`))
    };
} catch {
    console.log(colors.brightRed("Fatal: could not load etc/system.json or etc/zoia.json"));
    console.log(colors.grey(`Please run the following command to generate the configuration file: npm run config\n`));
    process.exit(1);
}
try {
    modules = fs.readJSONSync(path.resolve(`${__dirname}/../../build/etc/modules.json`)).filter(m => options.module ? m.id === options.module : true);
} catch {
    console.log(colors.brightRed("Fatal: could not load build/etc/modules.json"));
    console.log(colors.grey(`Please run the following command to generate the configuration file: npm run build-production\n`));
    process.exit(1);
}
const languages = Object.keys(config.languages);

console.log(colors.yellow(`Installing modules: ${modules.map(m => m.id).join(", ")}${options.defaults ? " (including defaults)" : ""}\n`));

(async () => {
    try {
        console.log("* Connecting to the database");
        const mongoClient = new MongoClient(config.mongo.url, config.mongo.options || {
            useUnifiedTopology: true,
            connectTimeoutMS: 5000,
            keepAlive: true,
            useNewUrlParser: true
        });
        await mongoClient.connect();
        const db = mongoClient.db(config.mongo.dbName);
        console.log("* Connected.");
        for (const m of modules) {
            try {
                const moduleDir = m.parentModule ? `${m.parentModule}/${m.id}` : m.id;
                console.log(colors.cyan(`\nInstalling module: ${colors.brightWhite(m.id)}\n`));
                console.log(`* Loading configuration file: ${fs.existsSync(path.resolve(`${__dirname}/../../etc/modules/$moduleDir}.json`)) ? `../../etc/modules/${m.id}.json` : `../../src/modules/${moduleDir}/config.dist.json`}`);
                const moduleConfig = fs.existsSync(path.resolve(`${__dirname}/../../etc/modules/${m.id}.json`)) ? require(path.resolve(`${__dirname}/../../etc/modules/${m.id}.json`)) : require(path.resolve(`${__dirname}/../../src/modules/${moduleDir}/config.dist.json`));
                console.log(`* Configuration file loaded.`);
                // Process database routines
                if (moduleConfig.database) {
                    console.log(`* Processing database collections`);
                    const collections = Object.keys(moduleConfig.database.collections);
                    for (const c of collections) {
                        try {
                            console.log(`* Creating collection: "${c}"`);
                            try {
                                await db.createCollection(c);
                            } catch {
                                // Ignore
                            }
                            const {
                                indexesAsc,
                                indexesDesc,
                                expires,
                                expireField,
                            } = moduleConfig.database.collections[c];
                            if (indexesAsc && indexesAsc.length) {
                                const indexes = {};
                                indexesAsc.map(i => {
                                    if (i.match(/\[language\]/i)) {
                                        languages.map(language => {
                                            const index = i.replace(/\[language\]/i, language);
                                            indexes[index] = 1;
                                        });
                                    } else {
                                        indexes[i] = 1;
                                    }
                                });
                                console.log(`* Dropping indexes: "${m.id}_${c}_asc"`);
                                try {
                                    await db.collection(c).dropIndex(`${m.id}_${c}_asc`);
                                } catch (e) {
                                    console.log(`  Warning: ${e.message}`);
                                    // Ignore
                                }
                                console.log(`* Creating indexes: "${m.id}_${c}_asc"`);
                                try {
                                    await db.collection(c).createIndex(indexes, {
                                        name: `${m.id}_${c}_asc`
                                    });
                                } catch (e) {
                                    console.log(`  Failed: ${e.message}`);
                                    // Ignore
                                }
                            }
                            if (indexesDesc && indexesDesc.length) {
                                const indexes = {};
                                indexesDesc.map(i => {
                                    if (i.match(/\[language\]/i)) {
                                        languages.map(language => {
                                            const index = i.replace(/\[language\]/i, language);
                                            indexes[index] = -1;
                                        });
                                    } else {
                                        indexes[i] = -1;
                                    }
                                });
                                console.log(`* Dropping indexes: "${m.id}_${c}_desc"`);
                                try {
                                    await db.collection(c).dropIndex(`${m.id}_${c}_desc`);
                                } catch (e) {
                                    console.log(`  Warning: ${e.message}`);
                                    // Ignore
                                }
                                console.log(`* Creating indexes: "${m.id}_${c}_desc"`);
                                try {
                                    await db.collection(c).createIndex(indexes, {
                                        name: `${m.id}_${c}_desc`
                                    });
                                } catch (e) {
                                    console.log(`  Failed: ${e.message}`);
                                    // Ignore
                                }
                            }
                            if (expires) {
                                console.log(`* Dropping indexes: "${m.id}_${c}_exp"`);
                                try {
                                    await db.collection(c).dropIndex(`${m.id}_${c}_exp`);
                                } catch (e) {
                                    console.log(`  Warning: ${e.message}`);
                                    // Ignore
                                }
                                console.log(`* Creating indexes: "${m.id}_${c}_exp"`);
                                const expData = {};
                                if (expireField) {
                                    expData[expireField] = 1;
                                } else {
                                    expData.createdAt = 1;
                                }
                                try {
                                    await db.collection(c).createIndex(expData, {
                                        expireAfterSeconds: parseInt(expires, 10),
                                        name: `${m.id}_${c}_exp`,
                                    });
                                } catch (e) {
                                    console.log(`  Failed: ${e.message}`);
                                    // Ignore
                                }
                            }
                        } catch (e) {
                            console.error(e);
                        }
                    }
                }
                if (options.defaults && moduleConfig.setup) {
                    console.log(`* Running setup script (../../build/scripts/${m.id}.js)`);
                    try {
                        const setupScript = require(path.resolve(`${__dirname}/../../build/scripts/${m.id}.js`));
                        await setupScript(config, moduleConfig, db);
                    } catch (e) {
                        console.error(e);
                    }
                    console.log(`* Script execution complete`);
                }
            } catch (e) {
                console.error(e);
            }
        }
        console.log("* Closing database connection");
        mongoClient.close();
        console.log(colors.green("\nDone."));
    } catch (e) {
        console.error(` Fatal: ${colors.brightRed(e.message)}`);
        process.exit(1);
    }
})();
