Skip to content

Instantly share code, notes, and snippets.

@randallknutson
Forked from zackurben/gist:1f2df3092e3547a199e0
Last active August 29, 2015 14:25
Show Gist options
  • Save randallknutson/534b256fb40e9351c433 to your computer and use it in GitHub Desktop.
Save randallknutson/534b256fb40e9351c433 to your computer and use it in GitHub Desktop.
Update formio database to version 1.0.0
/**
* Simple utility function to resize an array after elements have been removed.
*
* @param arr
* The array to resize.
* @returns {Array}
*/
var resizeArray = function(arr) {
if (!(arr instanceof Array)) {
return [];
}
var ret = [];
arr.forEach(function(element) {
if (typeof element !== 'undefined') {
ret.push(element);
}
});
return ret;
};
/**
* Update the collections in mongo.
*/
var updateMongo = function() {
db.schema.createIndex({key: 1});
db.applications.update({}, {$set: {owner: null}}, {multi: true});
db.applications.createIndex({owner: 1});
db.applications.update({}, {$set: {defaultAccess: null}}, {multi: true});
db.createCollection('roles');
db.roles.createIndex({app: 1});
db.forms.update({}, {$set: {submissionAccess: []}}, {multi: true});
db.forms.update({}, {$set: {owner: null}}, {multi: true});
db.forms.createIndex({owner: 1});
db.submissions.update({}, {$set: {owner: null}}, {multi: true});
db.submissions.createIndex({owner: 1});
db.submissions.update({}, {$set: {roles: []}}, {multi: true});
db.submissions.createIndex({roles: 1});
};
/**
* Delete major orphan entities.
*/
var pruneMongo = function() {
// Prune orphan forms.
db.forms.find().forEach(function(form) {
var app = db.applications.findOne({_id: form.app});
if (!app) {
// remove all forms associated with deleted applications.
db.forms.remove({app: form.app});
// remove all submissions associated with deleted applications and forms.
db.submissions.remove({form: form._id});
// remove all actions associated with deleted applications.
db.actions.remove({form: form._id});
}
});
// Prune orphan submissions.
db.submissions.find().forEach(function(submission) {
var form = db.forms.findOne({_id: submission.form});
if (!form) {
// remove all submissions associated with a deleted form.
db.submissions.remove({form: submission.form});
// remove all actions associated with a deleted form.
db.actions.remove({form: submission.form});
}
});
// Prune orphan form actions.
db.actions.find().forEach(function(action) {
var form = db.forms.findOne({_id: action.form});
if (!form) {
// remove all actions associated with a deleted form.
db.actions.remove({form: action.form});
// remove all submissions associated with a deleted form.
db.actions.remove({form: action.form});
}
});
};
/**
* Update the Application Model.
*/
var updateApplications = function() {
var applications = db.applications.find();
applications.forEach(function(application) {
// For each application, create 3 roles: Administrator, Authenticated, and Anonymous.
db.roles.insert({title: 'Administrator', description: 'The Administrator Role.', app: application._id});
db.roles.insert({title: 'Authenticated', description: 'The Authenticated Role.', app: application._id});
db.roles.insert({title: 'Anonymous', description: 'The Anonymous Role.', app: application._id});
// Query the application roles.
var anonymous = db.roles.findOne({app: application._id, title: 'Anonymous'});
var authenticated = db.roles.findOne({app: application._id, title: 'Authenticated'});
var administrator = db.roles.findOne({app: application._id, title: 'Administrator'});
// Assign the application owner.
var access = application.access;
if (access.length === 1) {
// Assign the only person defined to have access, as the owner.
application.owner = access[0].id;
}
else if (access.length === 2) {
// Give application ownership to the user who is not travist.
access.forEach(function(user) {
if (user.id.valueOf() !== '553dbfc08d22d5cb1a7024f2') {
application.owner = user.id;
}
});
}
else {
application.owner = null;
}
// Assign the anonymous role to the applications defaultAccess role
application.defaultAccess = anonymous._id;
// Give all known roles access to view the application, and admins the ability to update it.
application.access = [
{type: 'read_all', roles: [anonymous._id, authenticated._id, administrator._id]},
{type: 'update_all', roles: [administrator._id]}
];
// Save the updated application to the db.
db.applications.update({_id: application._id}, application);
});
};
/**
* Update the Form Model.
*/
var updateForms = function() {
var forms = db.forms.find();
forms.forEach(function(form) {
// confirm each form references a valid application
// Fix forms without access defined - db.forms.find({'access.0': {$exists: false}});
var access = form.hasOwnProperty('access')
? form.access
: [];
// Determine if anonymous has access to this form.
var anonymousAccess = false;
if (access.length > 0) {
for (var i in access) {
if (access[i].id && access[i].id.valueOf() === '000000000000000000000000') {
// Acknowledge anonymous access and remove it from the array.
anonymousAccess = true;
delete access[i];
}
}
// Remove any anonymous elements
access = resizeArray(access);
}
// Assign the owner of the form based on the remaining users with access.
switch (access.length) {
case 1:
// Assign the only person defined to have access, as the owner.
form.owner = access[0].id;
break;
case 2:
// Give application ownership to the user who is not travist.
access.forEach(function(user) {
if (user.id.valueOf() !== '553dbfc08d22d5cb1a7024f2') {
form.owner = user.id;
}
});
break;
default:
form.owner = null;
break;
}
// Update the form access variables.
form.access = [];
form.submissionAccess = [];
// If anonymous access is defined, attach the anonymous access to the form.
if (anonymousAccess) {
// query the application for its default role.
var application = db.applications.findOne({_id: form.app});
// Give the applications defaultAccess role (Anonymous) read access to the form.
form.access.push({type: 'read_all', roles: [application.defaultAccess]});
// Grant the Anonymous user CRUD access to submissions.
form.submissionAccess.push(
{type: 'create_own', roles: [application.defaultAccess]},
{type: 'read_own', roles: [application.defaultAccess]},
{type: 'update_own', roles: [application.defaultAccess]},
{type: 'delete_own', roles: [application.defaultAccess]}
);
}
// If other users are present attach the authenticated roles.
if (access.length > 0) {
var authenticated = db.roles.findOne({app: form.app, title: 'Authenticated'});
// Iterate each role and add the authenticated role to the read_all permission.
var done = false;
form.access.forEach(function(element) {
if (element.type === 'read_all') {
done = true;
element.roles.push(authenticated._id);
}
});
// If the read_all permission was not defined for anonymous, add it for authenticated users.
if (!done) {
form.access.push({type: 'read_all', roles: [authenticated._id]});
}
// Give authenticated users crud permissions for their own resources.
if (form.submissionAccess.length > 0) {
form.submissionAccess.forEach(function(element) {
// Ensure only CRUD _own roles are updated.
switch (element.type) {
case 'create_own':
case 'read_own':
case 'update_own':
case 'delete_own':
element.roles.push(authenticated._id);
break;
}
});
}
else {
form.submissionAccess.push(
{type: 'create_own', roles: [authenticated._id]},
{type: 'read_own', roles: [authenticated._id]},
{type: 'update_own', roles: [authenticated._id]},
{type: 'delete_own', roles: [authenticated._id]}
);
}
}
// Add the admin role to the form permissions regardless of access contents..
var administrator = db.roles.findOne({app: form.app, title: 'Administrator'});
// Add the admin role to the CRUD _all permission of the form.
form.access.forEach(function(element) {
element.roles.push(administrator._id);
});
// Add the admin role to the remaining CRUD operations of the form.
form.access.push(
{type: 'update_all', roles: [administrator._id]},
{type: 'delete_all', roles: [administrator._id]}
);
// Give admin users crud permissions for all submissions.
form.submissionAccess.push(
{type: 'create_all', roles: [administrator._id]},
{type: 'read_all', roles: [administrator._id]},
{type: 'update_all', roles: [administrator._id]},
{type: 'delete_all', roles: [administrator._id]}
);
// Update this form to reflect schema changes.
db.forms.update({_id: form._id}, form);
});
};
/**
* Update the Submission Model.
*/
var updateSubmission = function() {
var submissions = db.submissions.find();
submissions.forEach(function(submission) {
var access = submission.access;
var form = db.forms.findOne({_id: submission.form});
var application = db.applications.findOne({_id: form.app});
submission.owner = null;
// Store the two submission id's that cant be the owner.
var travist = '553dbfc08d22d5cb1a7024f2';
var owner = application.owner
? application.owner.valueOf()
: null;
// Attempt to update the owner of the submission.
switch (access.length) {
case 1:
// Assign the only person in the access array to the owner, if they arent travist or the application owner.
submission.owner = ((access[0].id.valueOf() !== travist) && (access[0].id.valueOf() !== owner))
? access[0].id
: null;
break;
case 2:
// Iterate the access list to find the first person who isnt travist or the application owner.
access.forEach(function(user) {
// Give application ownership to the user who is not travist or the application owner.
if ((user.id.valueOf() !== travist) && (user.id.valueOf() !== owner)) {
submission.owner = user.id;
}
});
break;
}
// Attach the applications authenticated role to every existing submission.
var authenticated = db.roles.findOne({app: application._id, title: 'Authenticated'});
submission.roles = [authenticated._id];
// Update this submission to reflect schema changes.
db.submissions.update({_id: submission._id}, submission);
});
};
// Invoke all the update methods..
updateMongo();
pruneMongo();
updateApplications();
updateForms();
updateSubmission();
/**
* Remove and update all mongo collections once old data is no longer needed.
*/
var finalizeMongoChanges = function() {
// Finalize the submissions collection by deleting the access field.
db.submissions.update({access: {$exists: true}}, {$unset: {access: 1}}, {multi: true});
};
// Clean up the mongo collections
finalizeMongoChanges();
/**
* Confirm the integrity of every application.
*/
var confirmApplicationUpdate = function() {
// Every application should have an owner
db.applications.find({'owner': {$exists: false}});
// Every application should have a non-empty access list.
db.applications.find({$or: [
{'access': {$exists: false}},
{'access.0': {$exists: false}}
]});
// Every application should have a defaultAccess id
db.applications.find({'defaultAccess': {$exists: false}});
};
/**
* Confirm the integrity of every form.
*/
var confirmFormUpdate = function() {
// Every form should have an owner
db.forms.find({'owner': {$exists: false}});
// Every form should have a non-empty access list.
db.forms.find({$or: [
{'access': {$exists: false}},
{'access.0': {$exists: false}}
]});
// Every application should have submissionAccess defined
db.forms.find({$or: [
{'submissionAccess': {$exists: false}},
{'submissionAccess.0': {$exists: false}}
]});
};
/**
* Confirm the integrity of every submission.
*/
var confirmSubmissionUpdate = function() {
// Every submission should have an owner, possibly null.
db.submissions.find({'owner': {$exists: false}});
// Every submission should have roles, possibly null.
db.submissions.find({'roles': {$exists: false}});
};
confirmApplicationUpdate();
confirmFormUpdate();
confirmSubmissionUpdate();
db.schema.update({}, { $set: { "version": "1.0.0" }});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment