Skip to content

Instantly share code, notes, and snippets.

@hannahwhy
Created July 26, 2012 04:02
Show Gist options
  • Select an option

  • Save hannahwhy/3180173 to your computer and use it in GitHub Desktop.

Select an option

Save hannahwhy/3180173 to your computer and use it in GitHub Desktop.
// this is set to validation/helpers
(function (ex) {
var knownTypes = [
'event',
'profile',
'source_resolution',
'video'
];
ex.isKnownType = function (type) {
return knownTypes.indexOf(type) !== -1;
};
ex.userHasRole = function (userCtx) {
return function (role) {
return userCtx.roles.indexOf(role) !== -1;
}
};
ex.userIn = function (userCtx) {
return function (list) {
return list && list.indexOf(userCtx.name) !== -1;
}
};
ex.enforce = function (cond, message) {
if (!cond) {
throw({forbidden: message});
}
};
ex.notBlank = function (str) {
return str && str.trim() !== '';
};
ex.abort = function () {
throw({forbidden: 'Permission denied.'});
};
return ex;
})(exports);
function (newDoc, oldDoc, userCtx, secObj) {
var libs = require('validation/helpers'),
isDeletion = newDoc['_deleted'],
isKnownType = libs.isKnownType,
enforce = libs.enforce,
notBlank = libs.notBlank,
userIn = libs.userIn(userCtx),
userHasRole = libs.userHasRole(userCtx),
isMember = userHasRole('member'),
abort = libs.abort,
ok;
// If this is a deletion, carry out the deletion rules.
if (isDeletion) {
switch (oldDoc['type']) {
case 'event':
// Events can only be deleted by their organizers.
ok = userIn(oldDoc['organizers']);
enforce(ok, 'You cannot delete events you do not organize.');
break;
case 'profile':
// Profiles can only be deleted by their owners.
ok = oldDoc['username'] === userCtx.name;
enforce(ok, "You cannot delete another user's profile.");
break;
case 'source_resolution':
// Only source resolvers can delete resolution documents.
ok = userHasRole('source_resolver');
enforce(ok, 'You cannot delete resolution documents.');
break;
case 'video':
// Videos can only be deleted by their owners or video DB admins.
ok = userIn(oldDoc['owners']) || userHasRole('video_db_admin');
enforce(ok, 'You cannot delete videos you do not own.');
break;
default:
abort();
break;
}
// At this point, everything's go for deletion. The rest of this function
// has to do with non-deletion updates, so we can return.
return;
}
// Okay, this isn't a deletion. In that case, the document's type must in
// the whitelist.
if (!isDeletion) {
enforce(isKnownType(newDoc['type']), 'Invalid type.');
}
// Also, a document's type cannot change once it has been set.
if (oldDoc) {
enforce(oldDoc['type'] === newDoc['type'],
'Document types cannot change once they are set.');
}
// OK, now we know we have a valid type, it hasn't changed, and we're
// updating a document.
// Each type has its own validation rules. We implement them below.
switch (newDoc['type']) {
case 'event':
// A user must be a member to create or update events.
enforce(isMember, 'You must be a site member to add or update events.');
// If the event already exists, the member must be an organizer of the
// event to change it.
if (oldDoc) {
enforce(userIn(oldDoc['organizers']),
'You must be an organizer of the event to update it.');
}
// The member entering the event must take ownership of the event.
enforce(userIn(newDoc['organizers']),
'You must claim ownership of your event.');
// The event's name must not be blank.
enforce(notBlank(newDoc['name']), 'Events must have a name.');
break;
case 'profile':
// A user must be a member to create or update profiles.
enforce(isMember,
'You must be a site member to add or update profiles.');
// A member can only update their own profile.
enforce(newDoc['username'] === userCtx.name,
"You cannot edit other editor's profiles.");
break;
case 'source_resolution':
// Only source resolvers may create or update resolution records.
enforce(userHasRole('source_resolver'),
'Only source resolvers may add or update resolution records.');
break;
case 'video':
// If the user is a video database admin, skip further checks.
if (userHasRole('video_db_admin')) {
return;
}
// Otherwise, continue with the checks.
// A user must be a member to create or update profiles.
enforce(isMember,
'You must be a site member to add or update videos.');
// If the video already exists, the member must be an organizer of the
// video to change it.
if (oldDoc) {
enforce(userIn(oldDoc['owners']),
'You must be an owner of the video to update it.');
}
// The member entering the video must take ownership of the video.
enforce(userIn(newDoc['owners']),
'You must claim ownership of your video.');
// A video must have a title.
enforce(notBlank(newDoc['title']), 'Videos must have a title.');
break;
default:
abort();
break;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment