Commit f0045483 authored by Tristan Cavelier's avatar Tristan Cavelier

Some files removed temporarily

parent 3356688e
/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
/*global jIO: true, hex_sha256: true, setTimeout: true */
jIO.addStorageType('conflictmanager', function (spec, my) {
var that, priv, storage_exists, local_namespace, empty_fun,
super_serialized;
spec = spec || {};
that = my.basicStorage(spec, my);
priv = {};
storage_exists = (spec.storage ? true : false);
priv.sub_storage_spec = spec.storage || {
type: 'base'
};
priv.sub_storage_string = JSON.stringify(priv.sub_storage_spec);
local_namespace = 'jio/conflictmanager/' + priv.sub_storage_string + '/';
empty_fun = function () {};
super_serialized = that.serialized;
that.serialized = function () {
var o = super_serialized();
o.storage = priv.sub_storage_spec;
return o;
};
that.validateState = function () {
if (storage_exists) {
return '';
}
return 'Need at least one parameter: "storage".';
};
priv.getDistantMetadata = function (command, path, success, error) {
var cloned_option = command.cloneOption();
cloned_option.metadata_only = false;
that.addJob('get', priv.sub_storage_spec, path, cloned_option,
success, error);
};
priv.saveMetadataToDistant = function (command, path, content, success,
error) {
that.addJob('put', priv.sub_storage_spec, {
_id: path,
content: JSON.stringify(content)
},
command.cloneOption(), success, error);
};
priv.saveNewRevision = function (command, path, content, success, error) {
that.addJob('post', priv.sub_storage_spec, {
_id: path,
content: content
},
command.cloneOption(), success, error);
};
priv.loadRevision = function (command, path, success, error) {
that.addJob('get', priv.sub_storage_spec, path, command.cloneOption(),
success, error);
};
priv.deleteAFile = function (command, path, success, error) {
that.addJob('remove', priv.sub_storage_spec, {
_id: path
},
command.cloneOption(), success, error);
};
priv.chooseARevision = function (metadata) {
var tmp_last_modified = 0,
ret_rev = '',
rev;
for (rev in metadata) {
if (metadata.hasOwnProperty(rev)) {
if (tmp_last_modified < metadata[rev]._last_modified) {
tmp_last_modified = metadata[rev]._last_modified;
ret_rev = rev;
}
}
}
return ret_rev;
};
priv._revs = function (metadata, revision) {
if (!(metadata && revision)) {
return null;
}
if (metadata[revision]) {
return {
start: metadata[revision]._revisions.length,
ids: metadata[revision]._revisions
};
}
return null;
};
priv._revs_info = function (metadata) {
if (!metadata) {
return null;
}
var k, l = [];
for (k in metadata) {
if (metadata.hasOwnProperty(k)) {
l.push({
rev: k,
status: (
metadata[k] ? (
metadata[k]._deleted ? 'deleted' : 'available'
) : 'missing'
)
});
}
}
return l;
};
priv.solveConflict = function (doc, option, param) {
var o = {}, am = priv.newAsyncModule(),
command = param.command,
metadata_file_path = param.docid + '.metadata',
current_revision = '',
current_revision_file_path = '',
metadata_file_content = null,
on_conflict = false,
conflict_object = {
total_rows: 0,
rows: []
},
on_remove = param._deleted,
previous_revision = param.previous_revision,
previous_revision_content_object = null,
now = new Date(),
failerror;
o.getDistantMetadata = function () {
priv.getDistantMetadata(
command,
metadata_file_path,
function (result) {
var previous_revision_number =
parseInt(previous_revision.split('-')[0], 10);
metadata_file_content = JSON.parse(result.content);
// set current revision
// jslint: removed '' in hex_sha256(''...
current_revision = (previous_revision_number + 1) + '-' +
hex_sha256(doc.content + previous_revision +
JSON.stringify(metadata_file_content));
current_revision_file_path = param.docid + '.' + current_revision;
previous_revision_content_object = metadata_file_content[
previous_revision
] || {};
if (!on_remove) {
am.wait(o, 'saveMetadataOnDistant', 1);
am.call(o, 'saveNewRevision');
}
am.call(o, 'previousUpdateMetadata');
},
function (error) {
am.call(o, 'error', [error]);
}
);
};
o.saveNewRevision = function () {
priv.saveNewRevision(
command,
current_revision_file_path,
doc.content,
function () {
am.call(o, 'saveMetadataOnDistant');
},
function (error) {
am.call(o, 'error', [error]);
}
);
};
o.previousUpdateMetadata = function () {
var i;
for (i = 0; i < param.key.length; i += 1) {
delete metadata_file_content[param.key[i]];
}
am.call(o, 'checkForConflicts');
};
o.checkForConflicts = function () {
var rev;
for (rev in metadata_file_content) {
if (metadata_file_content.hasOwnProperty(rev)) {
on_conflict = true;
failerror = {
status: 409,
error: 'conflict',
statusText: 'Conflict',
reason: 'document update conflict',
message: 'There is one or more conflicts'
};
break;
}
}
am.call(o, 'updateMetadata');
};
o.updateMetadata = function () {
var revision_history, id = '';
id = current_revision.split('-');
id.shift();
id = id.join('-');
revision_history = previous_revision_content_object._revisions;
revision_history.unshift(id);
metadata_file_content[current_revision] = {
_creation_date: previous_revision_content_object._creation_date ||
now.getTime(),
_last_modified: now.getTime(),
_revisions: revision_history,
_conflict: on_conflict,
_deleted: on_remove
};
if (on_conflict) {
conflict_object = priv.createConflictObject(
command,
metadata_file_content,
current_revision
);
}
am.call(o, 'saveMetadataOnDistant');
};
o.saveMetadataOnDistant = function () {
priv.saveMetadataToDistant(
command,
metadata_file_path,
metadata_file_content,
function () {
am.call(o, 'deleteAllConflictingRevision');
if (on_conflict) {
am.call(o, 'error');
} else {
am.call(o, 'success');
}
},
function (error) {
am.call(o, 'error', [error]);
}
);
};
o.deleteAllConflictingRevision = function () {
var i;
for (i = 0; i < param.key.length; i += 1) {
priv.deleteAFile(
command,
param.docid + '.' + param.key[i],
empty_fun,
empty_fun
);
}
};
o.success = function () {
var a = {
ok: true,
id: param.docid,
rev: current_revision
};
am.neverCall(o, 'error');
am.neverCall(o, 'success');
if (option.revs) {
a.revisions = priv._revs(
metadata_file_content,
current_revision
);
}
if (option.revs_info) {
a.revs_info = priv._revs_info(metadata_file_content);
}
if (option.conflicts) {
a.conflicts = conflict_object;
}
param.success(a);
};
o.error = function (error) {
var err = error || failerror || {
status: 0,
statusText: 'Unknown',
error: 'unknown_error',
message: 'Unknown error.',
reason: 'unknown error'
};
if (current_revision) {
err.rev = current_revision;
}
if (option.revs) {
err.revisions = priv._revs(
metadata_file_content,
current_revision
);
}
if (option.revs_info) {
err.revs_info = priv._revs_info(
metadata_file_content
);
}
if (option.conflicts) {
err.conflicts = conflict_object;
}
am.neverCall(o, 'error');
am.neverCall(o, 'success');
param.error(err);
};
am.call(o, 'getDistantMetadata');
};
priv.createConflictObject = function (command, metadata, revision) {
return {
total_rows: 1,
rows: [priv.createConflictRow(
command,
command.getDocId(),
metadata,
revision
)]
};
};
priv.getParam = function (list) {
var param = {}, i = 0;
if (typeof list[i] === 'string') {
param.content = list[i];
i += 1;
}
if (typeof list[i] === 'object') {
param.options = list[i];
i += 1;
} else {
param.options = {};
}
param.callback = function () {};
param.success = function (val) {
param.callback(undefined, val);
};
param.error = function (err) {
param.callback(err, undefined);
};
if (typeof list[i] === 'function') {
if (typeof list[i + 1] === 'function') {
param.success = list[i];
param.error = list[i + 1];
} else {
param.callback = list[i];
}
}
return param;
};
priv.createConflictRow = function (command, docid, metadata, revision) {
var row = {
id: docid,
key: [],
value: {
// jslint: removed params /* content, option, success, error */
_solveConflict: function () {
var param = {}, got = priv.getParam(arguments);
if (got.content === undefined) {
param._deleted = true;
} else {
param._deleted = false;
}
param.success = got.success;
param.error = got.error;
param.previous_revision = revision;
param.docid = docid;
param.key = row.key;
param.command = command.clone();
return priv.solveConflict({
_id: docid,
content: got.content,
_rev: revision
},
got.options, param);
}
}
}, k;
for (k in metadata) {
if (metadata.hasOwnProperty(k)) {
row.key.push(k);
}
}
return row;
};
priv.newAsyncModule = function () {
var async = {};
async.call = function (obj, function_name, arglist) {
obj._wait = obj._wait || {};
if (obj._wait[function_name]) {
obj._wait[function_name] -= 1;
return empty_fun;
}
// ok if undef or 0
arglist = arglist || [];
setTimeout(function () {
obj[function_name].apply(obj[function_name], arglist);
});
};
async.neverCall = function (obj, function_name) {
obj._wait = obj._wait || {};
obj._wait[function_name] = -1;
};
async.wait = function (obj, function_name, times) {
obj._wait = obj._wait || {};
obj._wait[function_name] = times;
};
async.end = function () {
async.call = empty_fun;
};
return async;
};
that.post = function (command) {
that.put(command);
};
/**
* Save a document and can manage conflicts.
* @method put
*/
that.put = function (command) {
var o = {}, am = priv.newAsyncModule(),
metadata_file_path = command.getDocId() + '.metadata',
current_revision = '',
current_revision_file_path = '',
metadata_file_content = null,
on_conflict = false,
conflict_object = {
total_rows: 0,
rows: []
},
previous_revision = command.getDocInfo('_rev') || '0',
previous_revision_file_path = command.getDocId() + '.' +
previous_revision,
now = new Date(),
failerror;
o.getDistantMetadata = function () {
priv.getDistantMetadata(
command,
metadata_file_path,
function (result) {
var previous_revision_number =
parseInt(previous_revision.split('-')[0], 10);
metadata_file_content = JSON.parse(result.content);
// set current revision
current_revision = (previous_revision_number + 1) + '-' +
// jslint: removed hex_sha256(''+...
hex_sha256(command.getDocContent() + previous_revision +
JSON.stringify(metadata_file_content));
current_revision_file_path = command.getDocId() + '.' +
current_revision;
am.wait(o, 'saveMetadataOnDistant', 1);
am.call(o, 'saveNewRevision');
am.call(o, 'checkForConflicts');
},
function (error) {
if (error.status === 404) {
current_revision = '1-' + hex_sha256(command.getDocContent());
current_revision_file_path = command.getDocId() + '.' +
current_revision;
am.wait(o, 'saveMetadataOnDistant', 1);
am.call(o, 'saveNewRevision');
am.call(o, 'createMetadata');
} else {
am.call(o, 'error', [error]);
}
}
);
};
o.saveNewRevision = function () {
priv.saveNewRevision(
command,
current_revision_file_path,
command.getDocContent(),
function () {
am.call(o, 'saveMetadataOnDistant');
},
function (error) {
am.call(o, 'error', [error]);
}
);
};
o.checkForConflicts = function () {
var rev;
for (rev in metadata_file_content) {
if (metadata_file_content.hasOwnProperty(rev) &&
rev !== previous_revision) {
on_conflict = true;
failerror = {
status: 409,
error: 'conflict',
statusText: 'Conflict',
reason: 'document update conflict',
message: 'Document update conflict.'
};
break;
}
}
am.call(o, 'updateMetadata');
};
o.createMetadata = function () {
var id = current_revision;
id = id.split('-');
id.shift();
id = id.join('-');
metadata_file_content = {};
metadata_file_content[current_revision] = {
_creation_date: now.getTime(),
_last_modified: now.getTime(),
_revisions: [id],
_conflict: false,
_deleted: false
};
am.call(o, 'saveMetadataOnDistant');
};
o.updateMetadata = function () {
var previous_creation_date, revision_history = [],
id = '';
if (metadata_file_content[previous_revision]) {
previous_creation_date = metadata_file_content[
previous_revision
]._creation_date;
revision_history = metadata_file_content[
previous_revision
]._revisions;
delete metadata_file_content[previous_revision];
}
id = current_revision.split('-');
id.shift();
id = id.join('-');
revision_history.unshift(id);
metadata_file_content[current_revision] = {
_creation_date: previous_creation_date || now.getTime(),
_last_modified: now.getTime(),
_revisions: revision_history,
_conflict: on_conflict,
_deleted: false
};
if (on_conflict) {
conflict_object = priv.createConflictObject(
command,
metadata_file_content,
current_revision
);
}
am.call(o, 'saveMetadataOnDistant');
};
o.saveMetadataOnDistant = function () {
priv.saveMetadataToDistant(
command,
metadata_file_path,
metadata_file_content,
function () {
am.call(o, 'deletePreviousRevision');
if (on_conflict) {
am.call(o, 'error');
} else {
am.call(o, 'success');
}
},
function (error) {
am.call(o, 'error', [error]);
}
);
};
o.deletePreviousRevision = function () {
// jslint: removed /*&& !on_conflict*/
if (previous_revision !== '0') {
priv.deleteAFile(
command,
previous_revision_file_path,
empty_fun,
empty_fun
);
}
};
o.success = function () {
var a = {
ok: true,
id: command.getDocId(),
rev: current_revision
};
am.neverCall(o, 'error');
am.neverCall(o, 'success');
if (command.getOption('revs')) {
a.revisions = priv._revs(
metadata_file_content,
current_revision
);
}
if (command.getOption('revs_info')) {
a.revs_info = priv._revs_info(metadata_file_content);
}
if (command.getOption('conflicts')) {
a.conflicts = conflict_object;
}
that.success(a);
};
o.error = function (error) {
var err = error || failerror || {
status: 0,
statusText: 'Unknown',
error: 'unknown_error',
message: 'Unknown error.',
reason: 'unknown error'
};
if (current_revision) {
err.rev = current_revision;
}
if (command.getOption('revs')) {
err.revisions = priv._revs(
metadata_file_content,
current_revision
);
}
if (command.getOption('revs_info')) {
err.revs_info = priv._revs_info(metadata_file_content);
}
if (command.getOption('conflicts')) {
err.conflicts = conflict_object;
}
am.neverCall(o, 'error');
am.neverCall(o, 'success');
that.error(err);
};
am.call(o, 'getDistantMetadata');
}; // end put
/**
* Load a document from several storages, and send the first retreived
* document.
* @method get
*/
that.get = function (command) {
var o = {}, am = priv.newAsyncModule(),
metadata_file_path = command.getDocId() + '.metadata',
current_revision = command.getOption('rev') || '',
metadata_file_content = null,
metadata_only = command.getOption('metadata_only'),
on_conflict = false,
conflict_object = {
total_rows: 0,
rows: []
},
doc = {
_id: command.getDocId()
},
call404 = function (message) {
am.call(o, 'error', [{
status: 404,
statusText: 'Not Found',
error: 'not_found',
message: message,
reason: message
}]);
};
o.getDistantMetadata = function () {
priv.getDistantMetadata(
command,
metadata_file_path,
function (result) {
metadata_file_content = JSON.parse(result.content);
if (!metadata_only) {
am.wait(o, 'success', 1);
}
am.call(o, 'affectMetadata');
am.call(o, 'checkForConflicts');
},
function (error) {
am.call(o, 'error', [error]);
}
);
};
o.affectMetadata = function () {
if (current_revision) {
if (!metadata_file_content[current_revision]) {
return call404('Document revision does not exists.');
}
} else {
current_revision = priv.chooseARevision(metadata_file_content);
}
doc._last_modified =
metadata_file_content[current_revision]._last_modified;
doc._creation_date =
metadata_file_content[current_revision]._creation_date;
doc._rev = current_revision;
if (metadata_only) {
am.call(o, 'success');
} else {
am.call(o, 'loadRevision');
}
};
o.loadRevision = function () {
if (!current_revision ||
metadata_file_content[current_revision]._deleted) {
return call404('Document has been removed.');
}
priv.loadRevision(
command,
doc._id + '.' + current_revision,
function (result) {
doc.content = result.content;
am.call(o, 'success');
},
function (error) {
am.call(o, 'error', [error]);
}
);
};
o.checkForConflicts = function () {
if (metadata_file_content[current_revision]._conflict) {
on_conflict = true;
conflict_object = priv.createConflictObject(
command,
metadata_file_content,
current_revision
);
}
am.call(o, 'success');
};
o.success = function () {
am.neverCall(o, 'error');
am.neverCall(o, 'success');
if (command.getOption('revs')) {
doc._revisions = priv._revs(
metadata_file_content,
current_revision
);
}
if (command.getOption('revs_info')) {
doc._revs_info = priv._revs_info(metadata_file_content);
}
if (command.getOption('conflicts')) {
doc._conflicts = conflict_object;
}
that.success(doc);
};
o.error = function (error) {
var err = error || {
status: 0,
statusText: 'Unknown',
message: 'Unknown error.'
};
if (command.getOption('revs')) {
err._revisions = priv._revs(
metadata_file_content,
current_revision
);
}
if (command.getOption('revs_info')) {
err._revs_info = priv._revs_info(metadata_file_content);
}
if (command.getOption('conflicts')) {
err._conflicts = conflict_object;
}
am.neverCall(o, 'error');
am.neverCall(o, 'success');
that.error(err);
};
am.call(o, 'getDistantMetadata');
};
/**
* Get a document list from several storages, and returns the first
* retreived document list.
* @method allDocs
*/
that.allDocs = function (command) {
var o = {}, am = priv.newAsyncModule(),
metadata_only = command.getOption('metadata_only'),
result_list = [],
conflict_object = {
total_rows: 0,
rows: []
},
success_count = 0,
success_max = 0;
o.retreiveList = function () {
var cloned_option = command.cloneOption(),
success = function (result) {
am.call(o, 'filterTheList', [result]);
},
error = function (error) {
am.call(o, 'error', [error]);
};
cloned_option.metadata_only = true;
that.addJob('allDocs', priv.sub_storage_spec, null, cloned_option,
success, error
);
};
o.filterTheList = function (result) {
var i, splitname;
success_max += 1;
for (i = 0; i < result.total_rows; i += 1) {
splitname = result.rows[i].id.split('.') || [];
if (splitname.length > 0 && splitname[splitname.length - 1] ===
'metadata') {
success_max += 1;
splitname.length -= 1;
am.call(o, 'loadMetadataFile', [splitname.join('.')]);
}
}
am.call(o, 'success');
};
o.loadMetadataFile = function (path) {
priv.getDistantMetadata(
command,
path + '.metadata',
function (data) {
data = JSON.parse(data.content);
var revision = priv.chooseARevision(data);
if (!data[revision]._deleted) {
am.call(o, 'loadFile', [path, revision, data]);
} else {
am.call(o, 'success');
}
},
function (error) {
am.call(o, 'error', [error]);
}
);
};
o.loadFile = function (path, revision, data) {
var doc = {
id: path,
key: path,
value: {
_last_modified: data[revision]._last_modified,
_creation_date: data[revision]._creation_date,
_rev: revision
}
};
if (command.getOption('revs')) {
doc.value._revisions = priv._revs(data, revision);
}
if (command.getOption('revs_info')) {
doc.value._revs_info = priv._revs_info(data, revision);
}
if (command.getOption('conflicts')) {
if (data[revision]._conflict) {
conflict_object.total_rows += 1;
conflict_object.rows.push(
priv.createConflictRow(command, path, data, revision)
);
}
}
if (!metadata_only) {
priv.loadRevision(
command,
path + '.' + revision,
function (data) {
doc.content = data.content;
result_list.push(doc);
am.call(o, 'success');
},
function (error) {
am.call(o, 'error', [error]);
}
);
} else {
result_list.push(doc);
am.call(o, 'success');
}
};
o.success = function () {
var obj;
success_count += 1;
if (success_count >= success_max) {
am.end();
obj = {
total_rows: result_list.length,
rows: result_list
};
if (command.getOption('conflicts')) {
obj.conflicts = conflict_object;
}
that.success(obj);
}
};
o.error = function (error) {
am.end();
that.error(error);
};
am.call(o, 'retreiveList');
}; // end allDocs
/**
* Remove a document from several storages.
* @method remove
*/
that.remove = function (command) {
var o = {}, am = priv.newAsyncModule(),
metadata_file_path = command.getDocId() + '.metadata',
current_revision = '',
current_revision_file_path = '',
metadata_file_content = null,
on_conflict = false,
conflict_object = {
total_rows: 0,
rows: []
},
previous_revision = command.getOption('rev') || '0',
previous_revision_file_path = command.getDocId() + '.' +
previous_revision,
now = new Date(),
failerror;
o.getDistantMetadata = function () {
priv.getDistantMetadata(
command,
metadata_file_path,
function (result) {
metadata_file_content = JSON.parse(result.content);
if (previous_revision === 'last') {
previous_revision = priv.chooseARevision(metadata_file_content);
previous_revision_file_path = command.getDocId() + '.' +
previous_revision;
}
var previous_revision_number =
parseInt(previous_revision.split('-')[0], 10) || 0;
// set current revision
current_revision = (previous_revision_number + 1) + '-' +
//jslint: removed hex_sha256(''...
hex_sha256(previous_revision +
JSON.stringify(metadata_file_content)
);
current_revision_file_path = command.getDocId() + '.' +
current_revision;
am.call(o, 'checkForConflicts');
},
function (error) {
if (error.status === 404) {
am.call(o, 'error', [{
status: 404,
statusText: 'Not Found',
error: 'not_found',
reason: 'missing',
message: 'Document not found.'
}]);
} else {
am.call(o, 'error', [error]);
}
}
);
};
o.checkForConflicts = function () {
var rev;
for (rev in metadata_file_content) {
if (metadata_file_content.hasOwnProperty(rev) &&
rev !== previous_revision) {
on_conflict = true;
failerror = {
status: 409,
error: 'conflict',
statusText: 'Conflict',
reason: 'document update conflict',
message: 'There is one or more conflicts'
};
break;
}
}
am.call(o, 'updateMetadata');
};
o.updateMetadata = function () {
var previous_creation_date, revision_history = [],
id = '';
if (metadata_file_content[previous_revision]) {
previous_creation_date = metadata_file_content[
previous_revision
]._creation_date;
revision_history = metadata_file_content[
previous_revision
]._revisions;
delete metadata_file_content[previous_revision];
}
id = current_revision;
id = id.split('-');
id.shift();
id = id.join('-');
revision_history.unshift(id);
metadata_file_content[current_revision] = {
_creation_date: previous_creation_date || now.getTime(),
_last_modified: now.getTime(),
_revisions: revision_history,
_conflict: on_conflict,
_deleted: true
};
if (on_conflict) {
conflict_object = priv.createConflictObject(
command,
metadata_file_content,
current_revision
);
}
am.call(o, 'saveMetadataOnDistant');
};
o.saveMetadataOnDistant = function () {
priv.saveMetadataToDistant(
command,
metadata_file_path,
metadata_file_content,
function () {
am.call(o, 'deletePreviousRevision');
if (on_conflict) {
am.call(o, 'error');
} else {
am.call(o, 'success');
}
},
function (error) {
am.call(o, 'error', [error]);
}
);
};
o.deletePreviousRevision = function () {
// jslint: removed /*&& !on_conflict*/
if (previous_revision !== '0') {
priv.deleteAFile(
command,
previous_revision_file_path,
empty_fun,
empty_fun
);
}
};
o.success = function (revision) {
var a = {
ok: true,
id: command.getDocId(),
rev: revision || current_revision
};
am.neverCall(o, 'error');
am.neverCall(o, 'success');
if (command.getOption('revs')) {
a.revisions = priv._revs(
metadata_file_content,
current_revision
);
}
if (command.getOption('revs_info')) {
a.revs_info = priv._revs_info(metadata_file_content);
}
if (command.getOption('conflicts')) {
a.conflicts = conflict_object;
}
that.success(a);
};
o.error = function (error) {
var err = error || failerror || {
status: 0,
statusText: 'Unknown',
error: 'unknown_error',
message: 'Unknown error.',
reason: 'unknown error'
};
if (current_revision) {
err.rev = current_revision;
}
if (command.getOption('revs')) {
err.revisions = priv._revs(
metadata_file_content,
current_revision
);
}
if (command.getOption('revs_info')) {
err.revs_info = priv._revs_info(metadata_file_content);
}
if (command.getOption('conflicts')) {
err.conflicts = conflict_object;
}
am.neverCall(o, 'error');
am.neverCall(o, 'success');
that.error(err);
};
am.call(o, 'getDistantMetadata');
}; // end remove
return that;
});
/*
* Copyright 2013, Nexedi SA
* Released under the LGPL license.
* http://www.gnu.org/licenses/lgpl.html
*/
/*jslint indent: 2, maxlen: 80, nomen: true */
/*global define, jIO, jQuery, btoa */
// JIO Dav Storage Description :
// {
// type: "dav",
// url: {string}
// }
// {
// type: "dav",
// url: {string},
// auth_type: {string}, (optional)
// - "auto" (default) (not implemented)
// - "basic"
// - "digest" (not implemented)
// realm: {string}, (optional)
// - undefined (default) (not implemented)
// - "<string>" realm name (not implemented)
// username: {string},
// password: {string} (optional)
// }
// {
// type: "dav",
// url: {string},
// encoded_login: {string}
// }
// {
// type: "dav",
// url: {string},
// secured_login: {string} (not implemented)
// }
// NOTE: to get the authentication type ->
// curl --verbose -X OPTION http://domain/
// In the headers: "WWW-Authenticate: Basic realm="DAV-upload"
// URL Characters convertion:
// If I want to retrieve the file which id is -> http://100%.json
// http://domain/collection/http://100%.json cannot be applied
// - '/' is col separator,
// - '?' is url/parameter separator
// - '%' is special char
// - '.' document and attachment separator
// http://100%.json will become
// - http:%2F%2F100%25.json to avoid bad request ('/', '%' -> '%2F', '%25')
// - http:%2F%2F100%25_.json to avoid ids conflicts ('.' -> '_.')
// - http:%252F%252F100%2525_.json to avoid request bad interpretation
// ('%', '%25')
// The file will be saved as http:%2F%2F100%25_.json
// define([module_name], [dependencies], module);
(function (dependencies, module) {
"use strict";
if (typeof define === 'function' && define.amd) {
return define(dependencies, module);
}
module(jIO, jQuery);
}(['jio', 'jquery'], function (jIO, $) {
"use strict";
jIO.addStorageType("dav", function (spec, my) {
var priv = {}, that = my.basicStorage(spec, my), dav = {};
// ATTRIBUTES //
priv.url = null;
priv.username = null;
priv.password = null;
priv.encoded_login = null;
// CONSTRUCTOR //
/**
* Init the dav storage connector thanks to the description
* @method __init__
* @param {object} description The description object
*/
priv.__init__ = function (description) {
priv.url = description.url || "";
priv.url = priv.removeSlashIfLast(priv.url);
// if (description.secured_login) {
// not implemented
// } else
if (description.encoded_login) {
priv.encoded_login = description.encoded_login;
} else if (description.auth_type) {
if (description.auth_type === "basic") {
priv.encoded_login = "Basic " +
btoa((description.username || "") + ":" +
(description.password || ""));
}
} else {
priv.encoded_login = "";
}
};
// OVERRIDES //
that.specToStore = function () {
// TODO: secured password
// The encoded_login can be seen by anyone,
// we must find a way to secure it!
// secured_login = encrypt(encoded_login)
// encoded_login = decrypt(secured_login)
return {
"url": priv.url,
"encoded_login": priv.encoded_login
};
};
that.validateState = function () {
if (typeof priv.url !== "string" || priv.url === "") {
return "The webDav server URL is not provided";
}
if (priv.encoded_login === null) {
return "Impossible to create the authorization";
}
return "";
};
// TOOLS //
/**
* Generate a new uuid
* @method generateUuid
* @return {string} The new uuid
*/
priv.generateUuid = function () {
var S4 = function () {
/* 65536 */
var i, string = Math.floor(
Math.random() * 0x10000
).toString(16);
for (i = string.length; i < 4; i += 1) {
string = "0" + string;
}
return string;
};
return S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() +
S4() + S4();
};
// /**
// * Clones an object in deep
// * @method clone
// * @param {object} object The object to clone
// * @return {object} The cloned object
// */
// priv.clone = function (object) {
// var tmp = JSON.stringify(object);
// if (tmp === undefined) {
// return undefined;
// }
// return JSON.parse(tmp);
// };
/**
* Replace substrings to another strings
* @method recursiveReplace
* @param {string} string The string to do replacement
* @param {array} list_of_replacement An array of couple
* ["substring to select", "selected substring replaced by this string"].
* @return {string} The replaced string
*/
priv.recursiveReplace = function (string, list_of_replacement) {
var i, split_string = string.split(list_of_replacement[0][0]);
if (list_of_replacement[1]) {
for (i = 0; i < split_string.length; i += 1) {
split_string[i] = priv.recursiveReplace(
split_string[i],
list_of_replacement.slice(1)
);
}
}
return split_string.join(list_of_replacement[0][1]);
};
/**
* Changes spaces to %20, / to %2f, % to %25 and ? to %3f
* @method secureName
* @param {string} name The name to secure
* @return {string} The secured name
*/
priv.secureName = function (name) {
return priv.recursiveReplace(name, [
[" ", "%20"],
["/", "%2F"],
["%", "%25"],
["?", "%3F"]
]);
};
/**
* Restores the original name from a secured name
* @method restoreName
* @param {string} secured_name The secured name to restore
* @return {string} The original name
*/
priv.restoreName = function (secured_name) {
return priv.recursiveReplace(secured_name, [
["%20", " "],
["%2F", "/"],
["%25", "%"],
["%3F", "?"]
]);
};
/**
* Convert document id and attachment id to a file name
* @method idsToFileName
* @param {string} doc_id The document id
* @param {string} attachment_id The attachment id (optional)
* @return {string} The file name
*/
priv.idsToFileName = function (doc_id, attachment_id) {
doc_id = priv.secureName(doc_id).split(".").join("_.");
if (typeof attachment_id === "string") {
attachment_id = priv.secureName(attachment_id).split(".").join("_.");
return doc_id + "." + attachment_id;
}
return doc_id;
};
/**
* Convert a file name to a document id (and attachment id if there)
* @method fileNameToIds
* @param {string} file_name The file name to convert
* @return {array} ["document id", "attachment id"] or ["document id"]
*/
priv.fileNameToIds = function (file_name) {
var separator_index = -1, split = file_name.split(".");
split.slice(0, -1).forEach(function (file_name_part, index) {
if (file_name_part.slice(-1) !== "_") {
if (separator_index !== -1) {
separator_index = new TypeError("Corrupted file name");
separator_index.status = 24;
throw separator_index;
}
separator_index = index;
}
});
if (separator_index === -1) {
return [priv.restoreName(priv.restoreName(
file_name
).split("_.").join("."))];
}
return [
priv.restoreName(priv.restoreName(
split.slice(0, separator_index + 1).join(".")
).split("_.").join(".")),
priv.restoreName(priv.restoreName(
split.slice(separator_index + 1).join(".")
).split("_.").join("."))
];
};
/**
* Removes the last character if it is a "/". "/a/b/c/" become "/a/b/c"
* @method removeSlashIfLast
* @param {string} string The string to modify
* @return {string} The modified string
*/
priv.removeSlashIfLast = function (string) {
if (string[string.length - 1] === "/") {
return string.slice(0, -1);
}
return string;
};
/**
* Modify an ajax object to add default values
* @method makeAjaxObject
* @param {string} file_name The file name to add to the url
* @param {object} ajax_object The ajax object to override
* @return {object} A new ajax object with default values
*/
priv.makeAjaxObject = function (file_name, method, ajax_object) {
ajax_object.type = method || ajax_object.type || "GET";
ajax_object.url = priv.url + "/" + priv.secureName(file_name) +
"?_=" + Date.now();
ajax_object.async = ajax_object.async === false ? false : true;
ajax_object.crossdomain =
ajax_object.crossdomain === false ? false : true;
ajax_object.headers = ajax_object.headers || {};
ajax_object.headers.Authorization = ajax_object.headers.Authorization ||
priv.encoded_login;
return ajax_object;
};
/**
* Runs all ajax requests for davStorage
* @method ajax
* @param {string} doc_id The document id
* @param {string} attachment_id The attachment id, can be undefined
* @param {string} method The request method
* @param {object} ajax_object The request parameters (optional)
*/
priv.ajax = function (doc_id, attachment_id, method, ajax_object) {
var new_ajax_object = JSON.parse(JSON.stringify(ajax_object) || "{}");
return $.ajax(priv.makeAjaxObject(
priv.idsToFileName(doc_id || '', attachment_id),
method,
new_ajax_object
));//.always(then || function () {});
};
/**
* Creates error objects for this storage
* @method createError
* @param {string} url url to clean up
* @return {object} error The error object
*/
priv.createError = function (status, message, reason) {
var error = {
"status": status,
"message": message,
"reason": reason
};
switch (status) {
case 404:
error.statusText = "Not found";
break;
case 405:
error.statusText = "Method Not Allowed";
break;
case 409:
error.statusText = "Conflicts";
break;
case 24:
error.statusText = "Corrupted Document";
break;
}
error.error = error.statusText.toLowerCase().split(" ").join("_");
return error;
};
/**
* Converts ajax error object to a JIO error object
* @method ajaxErrorToJioError
* @param {object} ajax_error_object The ajax error object
* @param {string} message The error message
* @param {string} reason The error reason
* @return {object} The JIO error object
*/
priv.ajaxErrorToJioError = function (ajax_error_object, message, reason) {
var jio_error_object = {};
jio_error_object.status = ajax_error_object.status;
jio_error_object.statusText = ajax_error_object.statusText;
jio_error_object.error =
ajax_error_object.statusText.toLowerCase().split(" ").join("_");
jio_error_object.message = message;
jio_error_object.reason = reason;
return jio_error_object;
};
/**
* Function that create an object containing jQuery like callbacks
* @method makeJQLikeCallback
* @return {object} jQuery like callback methods
*/
priv.makeJQLikeCallback = function () {
var result = null, emptyFun = function () {}, jql = {
"respond": function () {
result = arguments;
},
"to_return": {
"always": function (func) {
if (result) {
func.apply(func, result);
jql.to_return.always = emptyFun;
} else {
jql.respond = func;
}
return jql.to_return;
},
"then": function (func) {
if (result) {
func(result[1]);
jql.to_return.then = emptyFun;
} else {
jql.respond = function (err, response) {
func(response);
};
}
return jql.to_return;
}
}
};
return jql;
};
// DAV REQUESTS //
/**
* Retrieve a document file
* @method dav.getDocument
* @param {string} doc_id The document id
*/
dav.getDocument = function (doc_id) {
var doc, jql = priv.makeJQLikeCallback(), error = null;
priv.ajax(doc_id, undefined, "GET").always(function (one, state, three) {
if (state !== "success") {
error = priv.ajaxErrorToJioError(
one,
"Cannot retrieve document",
"Unknown"
);
if (one.status === 404) {
error.reason = "Not Found";
}
return jql.respond(error, undefined);
}
try {
doc = JSON.parse(one);
} catch (e) {
return jql.respond(priv.createError(
24,
"Cannot parse document",
"Document is corrupted"
), undefined);
}
// document health is good
return jql.respond(undefined, doc);
});
return jql.to_return;
};
/**
* Retrieve an attachment file
* @method dav.getAttachment
* @param {string} doc_id The document id
* @param {string} attachment_id The attachment id
*/
dav.getAttachment = function (doc_id, attachment_id) {
var jql = priv.makeJQLikeCallback(), error = null;
priv.ajax(
doc_id,
attachment_id,
"GET"
).always(function (one, state, three) {
if (state !== "success") {
error = priv.ajaxErrorToJioError(
one,
"Cannot retrieve attachment",
"Unknown"
);
if (one.status === 404) {
error.reason = "Not Found";
}
return jql.respond(error, undefined);
}
return jql.respond(undefined, one);
});
return jql.to_return;
};
/**
* Uploads a document file
* @method dav.putDocument
* @param {object} doc The document object
*/
dav.putDocument = function (doc) {
var jql = priv.makeJQLikeCallback();
priv.ajax(doc._id, undefined, "PUT", {
"dataType": "text",
"data": JSON.stringify(doc)
}).always(function (one, state, three) {
if (state !== "success") {
return jql.respond(priv.ajaxErrorToJioError(
one,
"Cannot upload document",
"Unknown"
), undefined);
}
jql.respond(undefined, {"ok": true, "id": doc._id});
});
return jql.to_return;
};
/**
* Uploads an attachment file
* @method dav.putAttachment
* @param {string} doc_id The document id
* @param {string} attachment_id The attachment id
* @param {string} data The attachment data
*/
dav.putAttachment = function (doc_id, attachment_id, data) {
var jql = priv.makeJQLikeCallback();
priv.ajax(doc_id, attachment_id, "PUT", {
"dataType": "text",
"data": data
}).always(function (one, state, three) {
if (state !== "success") {
return jql.respond(priv.ajaxErrorToJioError(
one,
"Cannot upload attachment",
"Unknown"
), undefined);
}
return jql.respond(undefined, {
"ok": true,
"id": doc_id,
"attachment": attachment_id
});
});
return jql.to_return;
};
/**
* Deletes a document file
* @method dav.removeDocument
* @param {string} doc_id The document id
*/
dav.removeDocument = function (doc_id) {
var jql = priv.makeJQLikeCallback(), error = null;
priv.ajax(
doc_id,
undefined,
"DELETE"
).always(function (one, state, three) {
if (state !== "success") {
error = priv.ajaxErrorToJioError(
one,
"Cannot delete document",
"Unknown"
);
if (one.status === 404) {
error.reason = "Not Found";
}
return jql.respond(error, undefined);
}
jql.respond(undefined, {"ok": true, "id": doc_id});
});
return jql.to_return;
};
/**
* Deletes an attachment file
* @method dav.removeAttachment
* @param {string} doc_id The document id
* @param {string} attachment_id The attachment id
*/
dav.removeAttachment = function (doc_id, attachment_id) {
var jql = priv.makeJQLikeCallback(), error = null;
priv.ajax(
doc_id,
attachment_id,
"DELETE"
).always(function (one, state, three) {
if (state !== "success") {
error = priv.ajaxErrorToJioError(
one,
"Cannot delete attachment",
"Unknown"
);
if (one.status === 404) {
error.reason = "Not Found";
}
return jql.respond(error, undefined);
}
jql.respond(undefined, {"ok": true, "id": doc_id});
});
return jql.to_return;
};
/**
* Get a list of document file
* @method dav.allDocs
*/
dav.allDocs = function () {
var jql = priv.makeJQLikeCallback(), rows = [];
priv.ajax(undefined, undefined, "PROPFIND", {
"dataType": "xml",
"headers": {"Depth": 1}
}).always(function (one, state, three) {
var response, len;
if (state !== "success") {
return jql.respond(priv.ajaxErrorToJioError(
one,
"Cannot get the document list",
"Unknown"
), undefined);
}
response = $(one).find("D\\:response, response");
len = response.length;
if (len === 1) {
return jql.respond({"total_rows": 0, "rows": []});
}
response.each(function (i, data) {
var row;
if (i > 0) { // exclude parent folder
row = {
"id": "",
"key": "",
"value": {}
};
$(data).find("D\\:href, href").each(function () {
row.id = $(this).text().split('/').slice(-1)[0];
try {
row.id = priv.fileNameToIds(row.id);
} catch (e) {
if (e.name === "TypeError" && e.status === 24) {
return;
}
throw e;
}
if (row.id.length !== 1) {
row = undefined;
} else {
row.id = row.id[0];
row.key = row.id;
}
});
if (row !== undefined) {
rows.push(row);
}
}
});
jql.respond(undefined, {
"total_rows": rows.length,
"rows": rows
});
});
return jql.to_return;
};
// JIO COMMANDS //
// wedDav methods rfc4918 (short summary)
// COPY Reproduces single resources (files) and collections (directory
// trees). Will overwrite files (if specified by request) but will
// respond 209 (Conflict) if it would overwrite a tree
// DELETE deletes files and directory trees
// GET just the vanilla HTTP/1.1 behaviour
// HEAD ditto
// LOCK locks a resources
// MKCOL creates a directory
// MOVE Moves (rename or copy) a file or a directory tree. Will
// 'overwrite' files (if specified by the request) but will respond
// 209 (Conflict) if it would overwrite a tree.
// OPTIONS If WebDAV is enabled and available for the path this reports the
// WebDAV extension methods
// PROPFIND Retrieves the requested file characteristics, DAV lock status
// and 'dead' properties for individual files, a directory and its
// child files, or a directory tree
// PROPPATCHset and remove 'dead' meta-data properties
// PUT Update or create resource or collections
// UNLOCK unlocks a resource
// Notes: all Ajax requests should be CORS (cross-domain)
// adding custom headers triggers preflight OPTIONS request!
// http://remysharp.com/2011/04/21/getting-cors-working/
/**
* Creates a new document
* @method post
* @param {object} command The JIO command
*/
that.post = function (command) {
var doc_id = command.getDocId() || priv.generateUuid();
dav.getDocument(doc_id).always(function (err, response) {
if (err) {
if (err.status === 404) {
// the document does not already exist
// updating document
var doc = command.cloneDoc();
doc._id = doc_id;
return dav.putDocument(doc).always(function (err, response) {
if (err) {
return that.retry(err);
}
return that.success(response);
});
}
if (err.status === 24) {
return that.error(err);
}
// an error occured
return that.retry(err);
}
// the document already exists
return that.error(priv.createError(
405,
"Cannot create document",
"Document already exists"
));
});
};
/**
* Creates or updates a document
* @method put
* @param {object} command The JIO command
*/
that.put = function (command) {
dav.putDocument(command.cloneDoc()).always(function (err, response) {
if (err) {
// an error occured
return that.retry(err);
}
// document updated
return that.success(response);
});
};
/**
* Add an attachment to a document
* @method putAttachment
* @param {object} command The JIO command
*/
that.putAttachment = function (command) {
var doc = null, doc_id = command.getDocId(), attachment_id, tmp;
attachment_id = command.getAttachmentId();
dav.getDocument(doc_id).always(function (err, response) {
if (err) {
// document not found or error
tmp = that.retry;
if (err.status === 404 ||
err.status === 24) {
tmp = that.error;
}
return tmp(err);
}
doc = response;
doc._attachments = doc._attachments || {};
doc._attachments[attachment_id] = {
"length": command.getAttachmentLength(),
"digest": "md5-" + command.md5SumAttachmentData(),
"content_type": command.getAttachmentMimeType()
};
// put the attachment
dav.putAttachment(
doc_id,
attachment_id,
command.getAttachmentData()
).always(function (err, response) {
if (err) {
// an error occured
return that.retry(err);
}
// update the document
dav.putDocument(doc).always(function (err, response) {
if (err) {
return that.retry(err);
}
response.attachment = attachment_id;
return that.success(response);
});
});
});
};
/**
* Get a document
* @method get
* @param {object} command The JIO command
*/
that.get = function (command) {
dav.getDocument(command.getDocId()).always(function (err, response) {
if (err) {
if (err.status === 404 ||
err.status === 24) {
return that.error(err);
}
return that.retry(err);
}
return that.success(response);
});
};
/**
* Get an attachment
* @method getAttachment
* @param {object} command The JIO command
*/
that.getAttachment = function (command) {
dav.getAttachment(
command.getDocId(),
command.getAttachmentId()
).always(function (err, response) {
if (err) {
if (err.status === 404) {
return that.error(err);
}
return that.retry(err);
}
return that.success(response);
});
};
/**
* Remove a document
* @method remove
* @param {object} command The JIO command
*/
that.remove = function (command) {
var doc_id = command.getDocId(), count = 0, end;
end = function () {
count -= 1;
if (count === 0) {
that.success({"ok": true, "id": doc_id});
}
};
dav.getDocument(doc_id).always(function (err, response) {
var attachment_id = null;
if (err) {
if (err.status === 404) {
return that.error(err);
}
if (err.status !== 24) { // 24 -> corrupted document
return that.retry(err);
}
response = {};
}
count += 2;
dav.removeDocument(doc_id).always(function (err, response) {
if (err) {
if (err.status === 404) {
return that.error(err);
}
return that.retry(err);
}
return end();
});
for (attachment_id in response._attachments) {
if (response._attachments.hasOwnProperty(attachment_id)) {
count += 1;
dav.removeAttachment(
doc_id,
attachment_id
).always(end);
}
}
end();
});
};
/**
* Remove an attachment
* @method removeAttachment
* @param {object} command The JIO command
*/
that.removeAttachment = function (command) {
var doc_id = command.getDocId(), doc, attachment_id;
attachment_id = command.getAttachmentId();
dav.getDocument(doc_id).always(function (err, response) {
var still_has_attachments;
if (err) {
if (err.status === 404 ||
err.status === 24) {
return that.error(err);
}
return that.retry(err);
}
doc = response;
if (typeof (doc._attachments || {})[attachment_id] !== "object") {
return that.error(priv.createError(
404,
"Cannot remove attachment",
"Not Found"
));
}
delete doc._attachments[attachment_id];
// check if there is still attachments
for (still_has_attachments in doc._attachments) {
if (doc._attachments.hasOwnProperty(still_has_attachments)) {
break;
}
}
if (still_has_attachments === undefined) {
delete doc._attachments;
}
doc._id = doc_id;
dav.putDocument(doc).always(function (err, response) {
if (err) {
return that.retry(err);
}
dav.removeAttachment(
doc_id,
attachment_id
).always(function (err, response) {
that.success({
"ok": true,
"id": doc_id,
"attachment": attachment_id
});
});
});
});
};
/**
* Gets a document list from a distant dav storage
* Options:
* - {boolean} include_docs Also retrieve the actual document content.
* @method allDocs
* @param {object} command The JIO command
*/
that.allDocs = function (command) {
var count = 0, end, rows;
end = function () {
count -= 1;
if (count === 0) {
that.success(rows);
}
};
dav.allDocs().always(function (err, response) {
if (err) {
return that.retry(err);
}
if (command.getOption("include_docs") === true) {
count += 1;
rows = response;
rows.rows.forEach(function (row) {
count += 1;
dav.getDocument(
row.id
).always(function (err, response) {
if (err) {
if (err.status === 404 || err.status === 24) {
return that.error(err);
}
return that.retry(err);
}
row.doc = response;
end();
});
});
end();
} else {
that.success(response);
}
});
};
priv.__init__(spec);
return that;
});
}));
/*
* Copyright 2013, Nexedi SA
* Released under the LGPL license.
* http://www.gnu.org/licenses/lgpl.html
*/
/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
/*global define, jIO, setTimeout, complex_queries */
// define([module_name], [dependencies], module);
(function (dependencies, module) {
"use strict";
if (typeof define === 'function' && define.amd) {
return define(dependencies, module);
}
module(jIO);
}(['jio'], function (jIO) {
var storage = {};
/**
* Returns 4 hexadecimal random characters.
*
* @return {String} The characters
*/
function S4() {
return ('0000' + Math.floor(
Math.random() * 0x10000 /* 65536 */
).toString(16)).slice(-4);
}
/**
* An Universal Unique ID generator
*
* @return {String} The new UUID.
*/
function generateUuid() {
return S4() + S4() + "-" +
S4() + "-" +
S4() + "-" +
S4() + "-" +
S4() + S4() + S4();
}
/**
* Checks if an object has no enumerable keys
*
* @param {Object} obj The object
* @return {Boolean} true if empty, else false
*/
function objectIsEmpty(obj) {
var k;
for (k in obj) {
if (obj.hasOwnProperty(k)) {
return false;
}
}
return true;
}
/**
* JIO Ram Storage. Type = 'ram'.
* Memory "database" storage.
*
* Storage Description:
*
* {
* "type": "ram",
* "namespace": <string>, // default 'default'
* }
*
* Document are stored in path
* 'namespace/document_id' like this:
*
* {
* "_id": "document_id",
* "_attachments": {
* "attachment_name": {
* "length": data_length,
* "digest": "md5-XXX",
* "content_type": "mime/type"
* },
* "attachment_name2": {..}, ...
* },
* "metadata_name": "metadata_value"
* "metadata_name2": ...
* ...
* }
*
* Only "_id" and "_attachments" are specific metadata keys, other one can be
* added without loss.
*
* @class RamStorage
*/
function ramStorage(spec, my) {
var that, priv = {}, ramstorage;
that = my.basicStorage(spec, my);
/*
* Wrapper for the localStorage used to simplify instion of any kind of
* values
*/
ramstorage = {
getItem: function (item) {
var value = storage[item];
return value === undefined ? null : JSON.parse(value);
},
setItem: function (item, value) {
storage[item] = JSON.stringify(value);
},
removeItem: function (item) {
delete storage[item];
}
};
// attributes
if (typeof spec.namespace !== 'string') {
priv.namespace = 'default';
} else {
priv.namespace = spec.namespace;
}
// ===================== overrides ======================
that.specToStore = function () {
return {
"namespace": priv.namespace
};
};
that.validateState = function () {
return '';
};
// ==================== commands ====================
/**
* Create a document in local storage.
* @method post
* @param {object} command The JIO command
*/
that.post = function (command) {
setTimeout(function () {
var doc, doc_id = command.getDocId();
if (!doc_id) {
doc_id = generateUuid();
}
doc = ramstorage.getItem(priv.namespace + "/" + doc_id);
if (doc === null) {
// the document does not exist
doc = command.cloneDoc();
doc._id = doc_id;
delete doc._attachments;
ramstorage.setItem(priv.namespace + "/" + doc_id, doc);
that.success({
"ok": true,
"id": doc_id
});
} else {
// the document already exists
that.error({
"status": 409,
"statusText": "Conflicts",
"error": "conflicts",
"message": "Cannot create a new document",
"reason": "Document already exists"
});
}
});
};
/**
* Create or update a document in local storage.
* @method put
* @param {object} command The JIO command
*/
that.put = function (command) {
setTimeout(function () {
var doc, tmp;
doc = ramstorage.getItem(priv.namespace + "/" + command.getDocId());
if (doc === null) {
// the document does not exist
doc = command.cloneDoc();
delete doc._attachments;
} else {
// the document already exists
tmp = command.cloneDoc();
tmp._attachments = doc._attachments;
doc = tmp;
}
// write
ramstorage.setItem(priv.namespace + "/" + command.getDocId(), doc);
that.success({
"ok": true,
"id": command.getDocId()
});
});
};
/**
* Add an attachment to a document
* @method putAttachment
* @param {object} command The JIO command
*/
that.putAttachment = function (command) {
setTimeout(function () {
var doc;
doc = ramstorage.getItem(priv.namespace + "/" + command.getDocId());
if (doc === null) {
// the document does not exist
that.error({
"status": 404,
"statusText": "Not Found",
"error": "not_found",
"message": "Impossible to add attachment",
"reason": "Document not found"
});
return;
}
// the document already exists
doc._attachments = doc._attachments || {};
doc._attachments[command.getAttachmentId()] = {
"content_type": command.getAttachmentMimeType(),
"digest": "md5-" + command.md5SumAttachmentData(),
"length": command.getAttachmentLength()
};
// upload data
ramstorage.setItem(priv.namespace + "/" + command.getDocId() + "/" +
command.getAttachmentId(),
command.getAttachmentData());
// write document
ramstorage.setItem(priv.namespace + "/" + command.getDocId(), doc);
that.success({
"ok": true,
"id": command.getDocId(),
"attachment": command.getAttachmentId()
});
});
};
/**
* Get a document
* @method get
* @param {object} command The JIO command
*/
that.get = function (command) {
setTimeout(function () {
var doc = ramstorage.getItem(priv.namespace + "/" + command.getDocId());
if (doc !== null) {
that.success(doc);
} else {
that.error({
"status": 404,
"statusText": "Not Found",
"error": "not_found",
"message": "Cannot find the document",
"reason": "Document does not exist"
});
}
});
};
/**
* Get a attachment
* @method getAttachment
* @param {object} command The JIO command
*/
that.getAttachment = function (command) {
setTimeout(function () {
var doc = ramstorage.getItem(priv.namespace + "/" + command.getDocId() +
"/" + command.getAttachmentId());
if (doc !== null) {
that.success(doc);
} else {
that.error({
"status": 404,
"statusText": "Not Found",
"error": "not_found",
"message": "Cannot find the attachment",
"reason": "Attachment does not exist"
});
}
});
};
/**
* Remove a document
* @method remove
* @param {object} command The JIO command
*/
that.remove = function (command) {
setTimeout(function () {
var doc, i, attachment_list;
doc = ramstorage.getItem(priv.namespace + "/" + command.getDocId());
attachment_list = [];
if (doc !== null && typeof doc === "object") {
if (typeof doc._attachments === "object") {
// prepare list of attachments
for (i in doc._attachments) {
if (doc._attachments.hasOwnProperty(i)) {
attachment_list.push(i);
}
}
}
} else {
return that.error({
"status": 404,
"statusText": "Not Found",
"error": "not_found",
"message": "Document not found",
"reason": "missing"
});
}
ramstorage.removeItem(priv.namespace + "/" + command.getDocId());
// delete all attachments
for (i = 0; i < attachment_list.length; i += 1) {
ramstorage.removeItem(priv.namespace + "/" + command.getDocId() +
"/" + attachment_list[i]);
}
that.success({
"ok": true,
"id": command.getDocId()
});
});
};
/**
* Remove an attachment
* @method removeAttachment
* @param {object} command The JIO command
*/
that.removeAttachment = function (command) {
setTimeout(function () {
var doc, error, i, attachment_list;
error = function (word) {
that.error({
"status": 404,
"statusText": "Not Found",
"error": "not_found",
"message": word + " not found",
"reason": "missing"
});
};
doc = ramstorage.getItem(priv.namespace + "/" + command.getDocId());
// remove attachment from document
if (doc !== null && typeof doc === "object" &&
typeof doc._attachments === "object") {
if (typeof doc._attachments[command.getAttachmentId()] ===
"object") {
delete doc._attachments[command.getAttachmentId()];
if (priv.objectIsEmpty(doc._attachments)) {
delete doc._attachments;
}
ramstorage.setItem(priv.namespace + "/" + command.getDocId(),
doc);
ramstorage.removeItem(priv.namespace + "/" + command.getDocId() +
"/" + command.getAttachmentId());
that.success({
"ok": true,
"id": command.getDocId(),
"attachment": command.getAttachmentId()
});
} else {
error("Attachment");
}
} else {
error("Document");
}
});
};
/**
* Get all filenames belonging to a user from the document index
* @method allDocs
* @param {object} command The JIO command
*/
that.allDocs = function (command) {
var i, row, path_re, rows = [], document_list, option, document_object;
document_list = [];
path_re = new RegExp(
"^" + complex_queries.stringEscapeRegexpCharacters(priv.namespace) +
"/[^/]+$"
);
option = command.cloneOption();
if (typeof complex_queries !== "object" ||
(option.query === undefined && option.sort_on === undefined &&
option.select_list === undefined &&
option.include_docs === undefined)) {
rows = [];
for (i in storage) {
if (storage.hasOwnProperty(i)) {
// filter non-documents
if (path_re.test(i)) {
row = {"value": {}};
row.id = i.split('/').slice(-1)[0];
row.key = row.id;
if (command.getOption('include_docs')) {
row.doc = ramstorage.getItem(i);
}
rows.push(row);
}
}
}
that.success({"rows": rows, "total_rows": rows.length});
} else {
// create complex query object from returned results
for (i in storage) {
if (storage.hasOwnProperty(i)) {
if (path_re.test(i)) {
document_list.push(ramstorage.getItem(i));
}
}
}
option.select_list = option.select_list || [];
option.select_list.push("_id");
if (option.include_docs === true) {
document_object = {};
document_list.forEach(function (meta) {
document_object[meta._id] = meta;
});
}
complex_queries.QueryFactory.create(option.query || "").
exec(document_list, option);
document_list = document_list.map(function (value) {
var o = {
"id": value._id,
"key": value._id
};
if (option.include_docs === true) {
o.doc = document_object[value._id];
delete document_object[value._id];
}
delete value._id;
o.value = value;
return o;
});
that.success({"total_rows": document_list.length,
"rows": document_list});
}
};
return that;
}
jIO.addStorageType('ram', ramStorage);
}));
/*jslint indent: 2, maxlen: 80, nomen: true */
/*global define, jIO, jio_tests, window, test, ok, deepEqual, sinon, expect */
// define([module_name], [dependencies], module);
(function (dependencies, module) {
"use strict";
if (typeof define === 'function' && define.amd) {
return define(dependencies, module);
}
module(jIO, jio_tests);
}(['jio', 'jio_tests', 'davstorage'], function (jIO, util) {
"use strict";
function generateTools() {
return {
clock: sinon.useFakeTimers(),
spy: util.ospy,
tick: util.otick
};
}
module("DAVStorage");
test("Post", function () {
var o = generateTools(this);
o.jio = jIO.newJio({
"type": "dav",
"url": "https://ca-davstorage:8080",
"auth_type": "basic",
"username": "admin",
"password": "pwd"
});
// post without id
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/[0-9a-fA-F]{4}"),
[
404,
{"Content-Type": "text/html"},
"<h1>Document not found</h1>"
]
);
o.server.respondWith(
"PUT",
new RegExp("https://ca-davstorage:8080/[0-9a-fA-F]{4}"),
[
200,
{"Content-Type": "text/html"},
"<h1>Document updated!</h1>"
]
);
o.spy(o, "jobstatus", "done", "Post without id");
o.jio.post({}, {"max_retry": 1}, function (err, response) {
o.f.apply(arguments);
if (response) {
ok(util.isUuid(response.id), "Uuid should look like " +
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx : " + response.id);
}
});
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
// post document with id
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
404,
{"Content-Type": "text/html"},
"<h1>Document not found</h1>"
]
);
o.server.respondWith(
"PUT",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
200,
{"Content-Type": "text/html"},
"<h1>Document updated!</h1>"
]
);
o.spy(o, "value", {"id": "http://100%.json", "ok": true},
"Create document with an id");
o.jio.post({
"_id": "http://100%.json",
"title": "Hello There"
}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
// post already existant file
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
200,
{"Content-Type": "text/plain"},
'{"_id":"doc1","title":"Hello There"}'
]
);
o.spy(o, "status", 405, "Update document previous -> 405");
o.jio.post({
"_id": "http://100%.json",
"title": "Hello There Again"
}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
util.closeAndcleanUpJio(o.jio);
});
test("Put", function () {
var o = generateTools(this);
o.jio = jIO.newJio({
"type": "dav",
"url": "https://ca-davstorage:8080",
"auth_type": "basic",
"username": "admin",
"password": "pwd"
});
// put without id => 20 Id Required
o.spy(o, "status", 20, "Put without id -> 20");
o.jio.put({}, o.f);
o.tick(o);
// put non empty document
o.server = sinon.fakeServer.create();
o.server.respondWith(
"PUT",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
200,
{"Content-Type": "text/html"},
"<h1>OK1</h1>"
]
);
o.spy(o, "value", {"ok": true, "id": "http://100%.json"},
"Create document");
o.jio.put({
"_id": "http://100%.json",
"title": "Hi There"
}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
// update document
o.server = sinon.fakeServer.create();
o.server.respondWith(
"PUT",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
200,
{"Content-Type": "text/html"},
"<h1>OK!</h1>"
]
);
o.spy(o, "value", {"ok": true, "id": "http://100%.json"},
"Update document");
o.jio.put({
"_id": "http://100%.json",
"title": "Hi There Again"
}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
// putAttachment without document id => 20 Id Required
o.spy(o, "status", 20, "PutAttachment without doc id -> 20");
o.jio.putAttachment({"_attachment": "body.html"}, o.f);
o.tick(o);
// putAttachment without attachment id => 22 Attachment Id Required
o.spy(o, "status", 22, "PutAttachment without attachment id -> 22");
o.jio.putAttachment({"_id": "http://100%.json"}, o.f);
o.tick(o);
// putAttachment without underlying document => 404 Not Found
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
404,
{"Content-Type": "text/html"},
"<h1>Not Found</h1>"
]
);
o.spy(o, "status", 404, "PutAttachment without document -> 404");
o.jio.putAttachment({
"_id": "http://100%.json",
"_attachment": "putattmt2"
}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
// upload attachment
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
200,
{"Content-Type": "text/plain"},
'{"_id":"http://100%.json","title":"Hi There!"}'
]
);
o.server.respondWith(
"PUT",
new RegExp("https://ca-davstorage:8080/" +
"http:%252F%252F100%2525_\\.json.body_\\.html"),
[
200,
{"Content-Type": "text/html"},
"<h1>OK!</h1>"
]
);
o.server.respondWith(
"PUT",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
200,
{"Content-Type": "text/html"},
"<h1>OK!</h1>"
]
);
o.spy(o, "value", {
"ok": true,
"id": "http://100%.json",
"attachment": "body.html"
}, "Upload attachment");
o.jio.putAttachment({
"_id": "http://100%.json",
"_attachment": "body.html",
"_mimetype": "text/html",
"_data": "<h1>Hi There!!</h1><p>How are you?</p>"
}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
util.closeAndcleanUpJio(o.jio);
});
test("Get", function () {
var o = generateTools(this);
o.jio = jIO.newJio({
"type": "dav",
"url": "https://ca-davstorage:8080",
"auth_type": "basic",
"username": "admin",
"password": "pwd"
});
// get inexistent document
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
404,
{"Content-Type": "text/html"},
"<h1>Not Found</h1>"
]
);
o.spy(o, "status", 404, "Get non existing document -> 404");
o.jio.get({"_id": "http://100%.json"}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
// get document
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
200,
{"Content-Type": "text/html"},
'{"_id":"http://100%.json","title":"Hi There!"}'
]
);
o.spy(o, "value", {"_id": "http://100%.json", "title": "Hi There!"},
"Get document");
o.jio.get({"_id": "http://100%.json"}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
// get inexistent attachment
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/" +
"http:%252F%252F100%2525_\\.json\\.body_\\.html"),
[
404,
{"Content-Type": "text/html"},
"<h1>Not Found</h1>"
]
);
o.spy(o, "status", 404, "Get inexistent attachment -> 404");
o.jio.getAttachment({
"_id": "http://100%.json",
"_attachment": "body.html"
}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
// get attachment
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/" +
"http:%252F%252F100%2525_\\.json\\.body_\\.html"),
[
200,
{"Content-Type": "text/plain"},
"My Attachment Content"
]
);
o.spy(o, "value", "My Attachment Content", "Get attachment");
o.jio.getAttachment({
"_id": "http://100%.json",
"_attachment": "body.html"
}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
util.closeAndcleanUpJio(o.jio);
});
test("Remove", function () {
var o = generateTools(this);
o.jio = jIO.newJio({
"type": "dav",
"url": "https://ca-davstorage:8080",
"auth_type": "basic",
"username": "admin",
"password": "pwd"
});
// remove inexistent document
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
404,
{"Content-Type": "text/html"},
"<h1>Not Found</h1>"
]
);
o.spy(o, "status", 404, "Remove inexistent document -> 404");
o.jio.remove({"_id": "http://100%.json"}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
// remove document
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
200,
{"Content-Type": "text/html"},
"{My corrupted document}"
]
);
o.server.respondWith(
"DELETE",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
200,
{"Content-Type": "text/plain"},
"<h1>Deleted</h1>"
]
);
o.spy(o, "value", {"ok": true, "id": "http://100%.json"},
"Remove document");
o.jio.remove({"_id": "http://100%.json"}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
// remove inexistent attachment
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
200,
{"Content-Type": "text/plain"},
"{}"
]
);
o.spy(o, "status", 404, "Remove inexistent attachment -> 404");
o.jio.removeAttachment({
"_id": "http://100%.json",
"_attachment": "body.html"
}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
// o.server.respond();
// o.server.respond();
o.server.restore();
// remove attachment
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
200,
{"Content-Type": "text/plain"},
JSON.stringify({
"_attachments": {
"body.html": {
"length": 32,
"digest": "md5-dontcare",
"content_type": "text/html"
}
}
})
]
);
o.server.respondWith(
"PUT",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
200,
{"Content-Type": "text/html"},
"<h1>OK</h1>"
]
);
o.server.respondWith(
"DELETE",
new RegExp("https://ca-davstorage:8080/" +
"http:%252F%252F100%2525_\\.json.body_\\.html"),
[
200,
{"Content-Type": "text/html"},
"<h1>OK</h1>"
]
);
o.spy(o, "value", {
"ok": true,
"id": "http://100%.json",
"attachment": "body.html"
}, "Remove attachment");
o.jio.removeAttachment({
"_id": "http://100%.json",
"_attachment": "body.html"
}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
// remove document with multiple attachments
o.server = sinon.fakeServer.create();
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
200,
{"Content-Type": "text/html"},
JSON.stringify({
"_attachments": {
"body.html": {
"length": 32,
"digest": "md5-dontcare",
"content_type": "text/html"
},
"other": {
"length": 3,
"digest": "md5-dontcare-again",
"content_type": "text/plain"
}
}
})
]
);
o.server.respondWith(
"DELETE",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
200,
{"Content-Type": "text/plain"},
"<h1>Deleted</h1>"
]
);
o.server.respondWith(
"DELETE",
new RegExp("https://ca-davstorage:8080/" +
"http:%252F%252F100%2525_\\.json\\.body_\\.html"),
[
200,
{"Content-Type": "text/plain"},
"<h1>Deleted</h1>"
]
);
o.server.respondWith(
"DELETE",
new RegExp("https://ca-davstorage:8080/" +
"http:%252F%252F100%2525_\\.json\\.other"),
[
200,
{"Content-Type": "text/plain"},
"<h1>Deleted</h1>"
]
);
o.spy(o, "value", {"ok": true, "id": "http://100%.json"},
"Remove document containing multiple attachments");
o.jio.remove({"_id": "http://100%.json"}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
util.closeAndcleanUpJio(o.jio);
});
test("AllDocs", function () {
// need to make server requests before activating fakeServer
var davlist, o = generateTools();
davlist = "<?xml version=\"1.0\" encoding=\"utf-8\"?> <D:multist" +
"atus xmlns:D=\"DAV:\"> <D:response xmlns:lp1=\"DAV:\" xmlns:lp2" +
"=\"http://apache.org/dav/props/\"> <D:href>/some/path/</D:href>" +
" <D:propstat> <D:prop> <lp1:resourcetype><D:collection/></lp1:r" +
"esourcetype> <lp1:creationdate>2012-05-02T12:48:33Z</lp1:creati" +
"ondate> <lp1:getlastmodified>Wed, 02 May 2012 12:48:33 GMT</lp1" +
":getlastmodified> <lp1:getetag>\"1000-4bf0d1aeb9e43\"</lp1:gete" +
"tag> <D:supportedlock> <D:lockentry> <D:lockscope><D:exclusive/" +
"></D:lockscope> <D:locktype><D:write/></D:locktype> </D:lockent" +
"ry> <D:lockentry> <D:lockscope><D:shared/></D:lockscope> <D:loc" +
"ktype><D:write/></D:locktype> </D:lockentry> </D:supportedlock>" +
" <D:lockdiscovery/> <D:getcontenttype>httpd/unix-directory</D:g" +
"etcontenttype> </D:prop> <D:status>HTTP/1.1 200 OK</D:status> <" +
"/D:propstat> </D:response> <D:response xmlns:lp1=\"DAV:\" xmlns" +
":lp2=\"http://apache.org/dav/props/\"> <D:href>/some/path/http:" +
"%252F%252F100%2525_.json</D:href> <D:propstat> <D:prop> <lp1:re" +
"sourcetype/> <lp1:creationdate>2012-05-02T12:48:31Z</lp1:creati" +
"ondate> <lp1:getcontentlength>201</lp1:getcontentlength> <lp1:g" +
"etlastmodified>Wed, 02 May 2012 12:48:27 GMT</lp1:getlastmodifi" +
"ed> <lp1:getetag>\"c9-4bf0d1a845df9\"</lp1:getetag> <lp2:execut" +
"able>F</lp2:executable> <D:supportedlock> <D:lockentry> <D:lock" +
"scope><D:exclusive/></D:lockscope> <D:locktype><D:write/></D:lo" +
"cktype> </D:lockentry> <D:lockentry> <D:lockscope><D:shared/></" +
"D:lockscope> <D:locktype><D:write/></D:locktype> </D:lockentry>" +
" </D:supportedlock> <D:lockdiscovery/> </D:prop> <D:status>HTTP" +
"/1.1 200 OK</D:status> </D:propstat> </D:response> <D:response " +
"xmlns:lp1=\"DAV:\" xmlns:lp2=\"http://apache.org/dav/props/\"> " +
"<D:href>/some/path/ISBN:1038729410372</D:href> <D:propstat> <D:" +
"prop> <lp1:resourcetype/> <lp1:creationdate>2012-05-01T17:41:13" +
"Z</lp1:creationdate> <lp1:getcontentlength>223</lp1:getcontentl" +
"ength> <lp1:getlastmodified>Wed, 02 May 2012 10:48:33 GMT</lp1:" +
"getlastmodified> <lp1:getetag>\"c9-4bf0d1aeb9e43\"</lp1:getetag" +
"> <lp2:executable>F</lp2:executable> <D:supportedlock> <D:locke" +
"ntry> <D:lockscope><D:exclusive/></D:lockscope> <D:locktype><D:" +
"write/></D:locktype> </D:lockentry> <D:lockentry> <D:lockscope>" +
"<D:shared/></D:lockscope> <D:locktype><D:write/></D:locktype> <" +
"/D:lockentry> </D:supportedlock> <D:lockdiscovery/> </D:prop> <" +
"D:status>HTTP/1.1 200 OK</D:status> </D:propstat> </D:response>" +
" <D:response xmlns:lp1=\"DAV:\" xmlns:lp2=\"http://apache.org/d" +
"av/props/\"> <D:href>/some/path/http:%252F%252F100%2525_.json.b" +
"ody_.html</D:href> <D:propstat> <D:prop> <lp1:resourcetype/> <l" +
"p1:creationdate>2012-05-01T17:41:13Z</lp1:creationdate> <lp1:ge" +
"tcontentlength>223</lp1:getcontentlength> <lp1:getlastmodified>" +
"Wed, 02 May 2012 10:48:33 GMT</lp1:getlastmodified> <lp1:geteta" +
"g>\"c9-4bf0d1aeb9e43\"</lp1:getetag> <lp2:executable>F</lp2:exe" +
"cutable> <D:supportedlock> <D:lockentry> <D:lockscope><D:exclus" +
"ive/></D:lockscope> <D:locktype><D:write/></D:locktype> </D:loc" +
"kentry> <D:lockentry> <D:lockscope><D:shared/></D:lockscope> <D" +
":locktype><D:write/></D:locktype> </D:lockentry> </D:supportedl" +
"ock> <D:lockdiscovery/> </D:prop> <D:status>HTTP/1.1 200 OK</D:" +
"status> </D:propstat> </D:response> </D:multistatus>";
o.jio = jIO.newJio({
"type": "dav",
"url": "https://ca-davstorage:8080",
"auth_type": "basic",
"username": "admin",
"password": "pwd"
});
// get all documents
o.server = sinon.fakeServer.create();
o.server.respondWith(
"PROPFIND",
new RegExp("https://ca-davstorage:8080/"),
[
200,
{"Content-Type": "text/xml"},
davlist
]
);
o.spy(o, "value", {
"rows": [
{"id": "http://100%.json", "key": "http://100%.json", "value": {}},
{"id": "ISBN:1038729410372", "key": "ISBN:1038729410372", "value": {}}
],
"total_rows": 2
}, "allDocs");
o.jio.allDocs(o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
// allDocs with option include_docs
o.server = sinon.fakeServer.create();
o.server.respondWith(
"PROPFIND",
new RegExp("https://ca-davstorage:8080/"),
[
200,
{"Content-Type": "text/xml"},
davlist
]
);
o.doc1 = {"_id": "http://100%.json", "_attachments": {
"body.html": {
"length": 32,
"digest": "md5-doncare",
"content_type": "text/html"
}
}};
o.doc2 = {"_id": "ISBN:1038729410372", "title": "Book Title"};
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/http:%252F%252F100%2525_\\.json"),
[
200,
{"Content-Type": "text/plain"},
JSON.stringify(o.doc1)
]
);
o.server.respondWith(
"GET",
new RegExp("https://ca-davstorage:8080/ISBN:1038729410372"),
[
200,
{"Content-Type": "text/plain"},
JSON.stringify(o.doc2)
]
);
o.spy(o, "value", {
"rows": [{
"id": "http://100%.json",
"key": "http://100%.json",
"value": {},
"doc": o.doc1
}, {
"id": "ISBN:1038729410372",
"key": "ISBN:1038729410372",
"value": {},
"doc": o.doc2
}],
"total_rows": 2
}, "allDocs (include_docs)");
o.jio.allDocs({"include_docs": true}, o.f);
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
util.closeAndcleanUpJio(o.jio);
});
}));
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment