|
/** |
|
* Clones a project in its entirety to a local install. |
|
* |
|
* Run this using |
|
|
|
NODE_CONFIG='{ |
|
"oss": true, |
|
"src": "mongodb://localhost:27017/formio", |
|
"dst": "mongodb://localhost:27017/cloned", |
|
"project": "61051ac21bbda812c36dcbe8" |
|
}' node cloneproject.js |
|
|
|
*/ |
|
const config = require('config'); |
|
const fs = require('fs'); |
|
const { MongoClient, ServerApiVersion, ObjectId } = require('mongodb'); |
|
const icons = { |
|
projects: '|', |
|
forms: '+', |
|
submissions: '.', |
|
}; |
|
|
|
// Get the cloneState and ensure we save it on exit. |
|
let cloneState = {}; |
|
try { |
|
cloneState = JSON.parse(fs.readFileSync('clonestate.json', 'utf8')); |
|
} |
|
catch (e) { |
|
cloneState = {}; |
|
console.log('No clonestate.json file found.'); |
|
} |
|
|
|
process.on('exit', () => { |
|
fs.writeFileSync('clonestate.json', JSON.stringify(cloneState, null, 2)); |
|
}); |
|
|
|
async function connectDb(uri) { |
|
const client = new MongoClient(uri, { |
|
serverApi: { |
|
version: ServerApiVersion.v1, |
|
strict: true, |
|
deprecationErrors: true, |
|
} |
|
}); |
|
await client.connect(); |
|
return await client.db(); |
|
}; |
|
|
|
(async () => { |
|
const srcDb = await connectDb(config.src); |
|
const src = { |
|
db: srcDb, |
|
projects: srcDb.collection('projects'), |
|
forms: srcDb.collection('forms'), |
|
submissions: srcDb.collection('submissions'), |
|
submissionrevisions: srcDb.collection('submissionrevisions'), |
|
roles: srcDb.collection('roles'), |
|
actions: srcDb.collection('actions'), |
|
formrevisions: srcDb.collection('formrevisions'), |
|
tags: srcDb.collection('tags') |
|
}; |
|
|
|
const destDb = await connectDb(config.dst); |
|
const dest = { |
|
db: destDb, |
|
projects: destDb.collection('projects'), |
|
forms: destDb.collection('forms'), |
|
submissions: destDb.collection('submissions'), |
|
submissionrevisions: destDb.collection('submissionrevisions'), |
|
roles: destDb.collection('roles'), |
|
actions: destDb.collection('actions'), |
|
formrevisions: destDb.collection('formrevisions'), |
|
tags: destDb.collection('tags') |
|
}; |
|
|
|
// Load the admin user. |
|
const admin = await dest.submissions.findOne({}); |
|
|
|
// Upsert. |
|
const upsertAll = async function(collection, query, beforeEach, afterEach) { |
|
if (!query._id && cloneState[collection]) { |
|
query.created = {$gt: new Date(cloneState[collection])}; |
|
} |
|
const ossProject = (collection === 'projects' && config.oss); |
|
const dbCollection = ossProject ? dest[collection] : src[collection]; |
|
const cursor = dbCollection.find(query).sort({created: 1}); |
|
while (await cursor.hasNext()) { |
|
const item = await cursor.next(); |
|
if (!ossProject) { |
|
item.owner = admin._id; |
|
} |
|
if (beforeEach) { |
|
await beforeEach(item); |
|
} |
|
if (icons.hasOwnProperty(collection)) { |
|
process.stdout.write(icons[collection]); |
|
} |
|
if (!ossProject) { |
|
await dest[collection].updateOne({_id: item._id}, {$set: item}, {upsert: true}); |
|
} |
|
try { |
|
cloneState[collection] = (new Date(item.created)).toISOString(); |
|
} |
|
catch (err) { |
|
// Do nothing. |
|
} |
|
if (afterEach) { |
|
await afterEach(item); |
|
} |
|
} |
|
delete cloneState[collection]; |
|
}; |
|
|
|
// Upsert everything. |
|
await upsertAll('projects', {_id: new ObjectId(config.project)}, null, async (project) => { |
|
const setProject = async (item) => { |
|
item.project = project._id; |
|
}; |
|
const itemQuery = (query) => { |
|
if (!config.oss) { |
|
query.project = project._id; |
|
} |
|
return query; |
|
}; |
|
|
|
await upsertAll('forms', itemQuery({deleted: {$eq: null}}), setProject, async (form) => { |
|
await upsertAll('submissions', {form: form._id, deleted: {$eq: null}}, setProject, async (submission) => { |
|
await upsertAll('submissionrevisions', {_rid: submission._id}); |
|
}); |
|
await upsertAll('actions', {form: form._id, deleted: {$eq: null}}, setProject); |
|
await upsertAll('formrevisions', {_rid: form._id, deleted: {$eq: null}}, setProject); |
|
}); |
|
await upsertAll('roles', itemQuery({deleted: {$eq: null}}), setProject); |
|
await upsertAll('tags', itemQuery({deleted: {$eq: null}}), setProject); |
|
}); |
|
|
|
try { |
|
fs.rmSync('clonestate.json'); |
|
} |
|
catch(err) { |
|
// Do nothing. |
|
} |
|
|
|
// We are done. |
|
console.log('DONE!'); |
|
})(); |