/* global Migrations */ /* eslint-disable import/no-absolute-path */ /* eslint-disable no-await-in-loop, no-restricted-syntax */ import { Meteor } from 'meteor/meteor'; import Comments from '/imports/api/Comments/Comments'; import { Accounts } from 'meteor/accounts-base'; import randomHex from 'crypto-random-hex'; import UserSubsToFiresCollection from '/imports/api/Subscriptions/Subscriptions'; import FireAlertsCollection from '/imports/api/FireAlerts/FireAlerts'; import SiteSettings from '/imports/api/SiteSettings/SiteSettings'; import FalsePositives from '/imports/api/FalsePositives/FalsePositives'; import Industries from '/imports/api/Industries/Industries'; import IndustryRegistries from '/imports/api/Industries/IndustryRegistries'; import Notifications from '/imports/api/Notifications/Notifications'; import ActiveFiresUnion from '/imports/api/ActiveFiresUnion/ActiveFiresUnion'; import { Mongo } from 'meteor/mongo'; Meteor.startup(async () => { // https://github.com/percolatestudio/meteor-migrations Migrations.config({ // Log job run details to console log: Meteor.isProduction }); Migrations.add({ version: 1, up: async function migrateIds() { // https://docs.mongodb.com/manual/reference/operator/query/type/ const users = await Meteor.users.find({ _id: { $type: 7 } }).fetchAsync(); for (const user of users) { const migratedUser = user; const id = user._id.valueOf(); console.log(`Migrating id of user: ${JSON.stringify(user)}`); await Meteor.users.removeAsync({ _id: user._id }); migratedUser._id = id; await Meteor.users.insertAsync(migratedUser); } } }); Migrations.add({ version: 2, up: async function migrateSubsForeignKey() { const subs = await UserSubsToFiresCollection.find({ owner: null }).fetchAsync(); for (const sub of subs) { console.log(`Migrating subs of chatId: ${sub.chatId}`); const subsUser = await Meteor.users.findOneAsync({ telegramChatId: sub.chatId }); if (subsUser) { console.log(`Migrating linking to user: ${JSON.stringify(subsUser)}`); await UserSubsToFiresCollection.updateAsync({ _id: sub._id }, { $set: { owner: subsUser._id } }); } else { // create user with chatId and def language const username = `tel${sub.chatId.toString().replace(/^-/, '')}`; console.log(`Linking to new user: ${username}`); const newUserId = await Accounts.createUserAsync({ username, password: randomHex(50), profile: { name: {} } }); await Meteor.users.updateAsync({ _id: newUserId }, { $set: { emails: [], roles: ['user'], telegramChatId: sub.chatId, lang: 'es' } }); await UserSubsToFiresCollection.updateAsync({ _id: sub._id }, { $set: { owner: newUserId } }); } } } }); Migrations.add({ version: 3, up: async function emptySubsTypes() { const subs = await UserSubsToFiresCollection.find({ type: null }).fetchAsync(); for (const sub of subs) { await UserSubsToFiresCollection.updateAsync({ _id: sub._id }, { $set: { type: 'telegram' } }); } } }); Migrations.add({ version: 4, up: async function deleteOldAlertFiresAndIndexes() { await FireAlertsCollection.removeAsync({ createdAd: null }); const raw = FireAlertsCollection.rawCollection(); await raw.createIndex({ ourid: '2dsphere' }); await raw.createIndex({ when: 1 }); await raw.createIndex({ updatedAt: 1 }); await raw.createIndex({ createdAt: 1 }); await raw.createIndex({ ourid: 1, type: 1 }); } }); Migrations.add({ version: 5, up: async function siteSettingsIndex() { // other way: await SiteSettings.createIndexAsync({ name: 1 }, { unique: true }); } }); Migrations.add({ version: 6, up: async function falsePositiveIndexes() { await FalsePositives.createIndexAsync({ chatId: 1 }); await FalsePositives.createIndexAsync({ owner: 1 }); await FalsePositives.createIndexAsync({ fireId: 1 }); await FalsePositives.createIndexAsync({ type: 1 }); await FalsePositives.createIndexAsync({ geo: '2dsphere' }); } }); Migrations.add({ version: 7, up: async function defLangIfNull() { const users = await Meteor.users.find({ lang: null }).fetchAsync(); for (const user of users) { await Meteor.users.updateAsync({ _id: user._id }, { $set: { lang: 'es' } }); } } }); Migrations.add({ version: 8, up: async function siteSettingsAddIndex() { await SiteSettings.createIndexAsync({ isPublic: 1 }); const settings = await SiteSettings.find({ isPublic: null }).fetchAsync(); for (const setting of settings) { await SiteSettings.updateAsync({ _id: setting._id }, { $set: { isPublic: true } }); } } }); Migrations.add({ version: 9, up: async function industriesIndexesAndRegistries() { await Industries.createIndexAsync({ registry: 1 }); await Industries.createIndexAsync({ geo: '2dsphere' }); // https://www.eea.europa.eu/data-and-maps/data/member-states-reporting-art-7-under-the-european-pollutant-release-and-transfer-register-e-prtr-regulation-16 await IndustryRegistries.insertAsync({ _id: '1', name: 'E-PRTR', agency: 'EEA', region: 'EU' }); // https://www.epa.gov/enviro/epa-frs-facilities-state-single-file-csv-download await IndustryRegistries.insertAsync({ _id: '2', name: 'FRS', agency: 'EPA', region: 'US' }); } }); Migrations.add({ version: 10, up: async function moreIndustryRegistries() { await IndustryRegistries.insertAsync({ _id: '3', name: 'NPRI', agency: 'GCODP', region: 'Canada' }); await IndustryRegistries.insertAsync({ _id: '4', name: 'NPI', agency: 'DEE', region: 'Australia' }); } }); Migrations.add({ version: 11, up: async function noAnonComments() { await Comments.removeAsync({ isAnonymous: true }); } }); Migrations.add({ version: 12, up: async function setTelegramUsersBotId() { await Meteor.users.updateAsync({ telegramChatId: { $ne: null }, telegramBot: null }, { $set: { telegramBot: 'es' } }, { multi: true }); } }); Migrations.add({ version: 13, up: async function removeTelegramBotFromUsersId() { await Meteor.users.updateAsync({}, { $unset: { telegramBot: '' } }, { multi: true }); } }); Migrations.add({ version: 14, up: async function setTelegramSubsBotId() { await UserSubsToFiresCollection.updateAsync({ chatId: { $ne: null }, telegramBot: null }, { $set: { telegramBot: 'es' } }, { multi: true }); } }); Migrations.add({ version: 15, up: async function moveToFalsePositivesUppercase() { /* const falsepositiveslower = new Mongo.Collection('falsepositives', { idGeneration: 'MONGO' }); * falsepositiveslower.find({}).forEach((falseDoc) => { * FalsePositives.insert(falseDoc); * }); */ // TODO remove falsepositives lowercase collection } }); Migrations.add({ version: 16, up: async function moveToFalsePositivesUppercaseWithUser() { const falsepositiveslower = new Mongo.Collection('falsepositives', { idGeneration: 'MONGO' }); const now = new Date(); const falseDocs = await falsepositiveslower.find({}).fetchAsync(); for (const falseDoc of falseDocs) { const user = await Meteor.users.findOneAsync({ telegramChatId: falseDoc.chatId }); if (user) { falseDoc.owner = user._id; } falseDoc.type = 'industry'; falseDoc.createdAt = now; falseDoc.updatedAt = now; await FalsePositives.insertAsync(falseDoc); } } }); Migrations.add({ version: 17, up: async function renameWebNotifiedField() { await Notifications.updateAsync({ webNotified: { $exists: true } }, { $rename: { webNotifiedAt: 'notifiedAt' } }, { upsert: false, multi: true }); await Notifications.updateAsync({ webNotified: { $exists: true } }, { $rename: { webNotified: 'notified' } }, { upsert: false, multi: true }); } }); Migrations.add({ version: 18, up: async () => { const raw = ActiveFiresUnion.rawCollection(); await raw.createIndex({ centerid: '2dsphere' }); await raw.createIndex({ shape: '2dsphere' }); await raw.createIndex({ when: 1 }); await raw.createIndex({ createdAt: 1 }); await raw.createIndex({ updatedAt: 1 }); } }); // Meteor 3: migrateTo is async and awaits each async up(), so a fresh DB can // migrate from 0 to latest without pre-marking the control version. await Migrations.migrateTo('latest'); // Migrations.migrateTo('14,rerun'); });