formio
Version:
The formio server application.
1,169 lines (970 loc) • 454 kB
JavaScript
/* eslint-env mocha */
'use strict';
const request = require('./formio-supertest');
var assert = require('assert');
var async = require('async');
var _ = require('lodash');
var docker = process.env.DOCKER;
// Request a 401.
var request401 = function(request, done, user) {
if (user) {
request.set('x-jwt-token', user.token);
}
request
.expect(401)
.expect('Content-Type', /text\/plain/)
.end(function(err, res) {
if (err) {
return done(err);
}
assert.equal(res.text, 'Unauthorized');
if (user) {
// Store the JWT for future API calls.
user.token = res.headers['x-jwt-token'];
}
done();
}
);
};
module.exports = function(app, template, hook) {
var Helper = require('./helper')(app);
describe('Submissions', function() {
describe('Submission Level Permissions (Project Owner)', function() {
describe('Submission CRUD', function() {
// Store the temp form for this test suite.
var tempForm = {
title: 'Project owner access check',
name: 'access',
path: 'accessowner',
type: 'form',
access: [],
submissionAccess: [],
components: [
{
type: 'textfield',
validate: {
custom: '',
pattern: '',
maxLength: '',
minLength: '',
required: false
},
defaultValue: '',
multiple: false,
suffix: '',
prefix: '',
placeholder: 'value',
key: 'value',
label: 'value',
inputMask: '',
inputType: 'text',
input: true
}
]
};
// Store the temp submission for this test suite.
var tempSubmission = {data: {value: 'foo'}};
var tempSubmissions = [];
describe('Bootstrap', function() {
it('Create a Form for a Submission level Access Check - Project Owner', function(done) {
request(app)
.post(hook.alter('url', '/form', template))
.set('x-jwt-token', template.users.admin.token)
.send(tempForm)
.expect('Content-Type', /json/)
.expect(201)
.end(function(err, res) {
if (err) {
return done(err);
}
var response = res.body;
assert(response.hasOwnProperty('_id'), 'The response should contain an `_id`.');
assert(response.hasOwnProperty('modified'), 'The response should contain a `modified` timestamp.');
assert(response.hasOwnProperty('created'), 'The response should contain a `created` timestamp.');
assert(response.hasOwnProperty('access'), 'The response should contain an the `access`.');
assert.equal(response.title, tempForm.title);
assert.equal(response.name, tempForm.name);
assert.equal(response.path, tempForm.path);
assert.equal(response.type, 'form');
assert.equal(response.access.length, 1);
assert.equal(response.access[0].type, 'read_all');
assert.equal(response.access[0].roles.length, 3);
assert.notEqual(response.access[0].roles.indexOf(template.roles.anonymous._id.toString()), -1);
assert.notEqual(response.access[0].roles.indexOf(template.roles.authenticated._id.toString()), -1);
assert.notEqual(response.access[0].roles.indexOf(template.roles.administrator._id.toString()), -1);
assert.deepEqual(response.submissionAccess, []);
assert.deepEqual(response.components, tempForm.components);
tempForm = response;
// Store the JWT for future API calls.
template.users.admin.token = res.headers['x-jwt-token'];
done();
});
});
});
describe('Project Owner Submission - Delete all submissions', function() {
var deleteTest = {data: {value: 'foo'}};
it('The Project Owner should be able to Create a submission without explicit permissions using the Form alias', function(done) {
request(app)
.post(hook.alter('url', '/' + tempForm.path + '/submission', template))
.set('x-jwt-token', template.users.admin.token)
.send(deleteTest)
.expect(201)
.expect('Content-Type', /json/)
.end(function(err, res) {
if (err) {
return done(err);
}
var response = res.body;
assert(response.hasOwnProperty('_id'), 'The response should contain an `_id`.');
assert(response.hasOwnProperty('modified'), 'The response should contain a `modified` timestamp.');
assert(response.hasOwnProperty('created'), 'The response should contain a `created` timestamp.');
assert(response.hasOwnProperty('data'), 'The response should contain a submission `data` object.');
assert(response.data.hasOwnProperty('value'), 'The submission `data` should contain the `value`.');
assert.equal(response.data.value, deleteTest.data.value);
assert(response.hasOwnProperty('form'), 'The response should contain the `form` id.');
assert.equal(response.form, tempForm._id);
assert(response.hasOwnProperty('roles'), 'The response should contain the resource `roles`.');
assert.deepEqual(response.roles, []);
assert(res.headers.hasOwnProperty('x-jwt-token'), 'The response should contain a `x-jwt-token` header.');
// Update the submission data.
deleteTest = response;
// Store the JWT for future API calls.
template.users.admin.token = res.headers['x-jwt-token'];
done();
});
});
it('The Project Owner should be able to Delete all form submissions with the confirmation header', function(done) {
request(app)
.delete(hook.alter('url', '/' + tempForm.path + '/submission', template))
.set('x-jwt-token', template.users.admin.token)
.set('x-delete-confirm', tempForm._id)
.expect(200)
.end(function(err, res) {
if (err) {
return done(err);
}
var response = res.body;
assert.deepEqual(response, {});
// Store the JWT for future API calls.
template.users.admin.token = res.headers['x-jwt-token'];
done();
});
});
it('The Project Owner should not be able to Delete all form submissions without the confirmation header', function(done) {
request(app)
.delete(hook.alter('url', '/' + tempForm.path + '/submission', template))
.set('x-jwt-token', template.users.admin.token)
.expect(400)
.end(function(err, res) {
if (err) {
return done(err);
}
var response = res.body;
assert.deepEqual(response, {error: 'No confirmation header provided'});
// Store the JWT for future API calls.
template.users.admin.token = res.headers['x-jwt-token'];
done();
});
});
});
describe('Project Owner Submission', function() {
it('The Project Owner should be able to Create a submission without explicit permissions', function(done) {
// Test that roles can not be added on creation.
tempSubmission.roles = [template.roles.administrator._id.toString()];
request(app)
.post(hook.alter('url', '/form/' + tempForm._id + '/submission', template))
.set('x-jwt-token', template.users.admin.token)
.send(tempSubmission)
.expect(201)
.expect('Content-Type', /json/)
.end(function(err, res) {
if (err) {
return done(err);
}
var response = res.body;
assert(response.hasOwnProperty('_id'), 'The response should contain an `_id`.');
assert(response.hasOwnProperty('modified'), 'The response should contain a `modified` timestamp.');
assert(response.hasOwnProperty('created'), 'The response should contain a `created` timestamp.');
assert(response.hasOwnProperty('data'), 'The response should contain a submission `data` object.');
assert(response.data.hasOwnProperty('value'), 'The submission `data` should contain the `value`.');
assert.equal(response.data.value, tempSubmission.data.value);
assert(response.hasOwnProperty('form'), 'The response should contain the `form` id.');
assert.equal(response.form, tempForm._id);
assert(response.hasOwnProperty('roles'), 'The response should contain the resource `roles`.');
assert.deepEqual(response.roles, []);
assert(res.headers.hasOwnProperty('x-jwt-token'), 'The response should contain a `x-jwt-token` header.');
// Update the submission data.
tempSubmission = response;
// Store the JWT for future API calls.
template.users.admin.token = res.headers['x-jwt-token'];
done();
});
});
it('The Project Owner should be able to Read a submission without explicit permissions', function(done) {
request(app)
.get(hook.alter('url', '/form/' + tempForm._id + '/submission/' + tempSubmission._id, template))
.set('x-jwt-token', template.users.admin.token)
.expect(200)
.expect('Content-Type', /json/)
.end(function(err, res) {
if (err) {
return done(err);
}
var response = res.body;
assert.deepEqual(response, tempSubmission);
// Store the JWT for future API calls.
template.users.admin.token = res.headers['x-jwt-token'];
done();
});
});
it('The Project Owner should be able to Update a submission without explicit permissions', function(done) {
var updatedSubmission = _.clone(tempSubmission);
updatedSubmission.data.value = 'bar';
request(app)
.put(hook.alter('url', '/form/' + tempForm._id + '/submission/' + tempSubmission._id, template))
.set('x-jwt-token', template.users.admin.token)
.send({data: {value: updatedSubmission.data.value}})
.expect(200)
.expect('Content-Type', /json/)
.end(function(err, res) {
if (err) {
return done(err);
}
var response = res.body;
// Update the modified timestamp for response comparison.
updatedSubmission.modified = response.modified;
assert.deepEqual(response, updatedSubmission);
// Update the submission data.
tempSubmission = updatedSubmission;
// Store the JWT for future API calls.
template.users.admin.token = res.headers['x-jwt-token'];
done();
});
});
it('The Project Owner should not be able to add roles to a submission', (done) => {
var updatedSubmission = _.clone(tempSubmission);
updatedSubmission.data.value = 'bar';
updatedSubmission.roles = [template.roles.administrator._id.toString()];
request(app)
.put(hook.alter('url', '/form/' + tempForm._id + '/submission/' + tempSubmission._id, template))
.set('x-jwt-token', template.users.admin.token)
.send(updatedSubmission)
.expect(200)
.expect('Content-Type', /json/)
.end(function(err, res) {
if (err) {
return done(err);
}
var response = res.body;
// Update the modified timestamp for response comparison.
updatedSubmission.modified = response.modified;
updatedSubmission.roles = [];
assert.deepEqual(response, updatedSubmission);
// Update the submission data.
tempSubmission = updatedSubmission;
// Store the JWT for future API calls.
template.users.admin.token = res.headers['x-jwt-token'];
done();
});
});
it('The Project Owner should be able to Read the Index of submissions without explicit permissions', function(done) {
request(app)
.get(hook.alter('url', '/form/' + tempForm._id + '/submission', template))
.set('x-jwt-token', template.users.admin.token)
.expect(200)
.expect('Content-Type', /json/)
.end(function(err, res) {
if (err) {
return done(err);
}
var response = res.body;
assert.equal(response.length, 1, 'The response should contain 1 element');
assert.deepEqual(response[0], tempSubmission);
// Store the JWT for future API calls.
template.users.admin.token = res.headers['x-jwt-token'];
done();
});
});
it('The Project Owner should be able to Read the Index of submissions without explicit permissions without data', function(done) {
request(app)
.get(hook.alter('url', '/form/' + tempForm._id + '/submission?list=1', template))
.set('x-jwt-token', template.users.admin.token)
.expect(200)
.expect('Content-Type', /json/)
.end(function(err, res) {
if (err) {
return done(err);
}
var response = res.body;
assert.equal(response.length, 1, 'The response should contain 1 element');
assert(!response[0].hasOwnProperty('data'));
// Store the JWT for future API calls.
template.users.admin.token = res.headers['x-jwt-token'];
done();
});
});
it('The Project Owner should be able to Read a submission without explicit permissions using the Form alias', function(done) {
request(app)
.get(hook.alter('url', '/' + tempForm.path + '/submission/' + tempSubmission._id, template))
.set('x-jwt-token', template.users.admin.token)
.expect(200)
.expect('Content-Type', /json/)
.end(function(err, res) {
if (err) {
return done(err);
}
var response = res.body;
assert.deepEqual(response, tempSubmission);
// Store the JWT for future API calls.
template.users.admin.token = res.headers['x-jwt-token'];
done();
});
});
it('The Project Owner should be able to Update a submission without explicit permissions using the Form alias', function(done) {
var updatedSubmission = _.clone(tempSubmission);
updatedSubmission.data.value = 'bar2';
request(app)
.put(hook.alter('url', '/' + tempForm.path + '/submission/' + tempSubmission._id, template))
.set('x-jwt-token', template.users.admin.token)
.send({data: {value: updatedSubmission.data.value}})
.expect(200)
.expect('Content-Type', /json/)
.end(function(err, res) {
if (err) {
return done(err);
}
var response = res.body;
// Update the modified timestamp for response comparison.
updatedSubmission.modified = response.modified;
assert.deepEqual(response, updatedSubmission);
tempSubmission = updatedSubmission;
// Store the JWT for future API calls.
template.users.admin.token = res.headers['x-jwt-token'];
done();
});
});
it('The Project Owner should be able to Read the Index of submissions without explicit permissions using the Form alias', function(done) {
request(app)
.get(hook.alter('url', '/' + tempForm.path + '/submission', template))
.set('x-jwt-token', template.users.admin.token)
.expect(200)
.expect('Content-Type', /json/)
.end(function(err, res) {
if (err) {
return done(err);
}
var response = res.body;
assert.equal(response.length, 1);
assert.deepEqual(response[0], tempSubmission);
// Store the JWT for future API calls.
template.users.admin.token = res.headers['x-jwt-token'];
done();
});
});
it('A user with full permissions should not be able to edit data outside the submission.data object', function(done) {
var updatedSubmission = _.clone(tempSubmission);
updatedSubmission.data.value = 'bar3';
request(app)
.put(hook.alter('url', '/' + tempForm.path + '/submission/' + tempSubmission._id, template))
.set('x-jwt-token', template.users.admin.token)
.send({
other: 'this should not save', // try to add a field that is not present
externalIds: [{foo: 'bar'}], // try to edit a field that exists on the submissions w/ timestamp plugin
roles: [].concat(tempSubmission.roles, template.users.admin._id), // try to edit a field that exists on the submissions
data: {value: updatedSubmission.data.value}
})
.expect(200)
.expect('Content-Type', /json/)
.end(function(err, res) {
if (err) {
return done(err);
}
var response = res.body;
// Update the modified timestamp for response comparison.
updatedSubmission.modified = response.modified;
// Confirm that other data was not saved.
assert.equal(response.hasOwnProperty('other'), false);
// Confirm that the externalIds were not modified by the user request.
assert.deepEqual(response.externalIds, tempSubmission.externalIds);
// Confirm that the roles were not modified by the user request.
assert.deepEqual(response.roles, tempSubmission.roles);
// Confirm that nothing else was changes (besides the automatic modified timestamp).
assert.deepEqual(response, updatedSubmission);
// Update the submission data.
tempSubmission = updatedSubmission;
// Store the JWT for future API calls.
template.users.admin.token = res.headers['x-jwt-token'];
done();
});
});
var deleteTest = {data: {value: 'foo'}};
it('The Project Owner should be able to Create a submission without explicit permissions using the Form alias', function(done) {
request(app)
.post(hook.alter('url', '/' + tempForm.path + '/submission', template))
.set('x-jwt-token', template.users.admin.token)
.send(deleteTest)
.expect(201)
.expect('Content-Type', /json/)
.end(function(err, res) {
if (err) {
return done(err);
}
var response = res.body;
assert(response.hasOwnProperty('_id'), 'The response should contain an `_id`.');
assert(response.hasOwnProperty('modified'), 'The response should contain a `modified` timestamp.');
assert(response.hasOwnProperty('created'), 'The response should contain a `created` timestamp.');
assert(response.hasOwnProperty('data'), 'The response should contain a submission `data` object.');
assert(response.data.hasOwnProperty('value'), 'The submission `data` should contain the `value`.');
assert.equal(response.data.value, deleteTest.data.value);
assert(response.hasOwnProperty('form'), 'The response should contain the `form` id.');
assert.equal(response.form, tempForm._id);
assert(response.hasOwnProperty('roles'), 'The response should contain the resource `roles`.');
assert.deepEqual(response.roles, []);
assert(res.headers.hasOwnProperty('x-jwt-token'), 'The response should contain a `x-jwt-token` header.');
// Update the submission data.
deleteTest = response;
// Store the JWT for future API calls.
template.users.admin.token = res.headers['x-jwt-token'];
done();
});
});
it('The Project Owner should be able to Delete a submission without explicit permissions using the Form alias', function(done) {
request(app)
.delete(hook.alter('url', '/' + tempForm.path + '/submission/' + deleteTest._id, template))
.set('x-jwt-token', template.users.admin.token)
.expect(200)
.end(function(err, res) {
if (err) {
return done(err);
}
var response = res.body;
assert.deepEqual(response, {});
// Store the JWT for future API calls.
template.users.admin.token = res.headers['x-jwt-token'];
done();
});
});
if (!docker)
it('A deleted Submission should remain in the database', async function() {
var formio = hook.alter('formio', app.formio);
let submission = await formio.resources.submission.model.findOne({_id: deleteTest._id});
if (!submission) {
throw('No submission found with _id: ' + deleteTest._id + ', expected 1.');
}
submission = submission.toObject();
assert.notEqual(submission.deleted, null);
});
it('Cant access a submission without a valid Submission Id', function(done) {
request(app)
.get(hook.alter('url', '/' + tempForm.path + '/submission/2342342344234', template))
.set('x-jwt-token', template.users.admin.token)
.expect(400)
.end(function(err, res) {
if (err) {
return done(err);
}
// Store the JWT for future API calls.
template.users.admin.token = res.headers['x-jwt-token'];
done();
});
});
});
describe('Authenticated User Submission', function() {
it('A Registered user should not be able to Create a submission without explicit permissions', function(done) {
var req = request(app)
.post(hook.alter('url', '/form/' + tempForm._id + '/submission', template))
.send(tempSubmission);
request401(req, done, template.users.user1);
});
it('A Registered user should not be able to Read a submission without explicit permissions', function(done) {
var req = request(app)
.get(hook.alter('url', '/form/' + tempForm._id + '/submission/' + tempSubmission._id, template));
request401(req, done, template.users.user1);
});
it('A Registered user should not be able to Update a submission without explicit permissions', function(done) {
var req = request(app)
.put(hook.alter('url', '/form/' + tempForm._id + '/submission/' + tempSubmission._id, template))
.send({foo: 'bar'});
request401(req, done, template.users.user1);
});
it('A Registered user should not be able to Read the Index of submissions without explicit permissions', function(done) {
var req = request(app)
.get(hook.alter('url', '/form/' + tempForm._id + '/submission', template));
request401(req, done, template.users.user1);
});
it('A Registered user should not be able to Read a submission without explicit permissions using the Form alias', function(done) {
var req = request(app)
.get(hook.alter('url', '/' + tempForm.path + '/submission/' + tempSubmission._id, template));
request401(req, done, template.users.user1);
});
it('A Registered user should not be able to Update a submission without explicit permissions using the Form alias', function(done) {
var req = request(app)
.put(hook.alter('url', '/' + tempForm.path + '/submission/' + tempSubmission._id, template))
.send({foo: 'bar'});
request401(req, done, template.users.user1);
});
it('A Registered user should not be able to Read the Index of submissions without explicit permissions using the Form alias', function(done) {
var req = request(app)
.get(hook.alter('url', '/' + tempForm.path + '/submission', template));
request401(req, done, template.users.user1);
});
it('A Registered user should not be able to Create a submissions without explicit permissions using the Form alias', function(done) {
var req = request(app)
.post(hook.alter('url', '/' + tempForm.path + '/submission', template))
.send(tempSubmission);
request401(req, done, template.users.user1);
});
it('A Registered user should not be able to Delete a submissions without explicit permissions using the Form alias', function(done) {
var req = request(app)
.delete(hook.alter('url', '/' + tempForm.path + '/submission/' + tempSubmission._id, template));
request401(req, done, template.users.user1);
});
it('A Registered user should not be able to Delete a submission without explicit permissions', function(done) {
var req = request(app)
.delete(hook.alter('url', '/form/' + tempForm._id + '/submission/' + tempSubmission._id, template));
request401(req, done, template.users.user1);
});
});
describe('Anonymous User Submission', function() {
it('An Anonymous user should not be able to Create a submission without explicit permissions', function(done) {
var req = request(app)
.post(hook.alter('url', '/form/' + tempForm._id + '/submission', template))
.send(tempSubmission);
request401(req, done);
});
it('An Anonymous user should not be able to Read a submission without explicit permissions', function(done) {
var req = request(app)
.get(hook.alter('url', '/form/' + tempForm._id + '/submission/' + tempSubmission._id, template));
request401(req, done);
});
it('An Anonymous user should not be able to Update a submission without explicit permissions', function(done) {
var req = request(app)
.put(hook.alter('url', '/form/' + tempForm._id + '/submission/' + tempSubmission._id, template))
.send({foo: 'bar'});
request401(req, done);
});
it('An Anonymous user should not be able to Read the Index of submissions without explicit permissions', function(done) {
var req = request(app)
.get(hook.alter('url', '/form/' + tempForm._id + '/submission', template));
request401(req, done);
});
it('An Anonymous user should not be able to Read a submission without explicit permissions using the Form alias', function(done) {
var req = request(app)
.get(hook.alter('url', '/' + tempForm.path + '/submission/' + tempSubmission._id, template));
request401(req, done);
});
it('An Anonymous user should not be able to Update a submission without explicit permissions using the Form alias', function(done) {
var req = request(app)
.put(hook.alter('url', '/' + tempForm.path + '/submission/' + tempSubmission._id, template))
.send({foo: 'bar'});
request401(req, done);
});
it('An Anonymous user should not be able to Read the Index of submissions without explicit permissions using the Form alias', function(done) {
var req = request(app)
.get(hook.alter('url', '/' + tempForm.path + '/submission', template));
request401(req, done);
});
it('An Anonymous user should not be able to Create a submission without explicit permissions using the Form alias', function(done) {
var req = request(app)
.post(hook.alter('url', '/' + tempForm.path + '/submission', template))
.send({foo: 'bar'});
request401(req, done);
});
it('An Anonymous user should not be able to Delete a submission without explicit permissions using the Form alias', function(done) {
var req = request(app)
.delete(hook.alter('url', '/' + tempForm.path + '/submission/' + tempSubmission._id, template));
request401(req, done);
});
it('An Anonymous user should not be able to Delete a submission without explicit permissions', function(done) {
var req = request(app)
.delete(hook.alter('url', '/form/' + tempForm._id + '/submission/' + tempSubmission._id, template));
request401(req, done);
});
});
describe('Submission Normalization', function() {
it('The Project owner should be able to Delete a submission with explicit Own permissions', function(done) {
request(app)
.delete(hook.alter('url', '/form/' + tempForm._id + '/submission/' + tempSubmission._id, template))
.set('x-jwt-token', template.users.admin.token)
.expect(200)
.end(function(err, res) {
if (err) {
return done(err);
}
var response = res.body;
assert.deepEqual(response, {});
// Store the JWT for future API calls.
template.users.admin.token = res.headers['x-jwt-token'];
done();
});
});
if (!docker)
it('A deleted Submission should remain in the database', async function() {
var formio = hook.alter('formio', app.formio);
let submission = await formio.resources.submission.model.findOne({_id: tempSubmission._id})
.exec();
if (!submission) {
throw('No submission found w/ _id: ' + submission._id + ', expected 1.');
}
submission = submission.toObject();
assert.notEqual(submission.deleted, null);
});
it('Delete the Submissions created for Ownership Checks', function(done) {
tempSubmissions.forEach(function(submission) {
request(app)
.delete(hook.alter('url', '/form/' + tempForm._id + '/submission/' + submission._id, template))
.set('x-jwt-token', template.users.admin.token)
.expect(200)
.end(function(err, res) {
if (err) {
return done(err);
}
var response = res.body;
assert.deepEqual(response, {});
// Store the JWT for future API calls.
template.users.admin.token = res.headers['x-jwt-token'];
});
});
tempSubmissions = [];
done();
});
});
describe('Form Normalization', function() {
it('Delete the form created for Access Checks', function(done) {
request(app)
.delete(hook.alter('url', '/form/' + tempForm._id, template))
.set('x-jwt-token', template.users.admin.token)
.expect(200)
.end(function(err, res) {
if (err) {
return done(err);
}
var response = res.body;
assert.deepEqual(response, {});
// Store the JWT for future API calls.
template.users.admin.token = res.headers['x-jwt-token'];
done();
});
});
if (!docker)
it('A deleted Form should not have active submissions in the database', async function() {
var formio = hook.alter('formio', app.formio);
const submissions = await formio.resources.submission.model.findOne({form: tempForm._id, deleted: {$eq: null}})
.exec();
if (submissions && submissions.length !== 0) {
throw(submissions.length + ' submissions found with the form: ' + tempForm._id + ', expected 0.');
}
});
});
});
describe('Submission Ownership', function() {
// Store the temp form for this test suite.
var tempForm = {
title: 'dummyForm',
name: 'dummyForm',
path: 'dummy/form',
type: 'form',
access: [],
submissionAccess: [],
components: [
{
type: 'textfield',
validate: {
custom: '',
pattern: '',
maxLength: '',
minLength: '',
required: false
},
defaultValue: '',
multiple: false,
suffix: '',
prefix: '',
placeholder: 'value',
key: 'value',
label: 'value',
inputMask: '',
inputType: 'text',
input: true
}
]
};
// Store the temp submissions for this test suite.
var tempSubmissions = [];
var temp = {};
describe('Bootstrap', function() {
it('Create the Form for Ownership Checks', function(done) {
request(app)
.post(hook.alter('url', '/form', template))
.set('x-jwt-token', template.users.admin.token)
.send(tempForm)
.expect('Content-Type', /json/)
.expect(201)
.end(function(err, res) {
if (err) {
return done(err);
}
var response = res.body;
assert(response.hasOwnProperty('_id'), 'The response should contain an `_id`.');
assert(response.hasOwnProperty('modified'), 'The response should contain a `modified` timestamp.');
assert(response.hasOwnProperty('created'), 'The response should contain a `created` timestamp.');
assert(response.hasOwnProperty('access'), 'The response should contain an the `access`.');
assert.equal(response.title, tempForm.title);
assert.equal(response.name, tempForm.name);
assert.equal(response.path, tempForm.path);
assert.equal(response.type, 'form');
assert.equal(response.access.length, 1);
assert.equal(response.access[0].type, 'read_all');
assert.equal(response.access[0].roles.length, 3);
assert.notEqual(response.access[0].roles.indexOf(template.roles.anonymous._id.toString()), -1);
assert.notEqual(response.access[0].roles.indexOf(template.roles.authenticated._id.toString()), -1);
assert.notEqual(response.access[0].roles.indexOf(template.roles.administrator._id.toString()), -1);
assert.deepEqual(response.submissionAccess, []);
assert.deepEqual(response.components, tempForm.components);
tempForm = response;
// Store the JWT for future API calls.
template.users.admin.token = res.headers['x-jwt-token'];
done();
});
});
});
describe('Project Owner', function() {
it('The Project Owner should create a submission in their name, when the owner is not specified, without permissions', function(done) {
var tempSubmission = {data: {value: 'foo'}};
request(app)
.post(hook.alter('url', '/form/' + tempForm._id + '/submission', template))
.set('x-jwt-token', template.users.admin.token)
.send(tempSubmission)
.expect(201)
.expect('Content-Type', /json/)
.end(function(err, res) {
if (err) {
return done(err);
}
var response = res.body;
assert(response.hasOwnProperty('_id'), 'The response should contain an `_id`.');
assert(response.hasOwnProperty('modified'), 'The response should contain a `modified` timestamp.');
assert(response.hasOwnProperty('created'), 'The response should contain a `created` timestamp.');
assert(response.hasOwnProperty('data'), 'The response should contain a submission `data` object.');
assert(response.data.hasOwnProperty('value'), 'The submission `data` should contain the `value`.');
assert.equal(response.data.value, tempSubmission.data.value);
assert(response.hasOwnProperty('form'), 'The response should contain the `form` id.');
assert.equal(response.form, tempForm._id);
assert(response.hasOwnProperty('roles'), 'The response should contain the resource `roles`.');
assert.deepEqual(response.roles, []);
assert(response.hasOwnProperty('owner'), 'The response should contain the resource `owner`.');
assert.equal(response.owner, template.users.admin._id);
assert(res.headers.hasOwnProperty('x-jwt-token'), 'The response should contain a `x-jwt-token` header.');
// Update the submission data.
tempSubmissions.push(response);
// Store the JWT for future API calls.
template.users.admin.token = res.headers['x-jwt-token'];
done();
});
});
it('The Project Owner should be able to create a submission in someones name, without permissions', function(done) {
var tempSubmission = {data: {value: 'foo'}, owner: template.users.user1._id};
request(app)
.post(hook.alter('url', '/form/' + tempForm._id + '/submission', template))
.set('x-jwt-token', template.users.admin.token)
.send(tempSubmission)
.expect(201)
.expect('Content-Type', /json/)
.end(function(err, res) {
if (err) {
return done(err);
}
var response = res.body;
assert(response.hasOwnProperty('_id'), 'The response should contain an `_id`.');
assert(response.hasOwnProperty('modified'), 'The response should contain a `modified` timestamp.');
assert(response.hasOwnProperty('created'), 'The response should contain a `created` timestamp.');
assert(response.hasOwnProperty('data'), 'The response should contain a submission `data` object.');
assert(response.data.hasOwnProperty('value'), 'The submission `data` should contain the `value`.');
assert.equal(response.data.value, tempSubmission.data.value);
assert(response.hasOwnProperty('form'), 'The response should contain the `form` id.');
assert.equal(response.form, tempForm._id);
assert(response.hasOwnProperty('roles'), 'The response should contain the resource `roles`.');
assert.deepEqual(response.roles, []);
assert(response.hasOwnProperty('owner'), 'The response should contain the resource `owner`.');
assert.notEqual(response.owner, null);
assert.equal(response.owner, tempSubmission.owner);
assert(res.headers.hasOwnProperty('x-jwt-token'), 'The response should contain a `x-jwt-token` header.');
// Update the submission data.
tempSubmissions.push(response);
// Store the response for an update test.
temp = response;
// Store the JWT for future API calls.
template.users.admin.token = res.headers['x-jwt-token'];
done();
});
});
it('The Project Owner should be able to update the owner of a submission, without explicit permissions', function(done) {
request(app)
.put(hook.alter('url', '/form/' + tempForm._id + '/submission/' + temp._id, template))
.set('x-jwt-token', template.users.admin.token)
.send({owner: template.users.admin._id})
.expect(200)
.expect('Content-Type', /json/)
.end(function(err, res) {
if (err) {
return done(err);
}
var response = res.body;
// Update the owner of temp for comparison.
temp.owner = template.users.admin._id;
// Remove the modified timestamp for comparison.
assert.deepEqual(_.omit(response, 'modified'), _.omit(temp, 'modified'));
// Update the temp form contents.
temp = response;
// Store the JWT for future API calls.
template.users.admin.token = res.headers['x-jwt-token'];
done();
});
});
it('Updating a submission with explicit empty data, will remove all the data', function(done) {
request(app)
.put(hook.alter('url', '/form/' + tempForm._id + '/submission/' + temp._id, template))
.set('x-jwt-token', template.users.admin.token)
.send({data: {}})
.expect(200)
.expect('Content-Type', /json/)
.end(function(err, res) {
if (err) {
return done(err);
}
var response = res.body;
// Compare the previous and current data contents before deep comparison.
assert.equal(Object.keys(response.data).length, 0);
assert.notEqual(temp.data, response.data);
temp.data = {};
// Remove the modified timestamp for comparison.
assert.deepEqual(_.omit(response, 'modified'), _.omit(temp, 'modified'));
// Update the temp form contents.
temp = response;
// Store the JWT for future API calls.
template.users.admin.token = res.headers['x-jwt-token'];
done();
});
});
});
describe('Authenticated User', function() {
it('An Authenticated User should not be able create a submission in their name, without permissions', function(done) {
var submission = {data: {value: 'foo'}, owner: template.users.user1._id};
var req = request(app)
.post(hook.alter('url', '/form/' + tempForm._id + '/submission', template))
.send(submission);
request401(req, done, template.users.user1);
});
it('An Authenticated User should not be able to create a submission in someones name, without permissions', function(done) {
var submission = {data: {value: 'foo'}, owner: template.users.user2._id};
var req = request(app)
.post(hook.alter('url', '/form/' + tempForm._id + '/submission', template))
.send(submission);
request401(req, done, template.users.user1);
});
it('An Authenticated User should not be able to update the owner of a submission, without permissions', function(done) {
var req = request(app)
.put(hook.alter('url', '/form/' + tempForm._id + '/submission/' + temp._id, template))
.send({owner: template.users.user1._id});
request401(req, done, template.users.user1);
});
});
describe('Anonymous User', function() {
it('An Anonymous User should not be able create a submission in their name, without permissions', function(done) {
var req = request(app)
.post(hook.alter('url', '/form/' + tempForm._id + '/submission', template))
.send({data: temp.data});
request401(req, done);
});
it('An Anonymous User should not be able to create a submission in someones name, without permissions', function(done) {
var req = request(app)
.post(hook.alter('url', '/form/' + tempForm._id + '/submission', template))
.send({data: {value: 'foo'}, owner: template.users.user2._id});
request401(req, done);
});
it('An Anonymous User should not be able to update the owner of a submission, without permissions', function(done) {
var req = request(app)
.put(hook.alter('url', '/form/' + tempForm._id + '/submission/' + temp._id, template))
.send({data: temp.data, owner: template.users.admin._id});
request401(req, done);
});
});
describe('Submission Normalization', function() {
it('Delete the Submissions created for Ownership Checks', function(done) {
tempSubmissions.forEach(function(submission) {
request(app)
.delete(hook.alter('url', '/form/' + tempForm._id + '/submission/' + submission._id, template))
.set('x-jwt-token', template.users.admin.token)
.expect(200)
.end(function(err, res) {
if (err) {
return done(err);
}
var response = res.body;
assert.deepEqual(response, {});
// Store the JWT for future API calls.
template.users.admin.token = res.headers['x-jwt-token'];
});
});
tempSubmissions = [];
done();
});
});
describe('Form Normalization', function() {
it('Delete the Form created for Ownership Checks', function(done) {
request(app)
.delete(hook.alter('url', '/form/' + tempForm._id, template))
.set('x-jwt-token', template.users.admin.token)
.expect(200)
.end(function(err, res) {
if (err) {
return done(err);
}
var response = res.body;
assert.deepEqual(response, {});
tempForm = response;
// Store the JWT for future API calls.
template.users.admin.token = res.headers['x-jwt-token'];
done();
});
});
});
});
});
describe('Submission Level Permissions (Authenticated User)', function() {
describe('Submission CRUD - _own', function() {
// Store the temp form for this test suite.
var tempForm = {
title: 'Authenticated access check',
name: 'access',
path: 'accessauthenticated',
type: 'form',
components: [
{
type: 'textfield',
validate: {
custom: '',
pattern: '',
maxLength: '',
minLength: '',
required: true
},
defaultValue: '',
multiple: false,
suffix: '',
prefix: '',
placeholder: 'value',
key: 'value',
label: 'value',
inputMask: '',
inputType: 'text',
input: true
}
]
};
// Store the template submission for this test suite.
var templateSubmission = {data: {value: 'foo'}};
// Store the user1 temp submission for this test suite.
var tempSubmissionUser1 = {};
// Store the user2 temp submission for this test suite.
v