Commit 6c2edc36 authored by Tristan Cavelier's avatar Tristan Cavelier

Storages Files concat & min

parent 91a84412
/*! JIO Storage - v0.1.0 - 2012-08-07 /*! JIO Storage - v0.1.0 - 2012-08-14
* Copyright (c) 2012 Nexedi; Licensed */ * Copyright (c) 2012 Nexedi; Licensed */
(function(LocalOrCookieStorage, $, Base64, sjcl, hex_sha256, Jio) { (function(LocalOrCookieStorage, $, Base64, sjcl, hex_sha256, Jio) {
...@@ -6,12 +6,32 @@ ...@@ -6,12 +6,32 @@
var newLocalStorage = function ( spec, my ) { var newLocalStorage = function ( spec, my ) {
var that = Jio.storage( spec, my, 'base' ), priv = {}; var that = Jio.storage( spec, my, 'base' ), priv = {};
priv.secureDocId = function (string) {
var split = string.split('/'), i;
if (split[0] === '') {
split = split.slice(1);
}
for (i = 0; i < split.length; i+= 1) {
if (split[i] === '') { return ''; }
}
return split.join('%2F');
};
priv.convertSlashes = function (string) {
return string.split('/').join('%2F');
};
priv.restoreSlashes = function (string) {
return string.split('%2F').join('/');
};
priv.username = spec.username || ''; priv.username = spec.username || '';
priv.secured_username = priv.convertSlashes(priv.username);
priv.applicationname = spec.applicationname || 'untitled'; priv.applicationname = spec.applicationname || 'untitled';
priv.secured_applicationname = priv.convertSlashes(priv.applicationname);
var storage_user_array_name = 'jio/local_user_array'; var storage_user_array_name = 'jio/local_user_array';
var storage_file_array_name = 'jio/local_file_name_array/' + var storage_file_array_name = 'jio/local_file_name_array/' +
priv.username + '/' + priv.applicationname; priv.secured_username + '/' + priv.secured_applicationname;
var super_serialized = that.serialized; var super_serialized = that.serialized;
that.serialized = function() { that.serialized = function() {
...@@ -22,7 +42,7 @@ var newLocalStorage = function ( spec, my ) { ...@@ -22,7 +42,7 @@ var newLocalStorage = function ( spec, my ) {
}; };
that.validateState = function() { that.validateState = function() {
if (priv.username) { if (priv.secured_username) {
return ''; return '';
} }
return 'Need at least one parameter: "username".'; return 'Need at least one parameter: "username".';
...@@ -104,42 +124,64 @@ var newLocalStorage = function ( spec, my ) { ...@@ -104,42 +124,64 @@ var newLocalStorage = function ( spec, my ) {
new_array); new_array);
}; };
priv.checkSecuredDocId = function (secured_docid,docid,method) {
if (!secured_docid) {
that.error({
status:403,statusText:'Method Not Allowed',
error:'method_not_allowed',
message:'Cannot '+method+' "'+docid+
'", file name is incorrect.',
reason:'Cannot '+method+' "'+docid+
'", file name is incorrect'
});
return false;
}
return true;
};
that.post = function (command) {
that.put(command);
};
/** /**
* Saves a document in the local storage. * Saves a document in the local storage.
* It will store the file in 'jio/local/USR/APP/FILE_NAME'. * It will store the file in 'jio/local/USR/APP/FILE_NAME'.
* @method saveDocument * @method put
*/ */
that.saveDocument = function (command) { that.put = function (command) {
// wait a little in order to simulate asynchronous saving // wait a little in order to simulate asynchronous saving
setTimeout (function () { setTimeout (function () {
var doc = null, path = var secured_docid = priv.secureDocId(command.getDocId()),
'jio/local/'+priv.username+'/'+ doc = null, path =
priv.applicationname+'/'+ 'jio/local/'+priv.secured_username+'/'+
command.getPath(); priv.secured_applicationname+'/'+
secured_docid;
if (!priv.checkSecuredDocId(
secured_docid,command.getDocId(),'put')) {return;}
// reading // reading
doc = LocalOrCookieStorage.getItem(path); doc = LocalOrCookieStorage.getItem(path);
if (!doc) { if (!doc) {
// create document // create document
doc = { doc = {
'name': command.getPath(), _id: command.getDocId(),
'content': command.getContent(), content: command.getDocContent(),
'creation_date': Date.now(), _creation_date: Date.now(),
'last_modified': Date.now() _last_modified: Date.now()
}; };
if (!priv.userExists(priv.username)) { if (!priv.userExists(priv.secured_username)) {
priv.addUser (priv.username); priv.addUser (priv.secured_username);
} }
priv.addFileName(command.getPath()); priv.addFileName(secured_docid);
} else { } else {
// overwriting // overwriting
doc.last_modified = Date.now(); doc.content = command.getDocContent();
doc.content = command.getContent(); doc._last_modified = Date.now();
} }
LocalOrCookieStorage.setItem(path, doc); LocalOrCookieStorage.setItem(path, doc);
that.success (); that.success ({ok:true,id:command.getDocId()});
}); });
}; // end saveDocument }; // end put
/** /**
* Loads a document from the local storage. * Loads a document from the local storage.
...@@ -147,22 +189,25 @@ var newLocalStorage = function ( spec, my ) { ...@@ -147,22 +189,25 @@ var newLocalStorage = function ( spec, my ) {
* You can add an 'options' object to the job, it can contain: * You can add an 'options' object to the job, it can contain:
* - metadata_only {boolean} default false, retrieve the file metadata * - metadata_only {boolean} default false, retrieve the file metadata
* only if true. * only if true.
* @method loadDocument * @method get
*/ */
that.loadDocument = function (command) { that.get = function (command) {
// document object is {'name':string,'content':string,
// 'creation_date':date,'last_modified':date}
setTimeout(function () { setTimeout(function () {
var doc = null; var secured_docid = priv.secureDocId(command.getDocId()),
doc = null;
if (!priv.checkSecuredDocId(
secured_docid,command.getDocId(),'get')) {return;}
doc = LocalOrCookieStorage.getItem( doc = LocalOrCookieStorage.getItem(
'jio/local/'+priv.username+'/'+ 'jio/local/'+priv.secured_username+'/'+
priv.applicationname+'/'+command.getPath()); priv.secured_applicationname+'/'+secured_docid);
if (!doc) { if (!doc) {
that.error ({status:404,statusText:'Not Found.', that.error ({status:404,statusText:'Not Found.',
message:'Document "'+ command.getPath() + error:'not_found',
'" not found in localStorage.'}); message:'Document "'+ command.getDocId() +
'" not found.',
reason:'missing'});
} else { } else {
if (command.getOption('metadata_only')) { if (command.getOption('metadata_only')) {
delete doc.content; delete doc.content;
...@@ -170,22 +215,20 @@ var newLocalStorage = function ( spec, my ) { ...@@ -170,22 +215,20 @@ var newLocalStorage = function ( spec, my ) {
that.success (doc); that.success (doc);
} }
}); });
}; // end loadDocument }; // end get
/** /**
* Gets a document list from the local storage. * Gets a document list from the local storage.
* It will retreive an array containing files meta data owned by * It will retreive an array containing files meta data owned by
* the user. * the user.
* @method getDocumentList * @method allDocs
*/ */
that.getDocumentList = function (command) { that.allDocs = function (command) {
// the list is [object,object] -> object = {'name':string,
// 'last_modified':date,'creation_date':date}
setTimeout(function () { setTimeout(function () {
var new_array = [], array = [], i, l, k = 'key', var new_array = [], array = [], i, l, k = 'key',
path = 'jio/local/'+priv.username+'/'+ priv.applicationname, path = 'jio/local/'+priv.secured_username+'/'+
file_object = {}; priv.secured_applicationname, file_object = {};
array = priv.getFileNameArray(); array = priv.getFileNameArray();
for (i = 0, l = array.length; i < l; i += 1) { for (i = 0, l = array.length; i < l; i += 1) {
...@@ -194,39 +237,43 @@ var newLocalStorage = function ( spec, my ) { ...@@ -194,39 +237,43 @@ var newLocalStorage = function ( spec, my ) {
if (file_object) { if (file_object) {
if (command.getOption('metadata_only')) { if (command.getOption('metadata_only')) {
new_array.push ({ new_array.push ({
name:file_object.name, id:file_object._id,key:file_object._id,value:{
creation_date:file_object.creation_date, _creation_date:file_object._creation_date,
last_modified:file_object.last_modified}); _last_modified:file_object._last_modified}});
} else { } else {
new_array.push ({ new_array.push ({
name:file_object.name, id:file_object._id,key:file_object._id,value:{
content:file_object.content, content:file_object.content,
creation_date:file_object.creation_date, _creation_date:file_object._creation_date,
last_modified:file_object.last_modified}); _last_modified:file_object._last_modified}});
} }
} }
} }
that.success (new_array); that.success ({total_rows:new_array.length,rows:new_array});
}); });
}; // end getDocumentList }; // end allDocs
/** /**
* Removes a document from the local storage. * Removes a document from the local storage.
* It will also remove the path from the local file array. * It will also remove the path from the local file array.
* @method removeDocument * @method remove
*/ */
that.removeDocument = function (command) { that.remove = function (command) {
setTimeout (function () { setTimeout (function () {
var path = 'jio/local/'+ var secured_docid = priv.secureDocId(command.getDocId()),
priv.username+'/'+ path = 'jio/local/'+
priv.applicationname+'/'+ priv.secured_username+'/'+
command.getPath(); priv.secured_applicationname+'/'+
secured_docid;
if (!priv.checkSecuredDocId(
secured_docid,command.getDocId(),'remove')) {return;}
// deleting // deleting
LocalOrCookieStorage.deleteItem(path); LocalOrCookieStorage.deleteItem(path);
priv.removeFileName(command.getPath()); priv.removeFileName(secured_docid);
that.success (); that.success ({ok:true,id:command.getDocId()});
}); });
}; }; // end remove
return that; return that;
}; };
Jio.addStorageType('local', newLocalStorage); Jio.addStorageType('local', newLocalStorage);
...@@ -234,8 +281,29 @@ Jio.addStorageType('local', newLocalStorage); ...@@ -234,8 +281,29 @@ Jio.addStorageType('local', newLocalStorage);
var newDAVStorage = function ( spec, my ) { var newDAVStorage = function ( spec, my ) {
var that = Jio.storage( spec, my, 'base' ), priv = {}; var that = Jio.storage( spec, my, 'base' ), priv = {};
priv.secureDocId = function (string) {
var split = string.split('/'), i;
if (split[0] === '') {
split = split.slice(1);
}
for (i = 0; i < split.length; i+= 1) {
if (split[i] === '') { return ''; }
}
return split.join('%2F');
};
priv.convertSlashes = function (string) {
return string.split('/').join('%2F');
};
priv.restoreSlashes = function (string) {
return string.split('%2F').join('/');
};
priv.username = spec.username || ''; priv.username = spec.username || '';
priv.secured_username = priv.convertSlashes(priv.username);
priv.applicationname = spec.applicationname || 'untitled'; priv.applicationname = spec.applicationname || 'untitled';
priv.secured_applicationname = priv.convertSlashes(priv.applicationname);
priv.url = spec.url || ''; priv.url = spec.url || '';
priv.password = spec.password || ''; // TODO : is it secured ? priv.password = spec.password || ''; // TODO : is it secured ?
...@@ -255,7 +323,7 @@ var newDAVStorage = function ( spec, my ) { ...@@ -255,7 +323,7 @@ var newDAVStorage = function ( spec, my ) {
* @return {string} '' -> ok, 'message' -> error * @return {string} '' -> ok, 'message' -> error
*/ */
that.validateState = function() { that.validateState = function() {
if (priv.username && priv.url) { if (priv.secured_username && priv.url) {
return ''; return '';
} }
return 'Need at least 2 parameters: "username" and "url".'; return 'Need at least 2 parameters: "username" and "url".';
...@@ -287,50 +355,55 @@ var newDAVStorage = function ( spec, my ) { ...@@ -287,50 +355,55 @@ var newDAVStorage = function ( spec, my ) {
return async; return async;
}; };
that.post = function (command) {
that.put(command);
};
/** /**
* Saves a document in the distant dav storage. * Saves a document in the distant dav storage.
* @method saveDocument * @method put
*/ */
that.saveDocument = function (command) { that.put = function (command) {
var secured_docid = priv.secureDocId(command.getDocId());
// TODO if path of /dav/user/applic does not exists, it won't work!
//// save on dav
$.ajax ( { $.ajax ( {
url: priv.url + '/dav/' + url: priv.url + '/' +
priv.username + '/' + priv.secured_username + '/' +
priv.applicationname + '/' + priv.secured_applicationname + '/' +
command.getPath(), secured_docid,
type: 'PUT', type: 'PUT',
data: command.getContent(), data: command.getDocContent(),
async: true, async: true,
dataType: 'text', // TODO is it necessary ? dataType: 'text', // TODO is it necessary ?
headers: {'Authorization':'Basic '+Base64.encode( headers: {'Authorization':'Basic '+Base64.encode(
priv.username+':'+priv.password)}, priv.username+':'+priv.password)},
// xhrFields: {withCredentials: 'true'}, // cross domain // xhrFields: {withCredentials: 'true'}, // cross domain
success: function () { success: function () {
that.success(); that.success({ok:true,id:command.getDocId()});
}, },
error: function (type) { error: function (type) {
type.message = 'Cannot save "' + command.getPath() + // TODO : make statusText to lower case and add '_'
'" into DAVStorage.'; type.error = type.statusText;
type.reason = 'Cannot save "' + command.getDocId() + '"';
type.message = type.reason + '.';
that.retry(type); that.retry(type);
} }
} ); } );
//// end saving on dav }; // end put
};
/** /**
* Loads a document from a distant dav storage. * Loads a document from a distant dav storage.
* @method loadDocument * @method get
*/ */
that.loadDocument = function (command) { that.get = function (command) {
var doc = {}, var secured_docid = priv.secureDocId(command.getDocId()),
getContent = function () { doc = {}, getContent = function () {
$.ajax ( { $.ajax ( {
url: priv.url + '/dav/' + url: priv.url + '/' +
priv.username + '/' + priv.secured_username + '/' +
priv.applicationname + '/' + priv.secured_applicationname + '/' +
command.getPath(), secured_docid,
type: "GET", type: "GET",
async: true, async: true,
dataType: 'text', // TODO is it necessary ? dataType: 'text', // TODO is it necessary ?
...@@ -342,28 +415,31 @@ var newDAVStorage = function ( spec, my ) { ...@@ -342,28 +415,31 @@ var newDAVStorage = function ( spec, my ) {
that.success(doc); that.success(doc);
}, },
error: function (type) { error: function (type) {
type.error = type.statusText; // TODO : to lower case
if (type.status === 404) { if (type.status === 404) {
type.message = 'Document "' + type.message = 'Document "' +
command.getPath() + command.getDocId() +
'" not found in localStorage.'; '" not found.';
type.reason = 'missing';
that.error(type); that.error(type);
} else { } else {
type.message = type.reason =
'Cannot load "' + command.getPath() + 'An error occured when trying to get "' +
'" from DAVStorage.'; command.getDocId() + '"';
type.message = type.reason + '.';
that.retry(type); that.retry(type);
} }
} }
} ); } );
}; };
doc.name = command.getPath(); // TODO : basename doc._id = command.getDocId();
// NOTE : if (command.getOption('content_only') { return getContent(); } // NOTE : if (command.getOption('content_only') { return getContent(); }
// Get properties // Get properties
$.ajax ( { $.ajax ( {
url: priv.url + '/dav/' + url: priv.url + '/' +
priv.username + '/' + priv.secured_username + '/' +
priv.applicationname + '/' + priv.secured_applicationname + '/' +
command.getPath(), secured_docid,
type: "PROPFIND", type: "PROPFIND",
async: true, async: true,
dataType: 'xml', dataType: 'xml',
...@@ -374,12 +450,14 @@ var newDAVStorage = function ( spec, my ) { ...@@ -374,12 +450,14 @@ var newDAVStorage = function ( spec, my ) {
$(xmlData).find( $(xmlData).find(
'lp1\\:getlastmodified, getlastmodified' 'lp1\\:getlastmodified, getlastmodified'
).each( function () { ).each( function () {
doc.last_modified = $(this).text(); doc._last_modified =
new Date($(this).text()).getTime();
}); });
$(xmlData).find( $(xmlData).find(
'lp1\\:creationdate, creationdate' 'lp1\\:creationdate, creationdate'
).each( function () { ).each( function () {
doc.creation_date = $(this).text(); doc._creation_date =
new Date($(this).text()).getTime();
}); });
if (!command.getOption('metadata_only')) { if (!command.getOption('metadata_only')) {
getContent(); getContent();
...@@ -388,11 +466,15 @@ var newDAVStorage = function ( spec, my ) { ...@@ -388,11 +466,15 @@ var newDAVStorage = function ( spec, my ) {
} }
}, },
error: function (type) { error: function (type) {
type.message = 'Cannot load "' + command.getPath() +
'" informations from DAVStorage.';
if (type.status === 404) { if (type.status === 404) {
type.message = 'Cannot find "' + command.getDocId() +
'" informations.';
type.reason = 'missing';
that.error(type); that.error(type);
} else { } else {
type.reason = 'Cannot get "' + command.getDocId() +
'" informations';
type.message = type.reason + '.';
that.retry(type); that.retry(type);
} }
} }
...@@ -401,18 +483,18 @@ var newDAVStorage = function ( spec, my ) { ...@@ -401,18 +483,18 @@ var newDAVStorage = function ( spec, my ) {
/** /**
* Gets a document list from a distant dav storage. * Gets a document list from a distant dav storage.
* @method getDocumentList * @method allDocs
*/ */
that.getDocumentList = function (command) { that.allDocs = function (command) {
var document_array = [], file = {}, path_array = [], var rows = [],
am = priv.newAsyncModule(), o = {}; am = priv.newAsyncModule(), o = {};
o.getContent = function (file) { o.getContent = function (file) {
$.ajax ( { $.ajax ( {
url: priv.url + '/dav/' + url: priv.url + '/' +
priv.username + '/' + priv.secured_username + '/' +
priv.applicationname + '/' + priv.secured_applicationname + '/' +
file.name, priv.secureDocId(file.id),
type: "GET", type: "GET",
async: true, async: true,
dataType: 'text', // TODO : is it necessary ? dataType: 'text', // TODO : is it necessary ?
...@@ -420,24 +502,26 @@ var newDAVStorage = function ( spec, my ) { ...@@ -420,24 +502,26 @@ var newDAVStorage = function ( spec, my ) {
Base64.encode(priv.username +':'+ Base64.encode(priv.username +':'+
priv.password)}, priv.password)},
success: function (content) { success: function (content) {
file.content = content; file.value.content = content;
// WARNING : files can be disordered because // WARNING : files can be disordered because
// of asynchronous action // of asynchronous action
document_array.push (file); rows.push (file);
am.call(o,'success'); am.call(o,'success');
}, },
error: function (type) { error: function (type) {
type.message = 'Cannot get a document '+ type.error = type.statusText; // TODO : to lower case
'content from DAVStorage.'; type.reason = 'Cannot get a document '+
'content from DAVStorage';
type.message = type.message + '.';
am.call(o,'error',[type]); am.call(o,'error',[type]);
} }
}); });
}; };
o.getDocumentList = function () { o.getDocumentList = function () {
$.ajax ( { $.ajax ( {
url: priv.url + '/dav/' + url: priv.url + '/' +
priv.username + '/' + priv.secured_username + '/' +
priv.applicationname + '/', priv.secured_applicationname + '/',
async: true, async: true,
type: 'PROPFIND', type: 'PROPFIND',
dataType: 'xml', dataType: 'xml',
...@@ -455,41 +539,46 @@ var newDAVStorage = function ( spec, my ) { ...@@ -455,41 +539,46 @@ var newDAVStorage = function ( spec, my ) {
} }
response.each( function(i,data){ response.each( function(i,data){
if(i>0) { // exclude parent folder if(i>0) { // exclude parent folder
file = {}; var file = {value:{}};
$(data).find('D\\:href, href').each(function(){ $(data).find('D\\:href, href').each(function(){
path_array = $(this).text().split('/'); var split = $(this).text().split('/');
file.name = file.id = split[split.length-1];
(path_array[path_array.length-1] ? file.id = priv.restoreSlashes(file.id);
path_array[path_array.length-1] : file.key = file.id;
path_array[path_array.length-2]+'/');
}); });
if (file.name === '.htaccess' || if (file.id === '.htaccess' ||
file.name === '.htpasswd') { return; } file.id === '.htpasswd') { return; }
$(data).find( $(data).find(
'lp1\\:getlastmodified, getlastmodified' 'lp1\\:getlastmodified, getlastmodified'
).each(function () { ).each(function () {
file.last_modified = $(this).text(); file.value._last_modified =
new Date($(this).text()).getTime();
}); });
$(data).find( $(data).find(
'lp1\\:creationdate, creationdate' 'lp1\\:creationdate, creationdate'
).each(function () { ).each(function () {
file.creation_date = $(this).text(); file.value._creation_date =
new Date($(this).text()).getTime();
}); });
if (!command.getOption ('metadata_only')) { if (!command.getOption ('metadata_only')) {
am.call(o,'getContent',[file]); am.call(o,'getContent',[file]);
} else { } else {
document_array.push (file); rows.push (file);
am.call(o,'success'); am.call(o,'success');
} }
} }
}); });
}, },
error: function (type) { error: function (type) {
type.message =
'Cannot get a document list from DAVStorage.';
if (type.status === 404) { if (type.status === 404) {
type.error = 'not_found';
type.reason = 'missing';
am.call(o,'error',[type]); am.call(o,'error',[type]);
} else { } else {
type.error = type.statusText; // TODO : to lower case
type.reason =
'Cannot get a document list from DAVStorage';
type.message = type.reason + '.';
am.call(o,'retry',[type]); am.call(o,'retry',[type]);
} }
} }
...@@ -511,36 +600,43 @@ var newDAVStorage = function ( spec, my ) { ...@@ -511,36 +600,43 @@ var newDAVStorage = function ( spec, my ) {
am.neverCall(o,'retry'); am.neverCall(o,'retry');
am.neverCall(o,'success'); am.neverCall(o,'success');
am.neverCall(o,'error'); am.neverCall(o,'error');
that.success(document_array); that.success({total_rows:rows.length,
rows:rows});
}; };
am.call (o,'getDocumentList'); am.call (o,'getDocumentList');
}; }; // end allDocs
/** /**
* Removes a document from a distant dav storage. * Removes a document from a distant dav storage.
* @method removeDocument * @method remove
*/ */
that.removeDocument = function (command) { that.remove = function (command) {
var secured_docid = priv.secureDocId(command.getDocId());
$.ajax ( { $.ajax ( {
url: priv.url + '/dav/' + url: priv.url + '/' +
priv.username + '/' + priv.secured_username + '/' +
priv.applicationname + '/' + priv.secured_applicationname + '/' +
command.getPath(), secured_docid,
type: "DELETE", type: "DELETE",
async: true, async: true,
headers: {'Authorization':'Basic '+Base64.encode( headers: {'Authorization':'Basic '+Base64.encode(
priv.username + ':' + priv.password )}, priv.username + ':' + priv.password )},
// xhrFields: {withCredentials: 'true'}, // cross domain // xhrFields: {withCredentials: 'true'}, // cross domain
success: function () { success: function (data,state,type) {
that.success(); that.success({ok:true,id:command.getDocId()});
}, },
error: function (type) { error: function (type,state,statusText) {
if (type.status === 404) { if (type.status === 404) {
that.success(); //that.success({ok:true,id:command.getDocId()});
type.error = 'not_found';
type.reason = 'missing';
type.message = 'Cannot remove missing file.';
that.error(type);
} else { } else {
type.message = 'Cannot remove "' + that.getFileName() + type.reason = 'Cannot remove "' + that.getDocId() + '"';
'" from DAVStorage.'; type.message = type.reason + '.';
that.retry(type); that.retry(type);
} }
} }
...@@ -573,84 +669,82 @@ var newReplicateStorage = function ( spec, my ) { ...@@ -573,84 +669,82 @@ var newReplicateStorage = function ( spec, my ) {
return ''; return '';
}; };
priv.isTheLast = function () { priv.isTheLast = function (error_array) {
return (priv.return_value_array.length === priv.nb_storage); return (error_array.length === priv.nb_storage);
}; };
priv.doJob = function (command,errormessage) { priv.doJob = function (command,errormessage,nodocid) {
var done = false, error_array = [], i, var done = false, error_array = [], i,
onErrorDo = function (result) { error = function (err) {
priv.return_value_array.push(result);
if (!done) { if (!done) {
error_array.push(result); error_array.push(err);
if (priv.isTheLast()) { if (priv.isTheLast(error_array)) {
that.error ( that.error ({
{status:207, status:207,
statusText:'Multi-Status', statusText:'Multi-Status',
message:errormessage, error:'multi_status',
array:error_array}); message:'All '+errormessage+
(!nodocid?' "'+command.getDocId()+'"':' ') +
' requests have failed.',
reason:'requests fail',
array:error_array
});
} }
} }
}, },
onSuccessDo = function (result) { success = function (val) {
priv.return_value_array.push(result);
if (!done) { if (!done) {
done = true; done = true;
that.success (result); that.success (val);
} }
}; };
for (i = 0; i < priv.nb_storage; i+= 1) { for (i = 0; i < priv.nb_storage; i+= 1) {
var newcommand = command.clone(); var cloned_option = command.cloneOption();
var newstorage = that.newStorage(priv.storagelist[i]); that.addJob (command.getLabel(),priv.storagelist[i],
newcommand.onErrorDo (onErrorDo); command.cloneDoc(),cloned_option,success,error);
newcommand.onSuccessDo (onSuccessDo);
that.addJob (newstorage, newcommand);
} }
}; };
that.post = function (command) {
priv.doJob (command,'post');
that.end();
};
/** /**
* Save a document in several storages. * Save a document in several storages.
* @method saveDocument * @method put
*/ */
that.saveDocument = function (command) { that.put = function (command) {
priv.doJob ( priv.doJob (command,'put');
command,
'All save "'+ command.getPath() +'" requests have failed.');
that.end(); that.end();
}; };
/** /**
* Load a document from several storages, and send the first retreived * Load a document from several storages, and send the first retreived
* document. * document.
* @method loadDocument * @method get
*/ */
that.loadDocument = function (command) { that.get = function (command) {
priv.doJob ( priv.doJob (command,'get');
command,
'All load "'+ command.getPath() +'" requests have failed.');
that.end(); that.end();
}; };
/** /**
* Get a document list from several storages, and returns the first * Get a document list from several storages, and returns the first
* retreived document list. * retreived document list.
* @method getDocumentList * @method allDocs
*/ */
that.getDocumentList = function (command) { that.allDocs = function (command) {
priv.doJob ( priv.doJob (command,'allDocs',true);
command,
'All get document list requests have failed.');
that.end(); that.end();
}; };
/** /**
* Remove a document from several storages. * Remove a document from several storages.
* @method removeDocument * @method remove
*/ */
that.removeDocument = function (command) { that.remove = function (command) {
priv.doJob ( priv.doJob (command,'remove');
command,
'All remove "' + command.getPath() + '" requests have failed.');
that.end(); that.end();
}; };
...@@ -665,8 +759,8 @@ var newIndexStorage = function ( spec, my ) { ...@@ -665,8 +759,8 @@ var newIndexStorage = function ( spec, my ) {
priv.secondstorage_spec = spec.storage || {type:'base'}; priv.secondstorage_spec = spec.storage || {type:'base'};
priv.secondstorage_string = JSON.stringify (priv.secondstorage_spec); priv.secondstorage_string = JSON.stringify (priv.secondstorage_spec);
var storage_array_name = 'jio/indexed_storage_array'; var storage_object_name = 'jio/indexed_storage_object';
var storage_file_array_name = 'jio/indexed_file_array/'+ var storage_file_object_name = 'jio/indexed_file_object/'+
priv.secondstorage_string; priv.secondstorage_string;
var super_serialized = that.serialized; var super_serialized = that.serialized;
...@@ -684,273 +778,184 @@ var newIndexStorage = function ( spec, my ) { ...@@ -684,273 +778,184 @@ var newIndexStorage = function ( spec, my ) {
return ''; return '';
}; };
/** priv.secureDocId = function (string) {
* Check if the indexed storage array exists. var split = string.split('/'), i;
* @method isStorageArrayIndexed if (split[0] === '') {
* @return {boolean} true if exists, else false split = split.slice(1);
*/ }
priv.isStorageArrayIndexed = function () { for (i = 0; i < split.length; i+= 1) {
return (LocalOrCookieStorage.getItem( if (split[i] === '') { return ''; }
storage_array_name) ? true : false); }
}; return split.join('%2F');
/**
* Returns a list of indexed storages.
* @method getIndexedStorageArray
* @return {array} The list of indexed storages.
*/
priv.getIndexedStorageArray = function () {
return LocalOrCookieStorage.getItem(
storage_array_name) || [];
}; };
/** priv.indexStorage = function () {
* Adds a storage to the indexed storage list. var obj = LocalOrCookieStorage.getItem (storage_object_name) || {};
* @method indexStorage obj[priv.secondstorage_spec] = new Date().getTime();
* @param {object/json} storage The new indexed storage. LocalOrCookieStorage.setItem (storage_object_name,obj);
*/
priv.indexStorage = function (storage) {
var indexed_storage_array = priv.getIndexedStorageArray();
indexed_storage_array.push(typeof storage === 'string'? storage:
JSON.stringify (storage));
LocalOrCookieStorage.setItem(storage_array_name,
indexed_storage_array);
}; };
/** priv.formatToFileObject = function (row) {
* Checks if a storage exists in the indexed storage list. var k, obj = {_id:row.id};
* @method isAnIndexedStorage for (k in row.value) {
* @param {object/json} storage The storage to find. obj[k] = row.value[k];
* @return {boolean} true if found, else false
*/
priv.isAnIndexedStorage = function (storage) {
var json_storage = (typeof storage === 'string'?storage:
JSON.stringify(storage)),
i,l,array = priv.getIndexedStorageArray();
for (i = 0, l = array.length; i < l; i+= 1) {
if (JSON.stringify(array[i]) === json_storage) {
return true;
}
} }
return false; return obj;
}; };
/** priv.allDocs = function (files_object) {
* Checks if the file array exists. var k, obj = {rows:[]}, i = 0;
* @method fileArrayExists for (k in files_object) {
* @return {boolean} true if exists, else false obj.rows[i] = {};
*/ obj.rows[i].value = files_object[k];
priv.fileArrayExists = function () { obj.rows[i].id = obj.rows[i].key = obj.rows[i].value._id;
return (LocalOrCookieStorage.getItem ( delete obj.rows[i].value._id;
storage_file_array_name) ? true : false); i ++;
}; }
obj.total_rows = obj.rows.length;
/** return obj;
* Returns the file from the indexed storage but not there content.
* @method getFileArray
* @return {array} All the existing file.
*/
priv.getFileArray = function () {
return LocalOrCookieStorage.getItem(
storage_file_array_name) || [];
}; };
/**
* Sets the file array list.
* @method setFileArray
* @param {array} file_array The array containing files.
*/
priv.setFileArray = function (file_array) { priv.setFileArray = function (file_array) {
return LocalOrCookieStorage.setItem( var i, obj = {};
storage_file_array_name, for (i = 0; i < file_array.length; i+= 1) {
file_array); obj[file_array[i].id] = priv.formatToFileObject(file_array[i]);
}
LocalOrCookieStorage.setItem (storage_file_object_name,obj);
}; };
/** priv.getFileObject = function (docid) {
* Checks if the file already exists in the array. var obj = LocalOrCookieStorage.getItem (storage_file_object_name) || {};
* @method isFileIndexed return obj[docid];
* @param {string} file_name The file we want to find.
* @return {boolean} true if found, else false
*/
priv.isFileIndexed = function (file_name) {
var i, l, array = priv.getFileArray();
for (i = 0, l = array.length; i < l; i+= 1) {
if (array[i].name === file_name){
return true;
}
}
return false;
}; };
/** priv.addFile = function (file_obj) {
* Adds a file to the local file array. var obj = LocalOrCookieStorage.getItem (storage_file_object_name) || {};
* @method addFile obj[file_obj._id] = file_obj;
* @param {object} file The new file. LocalOrCookieStorage.setItem (storage_file_object_name,obj);
*/
priv.addFile = function (file) {
var file_array = priv.getFileArray();
file_array.push(file);
LocalOrCookieStorage.setItem(storage_file_array_name,
file_array);
}; };
/** priv.removeFile = function (docid) {
* Removes a file from the local file array. var obj = LocalOrCookieStorage.getItem (storage_file_object_name) || {};
* @method removeFile delete obj[docid];
* @param {string} file_name The file to remove. LocalOrCookieStorage.setItem (storage_file_object_name,obj);
*/
priv.removeFile = function (file_name) {
var i, l, array = priv.getFileArray(), new_array = [];
for (i = 0, l = array.length; i < l; i+= 1) {
if (array[i].name !== file_name) {
new_array.push(array[i]);
}
}
LocalOrCookieStorage.setItem(storage_file_array_name,
new_array);
}; };
/** /**
* Updates the storage. * updates the storage.
* It will retreive all files from a storage. It is an asynchronous task * It will retreive all files from a storage. It is an asynchronous task
* so the update can be on going even if IndexedStorage has already * so the update can be on going even if IndexedStorage has already
* returned the result. * returned the result.
* @method update * @method update
*/ */
priv.update = function () { priv.update = function () {
// retreive list before, and then retreive all files var success = function (val) {
var getlist_onSuccess = function (result) { priv.setFileArray(val.rows);
if (!priv.isAnIndexedStorage(priv.secondstorage_string)) {
priv.indexStorage(priv.secondstorage_string);
}
priv.setFileArray(result);
}; };
that.addJob ( that.newStorage (priv.secondstorage_spec), that.addJob ('allDocs', priv.secondstorage_spec,null,
that.newCommand ('getDocumentList', {max_retry:3},success,function(){});
{path:'.', };
option:{success:getlist_onSuccess,
max_retry: 3}}) ); that.post = function (command) {
that.put(command);
}; };
/** /**
* Saves a document. * Saves a document.
* @method saveDocument * @method put
*/ */
that.saveDocument = function (command) { that.put = function (command) {
var newcommand = command.clone(); var cloned_doc = command.cloneDoc(),
newcommand.onSuccessDo (function (result) { cloned_option = command.cloneOption(),
if (!priv.isFileIndexed(command.getPath())) { success = function (val) {
priv.addFile({name:command.getPath(),
last_modified:0,creation_date:0});
}
priv.update(); priv.update();
that.success(); that.success(val);
}); },
newcommand.onErrorDo (function (result) { error = function (err) {
that.error(result); that.error(err);
}); };
that.addJob ( that.newStorage(priv.secondstorage_spec), priv.indexStorage();
newcommand ); that.addJob ('put',priv.secondstorage_spec,cloned_doc,
}; // end saveDocument cloned_option,success,error);
}; // end put
/** /**
* Loads a document. * Loads a document.
* @method loadDocument * @method get
*/ */
that.loadDocument = function (command) { that.get = function (command) {
var file_array, i, l, new_job, var file_array,
loadOnSuccess = function (result) { success = function (val) {
// if (file_array[i].last_modified !== that.success(val);
// result.return_value.last_modified ||
// file_array[i].creation_date !==
// result.return_value.creation_date) {
// // the file in the index storage is different than
// // the one in the second storage. priv.update will
// // take care of refresh the indexed storage
// }
that.success(result);
}, },
loadOnError = function (result) { error = function (err) {
that.error(result); that.error(err);
}, },
secondLoadDocument = function () { get = function () {
var newcommand = command.clone(); var cloned_option = command.cloneOption();
newcommand.onErrorDo (loadOnError); that.addJob ('get',priv.secondstorage_spec,command.cloneDoc(),
newcommand.onSuccessDo (loadOnSuccess); cloned_option,success,error);
that.addJob ( that.newStorage(priv.secondstorage_spec), that.end();
newcommand );
}; };
priv.indexStorage();
priv.update(); priv.update();
if (command.getOption('metadata_only')) { if (command.getOption('metadata_only')) {
setTimeout(function () { setTimeout(function () {
if (priv.fileArrayExists()) { var file_obj = priv.getFileObject(command.getDocId());
file_array = priv.getFileArray(); if (file_obj &&
for (i = 0, l = file_array.length; i < l; i+= 1) { (file_obj._last_modified ||
if (file_array[i].name === command.getPath()) { file_obj._creation_date)) {
return that.success(file_array[i]); that.success (file_obj);
}
}
} else { } else {
secondLoadDocument(); get();
} }
},100); });
} else { } else {
secondLoadDocument(); get();
} }
}; // end loadDocument }; // end get
/** /**
* Gets a document list. * Gets a document list.
* @method getDocumentList * @method allDocs
*/ */
that.getDocumentList = function (command) { that.allDocs = function (command) {
var id, newcommand, timeout = false; var obj = LocalOrCookieStorage.getItem (storage_file_object_name);
priv.update(); if (obj) {
if (command.getOption('metadata_only')) { priv.update();
id = setInterval(function () { setTimeout(function (){
if (timeout) { that.success (priv.allDocs(obj));
that.error({status:0,statusText:'Timeout',
message:'The request has timed out.'});
clearInterval(id);
}
if (priv.fileArrayExists()) {
that.success(priv.getFileArray());
clearInterval(id);
}
},100);
setTimeout (function () {
timeout = true;
}, 10000); // 10 sec
} else {
newcommand = command.clone();
newcommand.onSuccessDo (function (result) {
that.success(result);
});
newcommand.onErrorDo (function (result) {
that.error(result);
}); });
that.addJob ( that.newStorage (priv.secondstorage_spec), } else {
newcommand ); var success = function (val) {
priv.setFileArray(val.rows);
that.success(val);
},
error = function (err) {
that.error(err);
};
that.addJob ('allDocs', priv.secondstorage_spec,null,
command.cloneOption(),success,error);
} }
}; // end getDocumentList }; // end allDocs
/** /**
* Removes a document. * Removes a document.
* @method removeDocument * @method remove
*/ */
that.removeDocument = function (command) { that.remove = function (command) {
var newcommand = command.clone(); var success = function (val) {
newcommand.onSuccessDo (function (result) { priv.removeFile(command.getDocId());
priv.removeFile(command.getPath());
priv.update(); priv.update();
that.success(); that.success(val);
}); },
newcommand.onErrorDo (function (result) { error = function (err) {
that.error(result); that.error(err);
}); };
that.addJob( that.newStorage(priv.secondstorage_spec), that.addJob ('remove',priv.secondstorage_spec,command.cloneDoc(),
newcommand ); command.cloneOption(),success,error);
}; }; // end remove
return that; return that;
}; };
Jio.addStorageType ('indexed', newIndexStorage); Jio.addStorageType ('indexed', newIndexStorage);
...@@ -969,7 +974,7 @@ var newCryptedStorage = function ( spec, my ) { ...@@ -969,7 +974,7 @@ var newCryptedStorage = function ( spec, my ) {
that.serialized = function () { that.serialized = function () {
var o = super_serialized(); var o = super_serialized();
o.username = priv.username; o.username = priv.username;
o.password = priv.password; o.password = priv.password; // TODO : unsecured !!!
o.storage = priv.secondstorage_string; o.storage = priv.secondstorage_string;
return o; return o;
}; };
...@@ -1017,8 +1022,8 @@ var newCryptedStorage = function ( spec, my ) { ...@@ -1017,8 +1022,8 @@ var newCryptedStorage = function ( spec, my ) {
priv.password, priv.password,
param); param);
} catch (e) { } catch (e) {
callback({status:0,statusText:'Decrypt Fail', callback({status:403,statusText:'Forbidden',error:'forbidden',
message:'Unable to decrypt.'}); message:'Unable to decrypt.',reason:'unable to decrypt'});
return; return;
} }
callback(undefined,tmp); callback(undefined,tmp);
...@@ -1052,181 +1057,167 @@ var newCryptedStorage = function ( spec, my ) { ...@@ -1052,181 +1057,167 @@ var newCryptedStorage = function ( spec, my ) {
return async; return async;
}; };
that.post = function (command) {
that.put (command);
};
/** /**
* Saves a document. * Saves a document.
* @method saveDocument * @method put
*/ */
that.saveDocument = function (command) { that.put = function (command) {
var new_file_name, new_file_content, am = priv.newAsyncModule(), o = {}; var new_file_name, new_file_content, am = priv.newAsyncModule(), o = {};
o.encryptFilePath = function () { o.encryptFilePath = function () {
priv.encrypt(command.getPath(),function(res) { priv.encrypt(command.getDocId(),function(res) {
new_file_name = res; new_file_name = res;
am.call(o,'save'); am.call(o,'save');
}); });
}; };
o.encryptFileContent = function () { o.encryptFileContent = function () {
priv.encrypt(command.getContent(),function(res) { priv.encrypt(command.getDocContent(),function(res) {
new_file_content = res; new_file_content = res;
am.call(o,'save'); am.call(o,'save');
}); });
}; };
o.save = function () { o.save = function () {
var settings = command.cloneOption(), newcommand; var success = function (val) {
settings.success = function () { that.success(); }; val.id = command.getDocId();
settings.error = function (r) { that.error(r); }; that.success (val);
newcommand = that.newCommand( },
'saveDocument', error = function (err) {
{path:new_file_name,content:new_file_content,option:settings}); that.error (err);
that.addJob ( },
that.newStorage( priv.secondstorage_spec ), cloned_doc = command.cloneDoc();
newcommand ); cloned_doc._id = new_file_name;
cloned_doc.content = new_file_content;
that.addJob ('put',priv.secondstorage_spec,cloned_doc,
command.cloneOption(),success,error);
}; };
am.wait(o,'save',1); am.wait(o,'save',1);
am.call(o,'encryptFilePath'); am.call(o,'encryptFilePath');
am.call(o,'encryptFileContent'); am.call(o,'encryptFileContent');
}; // end saveDocument }; // end put
/** /**
* Loads a document. * Loads a document.
* @method loadDocument * @method get
*/ */
that.loadDocument = function (command) { that.get = function (command) {
var new_file_name, option, am = priv.newAsyncModule(), o = {}; var new_file_name, option, am = priv.newAsyncModule(), o = {};
o.encryptFilePath = function () { o.encryptFilePath = function () {
priv.encrypt(command.getPath(),function(res) { priv.encrypt(command.getDocId(),function(res) {
new_file_name = res; new_file_name = res;
am.call(o,'loadDocument'); am.call(o,'get');
}); });
}; };
o.loadDocument = function () { o.get = function () {
var settings = command.cloneOption(), newcommand; that.addJob('get',priv.secondstorage_spec,new_file_name,
settings.error = o.loadOnError; command.cloneOption(),o.success,o.error);
settings.success = o.loadOnSuccess; };
newcommand = that.newCommand ( o.success = function (val) {
'loadDocument', val._id = command.getDocId();
{path:new_file_name,option:settings});
that.addJob (
that.newStorage ( priv.secondstorage_spec ), newcommand );
};
o.loadOnSuccess = function (result) {
result.name = command.getPath();
if (command.getOption('metadata_only')) { if (command.getOption('metadata_only')) {
that.success(result); that.success (val);
} else { } else {
priv.decrypt (result.content, function(err,res){ priv.decrypt (val.content, function(err,res){
if (err) { if (err) {
that.error(err); that.error(err);
} else { } else {
result.content = res; val.content = res;
// content only: the second storage should that.success (val);
// manage content_only option, so it is not
// necessary to manage it.
that.success(result);
} }
}); });
} }
}; };
o.loadOnError = function (error) { o.error = function (error) {
// NOTE : we can re create an error object instead of
// keep the old ex:status=404,message="document 1y59gyl8g
// not found in localStorage"...
that.error(error); that.error(error);
}; };
am.call(o,'encryptFilePath'); am.call(o,'encryptFilePath');
}; // end loadDocument }; // end get
/** /**
* Gets a document list. * Gets a document list.
* @method getDocumentList * @method allDocs
*/ */
that.getDocumentList = function (command) { that.allDocs = function (command) {
var result_array = [], am = priv.newAsyncModule(), o = {}; var result_array = [], am = priv.newAsyncModule(), o = {};
o.getDocumentList = function () { o.allDocs = function () {
var settings = command.cloneOption(); that.addJob ('allDocs', priv.secondstorage_spec, null,
settings.success = o.getListOnSuccess; command.cloneOption(), o.onSuccess, o.error);
settings.error = o.getListOnError; };
that.addJob ( o.onSuccess = function (val) {
that.newStorage ( priv.secondstorage_spec ), if (val.total_rows === 0) {
that.newCommand ( 'getDocumentList', {path:command.getPath(), return am.call(o,'success');
option:settings}) ); }
}; result_array = val.rows;
o.getListOnSuccess = function (result) {
result_array = result;
var i, decrypt = function (c) { var i, decrypt = function (c) {
priv.decrypt (result_array[c].name,function (err,res) { priv.decrypt (result_array[c].id,function (err,res) {
if (err) { if (err) {
am.call(o,'error',[err]); am.call(o,'error',[err]);
} else { } else {
am.call(o,'pushResult',[res,c,'name']); result_array[c].id = res;
result_array[c].key = res;
am.call(o,'success');
} }
}); });
if (!command.getOption('metadata_only')) { if (!command.getOption('metadata_only')) {
priv.decrypt (result_array[c].content,function (err,res) { priv.decrypt (
if (err) { result_array[c].value.content,
am.call(o,'error',[err]); function (err,res) {
} else { if (err) {
am.call(o,'pushResult',[res,c,'content']); am.call(o,'error',[err]);
} } else {
}); result_array[c].value.content = res;
am.call(o,'success');
}
});
} }
}; };
if (command.getOption('metadata_only')) { if (command.getOption('metadata_only')) {
am.wait(o,'success',result.length-1); am.wait(o,'success',val.total_rows*1-1);
} else { } else {
am.wait(o,'success',result.length*2-1); am.wait(o,'success',val.total_rows*2-1);
} }
for (i = 0; i < result_array.length; i+= 1) { for (i = 0; i < result_array.length; i+= 1) {
decrypt(i); decrypt(i);
} }
}; };
o.getListOnError = function (error) {
am.call(o,'error',[error]);
};
o.pushResult = function (result,index,key) {
result_array[index][key] = result;
am.call(o,'success');
};
o.error = function (error) { o.error = function (error) {
am.end(); am.end();
that.error (error); that.error (error);
}; };
o.success = function () { o.success = function () {
am.end(); am.end();
that.success (result_array); that.success ({total_rows:result_array.length,rows:result_array});
}; };
am.call(o,'getDocumentList'); am.call(o,'allDocs');
}; // end getDocumentList }; // end allDocs
/** /**
* Removes a document. * Removes a document.
* @method removeDocument * @method remove
*/ */
that.removeDocument = function (command) { that.remove = function (command) {
var new_file_name, o = {}; var new_file_name, o = {};
o.encryptFilePath = function () { o.encryptDocId = function () {
priv.encrypt(command.getPath(),function(res) { priv.encrypt(command.getDocId(),function(res) {
new_file_name = res; new_file_name = res;
o.removeDocument(); o.removeDocument();
}); });
}; };
o.removeDocument = function () { o.removeDocument = function () {
var cloned_option = command.cloneOption(); var cloned_doc = command.cloneDoc();
cloned_option.error = o.removeOnError; cloned_doc._id = new_file_name;
cloned_option.success = o.removeOnSuccess; that.addJob ('remove', priv.secondstorage_spec, cloned_doc,
that.addJob(that.newStorage(priv.secondstorage_spec), command.cloneOption(), o.success, that.error);
that.newCommand(
'removeDocument',
{path:new_file_name,
option:cloned_option}));
};
o.removeOnSuccess = function (result) {
that.success();
};
o.removeOnError = function (error) {
that.error (error);
}; };
o.encryptFilePath(); o.success = function (val) {
}; val.id = command.getDocId();
that.success (val);
};
o.encryptDocId();
}; // end remove
return that; return that;
}; };
Jio.addStorageType('crypt', newCryptedStorage); Jio.addStorageType('crypt', newCryptedStorage);
...@@ -1263,94 +1254,83 @@ var newConflictManagerStorage = function ( spec, my ) { ...@@ -1263,94 +1254,83 @@ var newConflictManagerStorage = function ( spec, my ) {
var cloned_option = command.cloneOption (); var cloned_option = command.cloneOption ();
cloned_option.metadata_only = false; cloned_option.metadata_only = false;
cloned_option.max_retry = command.getOption('max_retry') || 3; cloned_option.max_retry = command.getOption('max_retry') || 3;
cloned_option.error = error; that.addJob ('get',priv.secondstorage_spec,path,cloned_option,
cloned_option.success = success; success, error);
var newcommand = that.newCommand(
'loadDocument',{path:path,
option:cloned_option});
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
}; };
priv.saveMetadataToDistant = function (command,path,content,success,error) { priv.saveMetadataToDistant = function (command,path,content,success,error) {
var cloned_option = command.cloneOption (); // max_retry:0 // inf
cloned_option.error = error; that.addJob ('put',priv.secondstorage_spec,
cloned_option.success = success; {_id:path,content:JSON.stringify (content)},
var newcommand = that.newCommand( command.cloneOption(),success,error);
'saveDocument',{path:path,
content:JSON.stringify (content),
option:cloned_option});
// newcommand.setMaxRetry (0); // inf
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
}; };
priv.saveNewRevision = function (command,path,content,success,error) { priv.saveNewRevision = function (command,path,content,success,error) {
var cloned_option = command.cloneOption (); that.addJob ('put',priv.secondstorage_spec,{_id:path,content:content},
cloned_option.error = error; command.cloneOption(),success,error);
cloned_option.success = success;
var newcommand = that.newCommand(
'saveDocument',{path:path,
content:content,
option:cloned_option});
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
}; };
priv.loadRevision = function (command,path,success,error) { priv.loadRevision = function (command,path,success,error) {
var cloned_option = command.cloneOption (); that.addJob('get',priv.secondstorage_spec,path,command.cloneOption(),
cloned_option.error = error; success, error);
cloned_option.success = success;
var newcommand = that.newCommand (
'loadDocument',{path:path,
option:cloned_option});
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
}; };
priv.deleteAFile = function (command,path,success,error) { priv.deleteAFile = function (command,path,success,error) {
var cloned_option = command.cloneOption(); var cloned_option = command.cloneOption();
cloned_option.max_retry = 0; // inf cloned_option.max_retry = 0; // inf
cloned_option.error = error; that.addJob ('remove',priv.secondstorage_spec,{_id:path},
cloned_option.success = success; command.cloneOption(), success, error);
var newcommand = that.newCommand(
'removeDocument',{path:path,
option:cloned_option});
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
}; };
priv.chooseARevision = function (metadata) { priv.chooseARevision = function (metadata) {
var tmp_last_modified = 0, ret_rev = ''; var tmp_last_modified = 0, ret_rev = '', rev;
for (var rev in metadata) { for (rev in metadata) {
if (tmp_last_modified < if (tmp_last_modified <
metadata[rev].last_modified) { metadata[rev]._last_modified) {
tmp_last_modified = tmp_last_modified =
metadata[rev].last_modified; metadata[rev]._last_modified;
ret_rev = rev; ret_rev = rev;
} }
} }
return ret_rev; return ret_rev;
}; };
priv.solveConflict = function (path,content,option) { priv._revs = function (metadata,revision) {
if (metadata[revision]) {
return {start:metadata[revision]._revisions.length,
ids:metadata[revision]._revisions};
} else {
return null;
}
};
priv._revs_info = function (metadata) {
var k, l = [];
for (k in metadata) {
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(), var o = {}, am = priv.newAsyncModule(),
command = option.command, command = param.command,
metadata_file_path = path + '.metadata', metadata_file_path = param.docid + '.metadata',
current_revision = '', current_revision = '',
current_revision_file_path = '', current_revision_file_path = '',
metadata_file_content = null, metadata_file_content = null,
on_conflict = false, conflict_object = {}, on_conflict = false, conflict_object = {total_rows:0,rows:[]},
on_remove = option.deleted, on_remove = param._deleted,
previous_revision = option.previous_revision, previous_revision = param.previous_revision,
previous_revision_object = option.revision_remove_object || {}, previous_revision_content_object = null,
previous_revision_content_object = previous_revision_object[
previous_revision] || {},
now = new Date(), now = new Date(),
failerror; failerror;
o.getDistantMetadata = function (){ o.getDistantMetadata = function (){
priv.getDistantMetadata ( priv.getDistantMetadata (
command, metadata_file_path, command, metadata_file_path,
function (result) { function (result) {
...@@ -1359,11 +1339,13 @@ var newConflictManagerStorage = function ( spec, my ) { ...@@ -1359,11 +1339,13 @@ var newConflictManagerStorage = function ( spec, my ) {
metadata_file_content = JSON.parse (result.content); metadata_file_content = JSON.parse (result.content);
// set current revision // set current revision
current_revision = (previous_revision_number + 1) + '-' + current_revision = (previous_revision_number + 1) + '-' +
hex_sha256 ('' + content + hex_sha256 ('' + doc.content +
previous_revision + previous_revision +
JSON.stringify (metadata_file_content)); JSON.stringify (metadata_file_content));
current_revision_file_path = path + '.' + current_revision_file_path = param.docid + '.' +
current_revision; current_revision;
previous_revision_content_object = metadata_file_content[
previous_revision] || {};
if (!on_remove) { if (!on_remove) {
am.wait(o,'saveMetadataOnDistant',1); am.wait(o,'saveMetadataOnDistant',1);
am.call(o,'saveNewRevision'); am.call(o,'saveNewRevision');
...@@ -1376,7 +1358,7 @@ var newConflictManagerStorage = function ( spec, my ) { ...@@ -1376,7 +1358,7 @@ var newConflictManagerStorage = function ( spec, my ) {
}; };
o.saveNewRevision = function (){ o.saveNewRevision = function (){
priv.saveNewRevision ( priv.saveNewRevision (
command, current_revision_file_path, content, command, current_revision_file_path, doc.content,
function (result) { function (result) {
am.call(o,'saveMetadataOnDistant'); am.call(o,'saveMetadataOnDistant');
}, function (error) { }, function (error) {
...@@ -1385,18 +1367,20 @@ var newConflictManagerStorage = function ( spec, my ) { ...@@ -1385,18 +1367,20 @@ var newConflictManagerStorage = function ( spec, my ) {
); );
}; };
o.previousUpdateMetadata = function () { o.previousUpdateMetadata = function () {
for (var prev_rev in previous_revision_object) { var i;
delete metadata_file_content[prev_rev]; for (i = 0; i < param.key.length; i+= 1) {
delete metadata_file_content[param.key[i]];
} }
am.call(o,'checkForConflicts'); am.call(o,'checkForConflicts');
}; };
o.checkForConflicts = function () { o.checkForConflicts = function () {
for (var rev in metadata_file_content) { var rev;
for (rev in metadata_file_content) {
var revision_index; var revision_index;
on_conflict = true; on_conflict = true;
failerror = { failerror = {
status:20, status:409,error:'conflict',
statusText:'Conflict', statusText:'Conflict',reason:'document update conflict',
message:'There is one or more conflicts' message:'There is one or more conflicts'
}; };
break; break;
...@@ -1404,22 +1388,29 @@ var newConflictManagerStorage = function ( spec, my ) { ...@@ -1404,22 +1388,29 @@ var newConflictManagerStorage = function ( spec, my ) {
am.call(o,'updateMetadata'); am.call(o,'updateMetadata');
}; };
o.updateMetadata = function (){ 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] = { metadata_file_content[current_revision] = {
creation_date: previous_revision_content_object.creation_date || _creation_date:previous_revision_content_object._creation_date||
now.getTime(), now.getTime(),
last_modified: now.getTime(), _last_modified: now.getTime(),
conflict: on_conflict, _revisions: revision_history,
deleted: on_remove _conflict: on_conflict,
_deleted: on_remove
}; };
conflict_object = if (on_conflict) {
priv.createConflictObject( conflict_object =
command, metadata_file_content, current_revision priv.createConflictObject(
); command, metadata_file_content, current_revision
);
}
am.call(o,'saveMetadataOnDistant'); am.call(o,'saveMetadataOnDistant');
}; };
o.saveMetadataOnDistant = function (){ o.saveMetadataOnDistant = function (){
priv.saveMetadataToDistant( priv.saveMetadataToDistant(
command, metadata_file_path,metadata_file_content, command, metadata_file_path, metadata_file_content,
function (result) { function (result) {
am.call(o,'deleteAllConflictingRevision'); am.call(o,'deleteAllConflictingRevision');
if (on_conflict) { if (on_conflict) {
...@@ -1433,58 +1424,115 @@ var newConflictManagerStorage = function ( spec, my ) { ...@@ -1433,58 +1424,115 @@ var newConflictManagerStorage = function ( spec, my ) {
); );
}; };
o.deleteAllConflictingRevision = function (){ o.deleteAllConflictingRevision = function (){
for (var prev_rev in previous_revision_object) { var i;
for (i = 0; i < param.key.length; i+= 1) {
priv.deleteAFile ( priv.deleteAFile (
command, path+'.'+prev_rev, empty_fun, empty_fun ); command, param.docid+'.'+param.key[i], empty_fun,empty_fun);
} }
}; };
o.success = function (){ o.success = function (){
var a = {ok:true,id:param.docid,rev:current_revision};
am.neverCall(o,'error'); am.neverCall(o,'error');
am.neverCall(o,'success'); am.neverCall(o,'success');
if (option.success) {option.success({revision:current_revision});} 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){ o.error = function (error){
var gooderror = error || failerror || {}; var err = error || failerror ||
if (on_conflict) { {status:0,statusText:'Unknown',error:'unknown_error',
gooderror.conflict_object = conflict_object; 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,'error');
am.neverCall(o,'success'); am.neverCall(o,'success');
if (option.error) {option.error(gooderror);} param.error(err);
}; };
am.call(o,'getDistantMetadata'); am.call(o,'getDistantMetadata');
}; };
priv.createConflictObject = function (command, metadata, revision) { priv.createConflictObject = function (command, metadata, revision) {
var cloned_command = command.clone(); return {
var conflict_object = { total_rows:1,
path: command.getPath(), rows:[priv.createConflictRow(command,command.getDocId(),
revision: revision, metadata,revision)]
revision_object: metadata, };
getConflictRevisionList: function () { };
return this.revision_object;
}, priv.getParam = function (list) {
solveConflict: function (content,option) { var param = {}, i = 0;
if (typeof content === 'undefined') { if (typeof list[i] === 'string') {
option = option || {}; param.content = list[i];
option.deleted = true; i ++;
} else if (typeof content === 'object') { }
option = content; if (typeof list[i] === 'object') {
option.deleted = true; param.options = list[i];
i ++;
} else {
param.options = {};
}
param.callback = function (err,val){};
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:{
_solveConflict: function (/*content, option, success, error*/) {
var param = {}, got = priv.getParam(arguments);
if (got.content === undefined) {
param._deleted = true;
} else { } else {
option = option || {}; param._deleted = false;
option.deleted = false;
content = content || '';
} }
option.previous_revision = this.revision; param.success = got.success;
option.revision_remove_object = this.revision_object; param.error = got.error;
option.command = cloned_command; param.previous_revision = revision;
param.docid = docid;
param.key = row.key;
param.command = command.clone();
return priv.solveConflict ( return priv.solveConflict (
this.path, content, option {_id:docid,content:got.content,_rev:revision},
got.options,param
); );
} }
}; }}, k;
return conflict_object; for (k in metadata) {
row.key.push(k);
}
return row;
}; };
priv.newAsyncModule = function () { priv.newAsyncModule = function () {
...@@ -1515,31 +1563,28 @@ var newConflictManagerStorage = function ( spec, my ) { ...@@ -1515,31 +1563,28 @@ var newConflictManagerStorage = function ( spec, my ) {
return async; return async;
}; };
that.post = function (command) {
that.put (command);
};
/** /**
* Save a document and can manage conflicts. * Save a document and can manage conflicts.
* @method saveDocument * @method put
*/ */
that.saveDocument = function (command) { that.put = function (command) {
var o = {}, am = priv.newAsyncModule(), var o = {}, am = priv.newAsyncModule(),
metadata_file_path = command.getPath() + '.metadata', metadata_file_path = command.getDocId() + '.metadata',
current_revision = '', current_revision = '',
current_revision_file_path = '', current_revision_file_path = '',
metadata_file_content = null, metadata_file_content = null,
on_conflict = false, conflict_object = {}, on_conflict = false, conflict_object = {total_rows:0,rows:[]},
previous_revision = command.getOption('previous_revision'), previous_revision = command.getDocInfo('_rev') || '0',
previous_revision_file_path = command.getPath() + '.' + previous_revision_file_path = command.getDocId() + '.' +
previous_revision, previous_revision,
now = new Date(), now = new Date(),
failerror; failerror;
if (!previous_revision) {
return setTimeout(function () {
that.error({status:0,statusText:'Parameter missing',
message:'Need a previous revision.'});
});
}
o.getDistantMetadata = function (){ o.getDistantMetadata = function (){
priv.getDistantMetadata ( priv.getDistantMetadata (
command,metadata_file_path, command,metadata_file_path,
...@@ -1549,10 +1594,10 @@ var newConflictManagerStorage = function ( spec, my ) { ...@@ -1549,10 +1594,10 @@ var newConflictManagerStorage = function ( spec, my ) {
metadata_file_content = JSON.parse (result.content); metadata_file_content = JSON.parse (result.content);
// set current revision // set current revision
current_revision = (previous_revision_number + 1) + '-' + current_revision = (previous_revision_number + 1) + '-' +
hex_sha256 ('' + command.getContent() + hex_sha256 ('' + command.getDocContent() +
previous_revision + previous_revision +
JSON.stringify (metadata_file_content)); JSON.stringify (metadata_file_content));
current_revision_file_path = command.getPath() + '.' + current_revision_file_path = command.getDocId() + '.' +
current_revision; current_revision;
am.wait(o,'saveMetadataOnDistant',1); am.wait(o,'saveMetadataOnDistant',1);
am.call(o,'saveNewRevision'); am.call(o,'saveNewRevision');
...@@ -1560,8 +1605,8 @@ var newConflictManagerStorage = function ( spec, my ) { ...@@ -1560,8 +1605,8 @@ var newConflictManagerStorage = function ( spec, my ) {
},function (error) { },function (error) {
if (error.status === 404) { if (error.status === 404) {
current_revision = '1-' + current_revision = '1-' +
hex_sha256 (command.getContent()); hex_sha256 (command.getDocContent());
current_revision_file_path = command.getPath() + '.' + current_revision_file_path = command.getDocId() + '.' +
current_revision; current_revision;
am.wait(o,'saveMetadataOnDistant',1); am.wait(o,'saveMetadataOnDistant',1);
am.call(o,'saveNewRevision'); am.call(o,'saveNewRevision');
...@@ -1574,7 +1619,7 @@ var newConflictManagerStorage = function ( spec, my ) { ...@@ -1574,7 +1619,7 @@ var newConflictManagerStorage = function ( spec, my ) {
}; };
o.saveNewRevision = function (){ o.saveNewRevision = function (){
priv.saveNewRevision ( priv.saveNewRevision (
command,current_revision_file_path,command.getContent(), command,current_revision_file_path,command.getDocContent(),
function (result) { function (result) {
am.call(o,'saveMetadataOnDistant'); am.call(o,'saveMetadataOnDistant');
}, function (error) { }, function (error) {
...@@ -1583,13 +1628,14 @@ var newConflictManagerStorage = function ( spec, my ) { ...@@ -1583,13 +1628,14 @@ var newConflictManagerStorage = function ( spec, my ) {
); );
}; };
o.checkForConflicts = function () { o.checkForConflicts = function () {
for (var rev in metadata_file_content) { var rev;
for (rev in metadata_file_content) {
if (rev !== previous_revision) { if (rev !== previous_revision) {
on_conflict = true; on_conflict = true;
failerror = { failerror = {
status:20, status:409,error:'conflict',
statusText:'Conflict', statusText:'Conflict',reason:'document update conflict',
message:'There is one or more conflicts' message:'Document update conflict.'
}; };
break; break;
} }
...@@ -1597,41 +1643,47 @@ var newConflictManagerStorage = function ( spec, my ) { ...@@ -1597,41 +1643,47 @@ var newConflictManagerStorage = function ( spec, my ) {
am.call(o,'updateMetadata'); am.call(o,'updateMetadata');
}; };
o.createMetadata = function (){ o.createMetadata = function (){
var id = current_revision;
id = id.split('-'); id.shift(); id = id.join('-');
metadata_file_content = {}; metadata_file_content = {};
metadata_file_content[current_revision] = { metadata_file_content[current_revision] = {
creation_date: now.getTime(), _creation_date: now.getTime(),
last_modified: now.getTime(), _last_modified: now.getTime(),
conflict: false, _revisions: [id],
deleted: false _conflict: false,
_deleted: false
}; };
am.call(o,'saveMetadataOnDistant'); am.call(o,'saveMetadataOnDistant');
}; };
o.updateMetadata = function (){ o.updateMetadata = function (){
var previous_creation_date; var previous_creation_date, revision_history = [], id = '';
if (metadata_file_content[previous_revision]) { if (metadata_file_content[previous_revision]) {
previous_creation_date = metadata_file_content[ previous_creation_date = metadata_file_content[
previous_revision].creation_date; previous_revision]._creation_date;
revision_history = metadata_file_content[
previous_revision]._revisions;
delete metadata_file_content[previous_revision]; delete metadata_file_content[previous_revision];
} }
id = current_revision.split('-'); id.shift(); id = id.join('-');
revision_history.unshift(id);
metadata_file_content[current_revision] = { metadata_file_content[current_revision] = {
creation_date: previous_creation_date || now.getTime(), _creation_date: previous_creation_date || now.getTime(),
last_modified: now.getTime(), _last_modified: now.getTime(),
conflict: on_conflict, _revisions: revision_history,
deleted: false _conflict: on_conflict,
_deleted: false
}; };
if (on_conflict) { if (on_conflict) {
conflict_object = conflict_object =
priv.createConflictObject( priv.createConflictObject(
command, command, metadata_file_content, current_revision
metadata_file_content,
current_revision
); );
} }
am.call(o,'saveMetadataOnDistant'); am.call(o,'saveMetadataOnDistant');
}; };
o.saveMetadataOnDistant = function (){ o.saveMetadataOnDistant = function (){
priv.saveMetadataToDistant( priv.saveMetadataToDistant(
command,metadata_file_path,metadata_file_content, command, metadata_file_path, metadata_file_content,
function (result) { function (result) {
am.call(o,'deletePreviousRevision'); am.call(o,'deletePreviousRevision');
if (on_conflict) { if (on_conflict) {
...@@ -1651,44 +1703,65 @@ var newConflictManagerStorage = function ( spec, my ) { ...@@ -1651,44 +1703,65 @@ var newConflictManagerStorage = function ( spec, my ) {
empty_fun,empty_fun); empty_fun,empty_fun);
} }
}; };
o.success = function (){ o.success = function () {
var a = {ok:true,id:command.getDocId(),rev:current_revision};
am.neverCall(o,'error'); am.neverCall(o,'error');
am.neverCall(o,'success'); am.neverCall(o,'success');
that.success({revision:current_revision}); 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){ o.error = function (error) {
var gooderror = error || failerror || var err = error || failerror ||
{status:0,statusText:'Unknown', {status:0,statusText:'Unknown',error:'unknown_error',
message:'Unknown error.'}; message:'Unknown error.',reason:'unknown error'};
if (on_conflict) { if (current_revision) {
gooderror.conflict_object = conflict_object; 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,'error');
am.neverCall(o,'success'); am.neverCall(o,'success');
that.error(gooderror); that.error(err);
}; };
am.call(o,'getDistantMetadata'); am.call(o,'getDistantMetadata');
}; }; // end put
/** /**
* Load a document from several storages, and send the first retreived * Load a document from several storages, and send the first retreived
* document. * document.
* @method loadDocument * @method get
*/ */
that.loadDocument = function (command) { that.get = function (command) {
var o = {}, am = priv.newAsyncModule(), var o = {}, am = priv.newAsyncModule(),
metadata_file_path = command.getPath() + '.metadata', metadata_file_path = command.getDocId() + '.metadata',
current_revision = command.getOption('revision') || '', current_revision = command.getOption('rev') || '',
metadata_file_content = null, metadata_file_content = null,
metadata_only = command.getOption('metadata_only'), metadata_only = command.getOption('metadata_only'),
on_conflict = false, conflict_object = {}, on_conflict = false, conflict_object = {total_rows:0,rows:[]},
now = new Date(), now = new Date(),
doc = {name:command.getPath()}, doc = {_id:command.getDocId()},
call404 = function (message) { call404 = function (message) {
am.call(o,'error',[{ am.call(o,'error',[{
status:404,statusText:'Not Found', status:404,statusText:'Not Found',error:'not_found',
message:message message:message,reason:message
}]); }]);
}; };
...@@ -1715,12 +1788,18 @@ var newConflictManagerStorage = function ( spec, my ) { ...@@ -1715,12 +1788,18 @@ var newConflictManagerStorage = function ( spec, my ) {
} else { } else {
current_revision = priv.chooseARevision(metadata_file_content); current_revision = priv.chooseARevision(metadata_file_content);
} }
doc.last_modified = doc._last_modified =
metadata_file_content[current_revision].last_modified; metadata_file_content[current_revision]._last_modified;
doc.creation_date = doc._creation_date =
metadata_file_content[current_revision].creation_date; metadata_file_content[current_revision]._creation_date;
doc.revision = current_revision; doc._rev = current_revision;
doc.revision_object = metadata_file_content; 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 (metadata_only) { if (metadata_only) {
am.call(o,'success'); am.call(o,'success');
} else { } else {
...@@ -1729,11 +1808,11 @@ var newConflictManagerStorage = function ( spec, my ) { ...@@ -1729,11 +1808,11 @@ var newConflictManagerStorage = function ( spec, my ) {
}; };
o.loadRevision = function (){ o.loadRevision = function (){
if (!current_revision || if (!current_revision ||
metadata_file_content[current_revision].deleted) { metadata_file_content[current_revision]._deleted) {
return call404('Document has been removed.'); return call404('Document has been removed.');
} }
priv.loadRevision ( priv.loadRevision (
command, doc.name+'.'+current_revision, command, doc._id+'.'+current_revision,
function (result) { function (result) {
doc.content = result.content; doc.content = result.content;
am.call(o,'success'); am.call(o,'success');
...@@ -1751,7 +1830,9 @@ var newConflictManagerStorage = function ( spec, my ) { ...@@ -1751,7 +1830,9 @@ var newConflictManagerStorage = function ( spec, my ) {
metadata_file_content, metadata_file_content,
current_revision current_revision
); );
doc.conflict_object = conflict_object; }
if (command.getOption('conflicts')) {
doc._conflicts = conflict_object;
} }
am.call(o,'success'); am.call(o,'success');
}; };
...@@ -1776,35 +1857,30 @@ var newConflictManagerStorage = function ( spec, my ) { ...@@ -1776,35 +1857,30 @@ var newConflictManagerStorage = function ( spec, my ) {
/** /**
* Get a document list from several storages, and returns the first * Get a document list from several storages, and returns the first
* retreived document list. * retreived document list.
* @method getDocumentList * @method allDocs
*/ */
that.getDocumentList = function (command) { that.allDocs = function (command) {
var o = {}, am = priv.newAsyncModule(), var o = {}, am = priv.newAsyncModule(),
metadata_only = command.getOption('metadata_only'), metadata_only = command.getOption('metadata_only'),
result_list = [], result_list = [],
nb_loaded_file = 0, nb_loaded_file = 0,
success_count = 0, success_max = 0; success_count = 0, success_max = 0;
o.retreiveList = function () { o.retreiveList = function () {
var cloned_option = command.cloneOption (); var cloned_option = command.cloneOption (),
cloned_option.metadata_only = true; success = function (result) {
cloned_option.error = function (error) {
am.call(o,'error',[error]);
};
cloned_option.success = function (result) {
am.call(o,'filterTheList',[result]); am.call(o,'filterTheList',[result]);
},error = function (error) {
am.call(o,'error',[error]);
}; };
var newcommand = that.newCommand( cloned_option.metadata_only = true;
'getDocumentList',{ that.addJob ('allDocs',priv.secondstorage_spec,null,cloned_option,
path:command.getPath(),option:cloned_option success,error);
});
that.addJob ( that.newStorage (priv.secondstorage_spec),
newcommand );
}; };
o.filterTheList = function (result) { o.filterTheList = function (result) {
var i; var i;
success_max ++; success_max ++;
for (i = 0; i < result.length; i+= 1) { for (i = 0; i < result.total_rows; i+= 1) {
var splitname = result[i].name.split('.') || []; var splitname = result.rows[i].id.split('.') || [];
if (splitname.length > 0 && if (splitname.length > 0 &&
splitname[splitname.length-1] === 'metadata') { splitname[splitname.length-1] === 'metadata') {
success_max ++; success_max ++;
...@@ -1820,7 +1896,7 @@ var newConflictManagerStorage = function ( spec, my ) { ...@@ -1820,7 +1896,7 @@ var newConflictManagerStorage = function ( spec, my ) {
function (data) { function (data) {
data = JSON.parse (data.content); data = JSON.parse (data.content);
var revision = priv.chooseARevision(data); var revision = priv.chooseARevision(data);
if (!data[revision].deleted) { if (!data[revision]._deleted) {
am.call( am.call(
o,'loadFile', o,'loadFile',
[path,revision,data] [path,revision,data]
...@@ -1835,15 +1911,22 @@ var newConflictManagerStorage = function ( spec, my ) { ...@@ -1835,15 +1911,22 @@ var newConflictManagerStorage = function ( spec, my ) {
}; };
o.loadFile = function (path,revision,data) { o.loadFile = function (path,revision,data) {
var doc = { var doc = {
name: path, id: path,key: path,value:{
last_modified:data[revision].last_modified, _last_modified:data[revision]._last_modified,
creation_date:data[revision].creation_date, _creation_date:data[revision]._creation_date,
revision:revision, _rev:revision
revision_object:data }
}; };
if (data[revision].conflict) { if (command.getOption('revs_info')) {
doc.conflict_object = priv.createConflictObject( doc.value._revs_info = priv._revs_info(data,revision);
command, data, revision ); }
if (command.getOption('conflicts')) {
if (data[revision]._conflict) {
doc.value._conflicts = priv.createConflictObject(
command, data, revision );
} else {
doc.value._conflicts = {total_rows:0,rows:[]};
}
} }
if (!metadata_only) { if (!metadata_only) {
priv.loadRevision ( priv.loadRevision (
...@@ -1864,7 +1947,7 @@ var newConflictManagerStorage = function ( spec, my ) { ...@@ -1864,7 +1947,7 @@ var newConflictManagerStorage = function ( spec, my ) {
success_count ++; success_count ++;
if (success_count >= success_max) { if (success_count >= success_max) {
am.end(); am.end();
that.success(result_list); that.success({total_rows:result_list.length,rows:result_list});
} }
}; };
o.error = function (error){ o.error = function (error){
...@@ -1872,33 +1955,26 @@ var newConflictManagerStorage = function ( spec, my ) { ...@@ -1872,33 +1955,26 @@ var newConflictManagerStorage = function ( spec, my ) {
that.error(error); that.error(error);
}; };
am.call(o,'retreiveList'); am.call(o,'retreiveList');
}; }; // end allDocs
/** /**
* Remove a document from several storages. * Remove a document from several storages.
* @method removeDocument * @method remove
*/ */
that.removeDocument = function (command) { that.remove = function (command) {
var o = {}, am = priv.newAsyncModule(), var o = {}, am = priv.newAsyncModule(),
metadata_file_path = command.getPath() + '.metadata', metadata_file_path = command.getDocId() + '.metadata',
current_revision = '', current_revision = '',
current_revision_file_path = '', current_revision_file_path = '',
metadata_file_content = null, metadata_file_content = null,
on_conflict = false, conflict_object = {}, on_conflict = false, conflict_object = {total_rows:0,rows:[]},
previous_revision = command.getOption('revision'), previous_revision = command.getOption('rev') || '0',
previous_revision_file_path = command.getPath() + '.' + previous_revision_file_path = command.getDocId() + '.' +
previous_revision, previous_revision,
now = new Date(), now = new Date(),
failerror; failerror;
if (!previous_revision) {
return setTimeout(function () {
that.error({status:0,statusText:'Parameter missing',
message:'Need a revision.'});
});
}
o.getDistantMetadata = function (){ o.getDistantMetadata = function (){
priv.getDistantMetadata ( priv.getDistantMetadata (
command,metadata_file_path, command,metadata_file_path,
...@@ -1907,21 +1983,25 @@ var newConflictManagerStorage = function ( spec, my ) { ...@@ -1907,21 +1983,25 @@ var newConflictManagerStorage = function ( spec, my ) {
if (previous_revision === 'last') { if (previous_revision === 'last') {
previous_revision = previous_revision =
priv.chooseARevision (metadata_file_content); priv.chooseARevision (metadata_file_content);
previous_revision_file_path = command.getPath() + '.' + previous_revision_file_path = command.getDocId() + '.' +
previous_revision; previous_revision;
} }
var previous_revision_number = var previous_revision_number =
parseInt(previous_revision.split('-')[0],10); parseInt(previous_revision.split('-')[0],10) || 0;
// set current revision // set current revision
current_revision = (previous_revision_number + 1) + '-' + current_revision = (previous_revision_number + 1) + '-' +
hex_sha256 ('' + previous_revision + hex_sha256 ('' + previous_revision +
JSON.stringify (metadata_file_content)); JSON.stringify (metadata_file_content));
current_revision_file_path = command.getPath() + '.' + current_revision_file_path = command.getDocId() + '.' +
current_revision; current_revision;
am.call(o,'checkForConflicts'); am.call(o,'checkForConflicts');
},function (error) { },function (error) {
if (error.status === 404) { if (error.status === 404) {
am.call(o,'success',['0']); am.call(o,'error',[{
status:404,statusText:'Not Found',
error:'not_found',reason:'missing',
message:'Document not found.'
}]);
} else { } else {
am.call(o,'error',[error]); am.call(o,'error',[error]);
} }
...@@ -1929,12 +2009,13 @@ var newConflictManagerStorage = function ( spec, my ) { ...@@ -1929,12 +2009,13 @@ var newConflictManagerStorage = function ( spec, my ) {
); );
}; };
o.checkForConflicts = function () { o.checkForConflicts = function () {
for (var rev in metadata_file_content) { var rev;
for (rev in metadata_file_content) {
if (rev !== previous_revision) { if (rev !== previous_revision) {
on_conflict = true; on_conflict = true;
failerror = { failerror = {
status:20, status:409,error:'conflict',
statusText:'Conflict', statusText:'Conflict',reason:'document update conflict',
message:'There is one or more conflicts' message:'There is one or more conflicts'
}; };
break; break;
...@@ -1943,31 +2024,35 @@ var newConflictManagerStorage = function ( spec, my ) { ...@@ -1943,31 +2024,35 @@ var newConflictManagerStorage = function ( spec, my ) {
am.call(o,'updateMetadata'); am.call(o,'updateMetadata');
}; };
o.updateMetadata = function (){ o.updateMetadata = function (){
var previous_creation_date; var previous_creation_date, revision_history = [], id = '';
if (metadata_file_content[previous_revision]) { if (metadata_file_content[previous_revision]) {
previous_creation_date = metadata_file_content[ previous_creation_date = metadata_file_content[
previous_revision].creation_date; previous_revision]._creation_date;
revision_history = metadata_file_content[
previous_revision]._revisions;
delete metadata_file_content[previous_revision]; 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] = { metadata_file_content[current_revision] = {
creation_date: previous_creation_date || now.getTime(), _creation_date: previous_creation_date || now.getTime(),
last_modified: now.getTime(), _last_modified: now.getTime(),
conflict: on_conflict, _revisions: revision_history,
deleted: true _conflict: on_conflict,
_deleted: true
}; };
if (on_conflict) { if (on_conflict) {
conflict_object = conflict_object =
priv.createConflictObject( priv.createConflictObject(
command, command, metadata_file_content, current_revision
metadata_file_content,
current_revision
); );
} }
am.call(o,'saveMetadataOnDistant'); am.call(o,'saveMetadataOnDistant');
}; };
o.saveMetadataOnDistant = function (){ o.saveMetadataOnDistant = function (){
priv.saveMetadataToDistant( priv.saveMetadataToDistant(
command,metadata_file_path,metadata_file_content, command, metadata_file_path, metadata_file_content,
function (result) { function (result) {
am.call(o,'deletePreviousRevision'); am.call(o,'deletePreviousRevision');
if (on_conflict) { if (on_conflict) {
...@@ -1988,23 +2073,45 @@ var newConflictManagerStorage = function ( spec, my ) { ...@@ -1988,23 +2073,45 @@ var newConflictManagerStorage = function ( spec, my ) {
} }
}; };
o.success = function (revision){ o.success = function (revision){
var a = {ok:true,id:command.getDocId(),
rev:revision || current_revision};
am.neverCall(o,'error'); am.neverCall(o,'error');
am.neverCall(o,'success'); am.neverCall(o,'success');
that.success({revision:revision || current_revision}); 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){ o.error = function (error){
var gooderror = error || failerror || var err = error || failerror ||
{status:0,statusText:'Unknown', {status:0,statusText:'Unknown',error:'unknown_error',
message:'Unknown error.'}; message:'Unknown error.',reason:'unknown error'};
if (on_conflict) { if (current_revision) {
gooderror.conflict_object = conflict_object; 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,'error');
am.neverCall(o,'success'); am.neverCall(o,'success');
that.error(gooderror); that.error(err);
}; };
am.call(o,'getDistantMetadata'); am.call(o,'getDistantMetadata');
}; }; // end remove
return that; return that;
}; };
......
/*! JIO Storage - v0.1.0 - 2012-08-07 /*! JIO Storage - v0.1.0 - 2012-08-14
* Copyright (c) 2012 Nexedi; Licensed */ * Copyright (c) 2012 Nexedi; Licensed */
(function(a,b,c,d,e,f){var g=function(b,c){var d=f.storage(b,c,"base"),e={};e.username=b.username||"",e.applicationname=b.applicationname||"untitled";var g="jio/local_user_array",h="jio/local_file_name_array/"+e.username+"/"+e.applicationname,i=d.serialized;return d.serialized=function(){var a=i();return a.applicationname=e.applicationname,a.username=e.username,a},d.validateState=function(){return e.username?"":'Need at least one parameter: "username".'},e.getUserArray=function(){return a.getItem(g)||[]},e.addUser=function(b){var c=e.getUserArray();c.push(b),a.setItem(g,c)},e.userExists=function(a){var b=e.getUserArray(),c,d;for(c=0,d=b.length;c<d;c+=1)if(b[c]===a)return!0;return!1},e.getFileNameArray=function(){return a.getItem(h)||[]},e.addFileName=function(b){var c=e.getFileNameArray();c.push(b),a.setItem(h,c)},e.removeFileName=function(b){var c,d,f=e.getFileNameArray(),g=[];for(c=0,d=f.length;c<d;c+=1)f[c]!==b&&g.push(f[c]);a.setItem(h,g)},d.saveDocument=function(b){setTimeout(function(){var c=null,f="jio/local/"+e.username+"/"+e.applicationname+"/"+b.getPath();c=a.getItem(f),c?(c.last_modified=Date.now(),c.content=b.getContent()):(c={name:b.getPath(),content:b.getContent(),creation_date:Date.now(),last_modified:Date.now()},e.userExists(e.username)||e.addUser(e.username),e.addFileName(b.getPath())),a.setItem(f,c),d.success()})},d.loadDocument=function(b){setTimeout(function(){var c=null;c=a.getItem("jio/local/"+e.username+"/"+e.applicationname+"/"+b.getPath()),c?(b.getOption("metadata_only")&&delete c.content,d.success(c)):d.error({status:404,statusText:"Not Found.",message:'Document "'+b.getPath()+'" not found in localStorage.'})})},d.getDocumentList=function(b){setTimeout(function(){var c=[],f=[],g,h,i="key",j="jio/local/"+e.username+"/"+e.applicationname,k={};f=e.getFileNameArray();for(g=0,h=f.length;g<h;g+=1)k=a.getItem(j+"/"+f[g]),k&&(b.getOption("metadata_only")?c.push({name:k.name,creation_date:k.creation_date,last_modified:k.last_modified}):c.push({name:k.name,content:k.content,creation_date:k.creation_date,last_modified:k.last_modified}));d.success(c)})},d.removeDocument=function(b){setTimeout(function(){var c="jio/local/"+e.username+"/"+e.applicationname+"/"+b.getPath();a.deleteItem(c),e.removeFileName(b.getPath()),d.success()})},d};f.addStorageType("local",g);var h=function(a,d){var e=f.storage(a,d,"base"),g={};g.username=a.username||"",g.applicationname=a.applicationname||"untitled",g.url=a.url||"",g.password=a.password||"";var h=e.serialized;return e.serialized=function(){var a=h();return a.username=g.username,a.applicationname=g.applicationname,a.url=g.url,a.password=g.password,a},e.validateState=function(){return g.username&&g.url?"":'Need at least 2 parameters: "username" and "url".'},g.newAsyncModule=function(){var a={};return a.call=function(a,b,c){return a._wait=a._wait||{},a._wait[b]?(a._wait[b]--,function(){}):(c=c||[],a[b].apply(a[b],c))},a.neverCall=function(a,b){a._wait=a._wait||{},a._wait[b]=-1},a.wait=function(a,b,c){a._wait=a._wait||{},a._wait[b]=c},a.end=function(){a.call=function(){}},a},e.saveDocument=function(a){b.ajax({url:g.url+"/dav/"+g.username+"/"+g.applicationname+"/"+a.getPath(),type:"PUT",data:a.getContent(),async:!0,dataType:"text",headers:{Authorization:"Basic "+c.encode(g.username+":"+g.password)},success:function(){e.success()},error:function(b){b.message='Cannot save "'+a.getPath()+'" into DAVStorage.',e.retry(b)}})},e.loadDocument=function(a){var d={},f=function(){b.ajax({url:g.url+"/dav/"+g.username+"/"+g.applicationname+"/"+a.getPath(),type:"GET",async:!0,dataType:"text",headers:{Authorization:"Basic "+c.encode(g.username+":"+g.password)},success:function(a){d.content=a,e.success(d)},error:function(b){b.status===404?(b.message='Document "'+a.getPath()+'" not found in localStorage.',e.error(b)):(b.message='Cannot load "'+a.getPath()+'" from DAVStorage.',e.retry(b))}})};d.name=a.getPath(),b.ajax({url:g.url+"/dav/"+g.username+"/"+g.applicationname+"/"+a.getPath(),type:"PROPFIND",async:!0,dataType:"xml",headers:{Authorization:"Basic "+c.encode(g.username+":"+g.password)},success:function(c){b(c).find("lp1\\:getlastmodified, getlastmodified").each(function(){d.last_modified=b(this).text()}),b(c).find("lp1\\:creationdate, creationdate").each(function(){d.creation_date=b(this).text()}),a.getOption("metadata_only")?e.success(d):f()},error:function(b){b.message='Cannot load "'+a.getPath()+'" informations from DAVStorage.',b.status===404?e.error(b):e.retry(b)}})},e.getDocumentList=function(a){var d=[],f={},h=[],i=g.newAsyncModule(),j={};j.getContent=function(a){b.ajax({url:g.url+"/dav/"+g.username+"/"+g.applicationname+"/"+a.name,type:"GET",async:!0,dataType:"text",headers:{Authorization:"Basic "+c.encode(g.username+":"+g.password)},success:function(b){a.content=b,d.push(a),i.call(j,"success")},error:function(a){a.message="Cannot get a document content from DAVStorage.",i.call(j,"error",[a])}})},j.getDocumentList=function(){b.ajax({url:g.url+"/dav/"+g.username+"/"+g.applicationname+"/",async:!0,type:"PROPFIND",dataType:"xml",headers:{Authorization:"Basic "+c.encode(g.username+":"+g.password),Depth:"1"},success:function(c){var e=b(c).find("D\\:response, response"),g=e.length;if(g===1)return i.call(j,"success");i.wait(j,"success",g-2),e.each(function(c,e){if(c>0){f={},b(e).find("D\\:href, href").each(function(){h=b(this).text().split("/"),f.name=h[h.length-1]?h[h.length-1]:h[h.length-2]+"/"});if(f.name===".htaccess"||f.name===".htpasswd")return;b(e).find("lp1\\:getlastmodified, getlastmodified").each(function(){f.last_modified=b(this).text()}),b(e).find("lp1\\:creationdate, creationdate").each(function(){f.creation_date=b(this).text()}),a.getOption("metadata_only")?(d.push(f),i.call(j,"success")):i.call(j,"getContent",[f])}})},error:function(a){a.message="Cannot get a document list from DAVStorage.",a.status===404?i.call(j,"error",[a]):i.call(j,"retry",[a])}})},j.retry=function(a){i.neverCall(j,"retry"),i.neverCall(j,"success"),i.neverCall(j,"error"),e.retry(a)},j.error=function(a){i.neverCall(j,"retry"),i.neverCall(j,"success"),i.neverCall(j,"error"),e.error(a)},j.success=function(){i.neverCall(j,"retry"),i.neverCall(j,"success"),i.neverCall(j,"error"),e.success(d)},i.call(j,"getDocumentList")},e.removeDocument=function(a){b.ajax({url:g.url+"/dav/"+g.username+"/"+g.applicationname+"/"+a.getPath(),type:"DELETE",async:!0,headers:{Authorization:"Basic "+c.encode(g.username+":"+g.password)},success:function(){e.success()},error:function(a){a.status===404?e.success():(a.message='Cannot remove "'+e.getFileName()+'" from DAVStorage.',e.retry(a))}})},e};f.addStorageType("dav",h);var i=function(a,b){var c=f.storage(a,b,"handler"),d={};d.return_value_array=[],d.storagelist=a.storagelist||[],d.nb_storage=d.storagelist.length;var e=c.serialized;return c.serialized=function(){var a=e();return a.storagelist=d.storagelist,a},c.validateState=function(){return d.storagelist.length===0?'Need at least one parameter: "storagelist" containing at least one storage.':""},d.isTheLast=function(){return d.return_value_array.length===d.nb_storage},d.doJob=function(a,b){var e=!1,f=[],g,h=function(a){d.return_value_array.push(a),e||(f.push(a),d.isTheLast()&&c.error({status:207,statusText:"Multi-Status",message:b,array:f}))},i=function(a){d.return_value_array.push(a),e||(e=!0,c.success(a))};for(g=0;g<d.nb_storage;g+=1){var j=a.clone(),k=c.newStorage(d.storagelist[g]);j.onErrorDo(h),j.onSuccessDo(i),c.addJob(k,j)}},c.saveDocument=function(a){d.doJob(a,'All save "'+a.getPath()+'" requests have failed.'),c.end()},c.loadDocument=function(a){d.doJob(a,'All load "'+a.getPath()+'" requests have failed.'),c.end()},c.getDocumentList=function(a){d.doJob(a,"All get document list requests have failed."),c.end()},c.removeDocument=function(a){d.doJob(a,'All remove "'+a.getPath()+'" requests have failed.'),c.end()},c};f.addStorageType("replicate",i);var j=function(b,c){var d=f.storage(b,c,"handler"),e={},g=b.storage||!1;e.secondstorage_spec=b.storage||{type:"base"},e.secondstorage_string=JSON.stringify(e.secondstorage_spec);var h="jio/indexed_storage_array",i="jio/indexed_file_array/"+e.secondstorage_string,j=d.serialized;return d.serialized=function(){var a=j();return a.storage=e.secondstorage_spec,a},d.validateState=function(){return g?"":'Need at least one parameter: "storage" containing storage specifications.'},e.isStorageArrayIndexed=function(){return a.getItem(h)?!0:!1},e.getIndexedStorageArray=function(){return a.getItem(h)||[]},e.indexStorage=function(b){var c=e.getIndexedStorageArray();c.push(typeof b=="string"?b:JSON.stringify(b)),a.setItem(h,c)},e.isAnIndexedStorage=function(a){var b=typeof a=="string"?a:JSON.stringify(a),c,d,f=e.getIndexedStorageArray();for(c=0,d=f.length;c<d;c+=1)if(JSON.stringify(f[c])===b)return!0;return!1},e.fileArrayExists=function(){return a.getItem(i)?!0:!1},e.getFileArray=function(){return a.getItem(i)||[]},e.setFileArray=function(b){return a.setItem(i,b)},e.isFileIndexed=function(a){var b,c,d=e.getFileArray();for(b=0,c=d.length;b<c;b+=1)if(d[b].name===a)return!0;return!1},e.addFile=function(b){var c=e.getFileArray();c.push(b),a.setItem(i,c)},e.removeFile=function(b){var c,d,f=e.getFileArray(),g=[];for(c=0,d=f.length;c<d;c+=1)f[c].name!==b&&g.push(f[c]);a.setItem(i,g)},e.update=function(){var a=function(a){e.isAnIndexedStorage(e.secondstorage_string)||e.indexStorage(e.secondstorage_string),e.setFileArray(a)};d.addJob(d.newStorage(e.secondstorage_spec),d.newCommand("getDocumentList",{path:".",option:{success:a,max_retry:3}}))},d.saveDocument=function(a){var b=a.clone();b.onSuccessDo(function(b){e.isFileIndexed(a.getPath())||e.addFile({name:a.getPath(),last_modified:0,creation_date:0}),e.update(),d.success()}),b.onErrorDo(function(a){d.error(a)}),d.addJob(d.newStorage(e.secondstorage_spec),b)},d.loadDocument=function(a){var b,c,f,g,h=function(a){d.success(a)},i=function(a){d.error(a)},j=function(){var b=a.clone();b.onErrorDo(i),b.onSuccessDo(h),d.addJob(d.newStorage(e.secondstorage_spec),b)};e.update(),a.getOption("metadata_only")?setTimeout(function(){if(e.fileArrayExists()){b=e.getFileArray();for(c=0,f=b.length;c<f;c+=1)if(b[c].name===a.getPath())return d.success(b[c])}else j()},100):j()},d.getDocumentList=function(a){var b,c,f=!1;e.update(),a.getOption("metadata_only")?(b=setInterval(function(){f&&(d.error({status:0,statusText:"Timeout",message:"The request has timed out."}),clearInterval(b)),e.fileArrayExists()&&(d.success(e.getFileArray()),clearInterval(b))},100),setTimeout(function(){f=!0},1e4)):(c=a.clone(),c.onSuccessDo(function(a){d.success(a)}),c.onErrorDo(function(a){d.error(a)}),d.addJob(d.newStorage(e.secondstorage_spec),c))},d.removeDocument=function(a){var b=a.clone();b.onSuccessDo(function(b){e.removeFile(a.getPath()),e.update(),d.success()}),b.onErrorDo(function(a){d.error(a)}),d.addJob(d.newStorage(e.secondstorage_spec),b)},d};f.addStorageType("indexed",j);var k=function(a,c){var e=f.storage(a,c,"handler"),g={},h=a.storage?!0:!1;g.username=a.username||"",g.password=a.password||"",g.secondstorage_spec=a.storage||{type:"base"},g.secondstorage_string=JSON.stringify(g.secondstorage_string);var i=e.serialized;return e.serialized=function(){var a=i();return a.username=g.username,a.password=g.password,a.storage=g.secondstorage_string,a},e.validateState=function(){return g.username&&h?"":'Need at least two parameters: "username" and "storage".'},g.encrypt_param_object={iv:"kaprWwY/Ucr7pumXoTHbpA",v:1,iter:1e3,ks:256,ts:128,mode:"ccm",adata:"",cipher:"aes",salt:"K4bmZG9d704"},g.decrypt_param_object={iv:"kaprWwY/Ucr7pumXoTHbpA",ks:256,ts:128,salt:"K4bmZG9d704"},g.encrypt=function(a,b){var c=d.encrypt(g.username+":"+g.password,a,g.encrypt_param_object);b(JSON.parse(c).ct)},g.decrypt=function(a,c){var e,f=b.extend(!0,{},g.decrypt_param_object);f.ct=a||"",f=JSON.stringify(f);try{e=d.decrypt(g.username+":"+g.password,f)}catch(h){c({status:0,statusText:"Decrypt Fail",message:"Unable to decrypt."});return}c(undefined,e)},g.newAsyncModule=function(){var a={};return a.call=function(a,b,c){a._wait=a._wait||{};if(a._wait[b])return a._wait[b]--,function(){};c=c||[],setTimeout(function(){a[b].apply(a[b],c)})},a.neverCall=function(a,b){a._wait=a._wait||{},a._wait[b]=-1},a.wait=function(a,b,c){a._wait=a._wait||{},a._wait[b]=c},a.end=function(){a.call=function(){}},a},e.saveDocument=function(a){var b,c,d=g.newAsyncModule(),f={};f.encryptFilePath=function(){g.encrypt(a.getPath(),function(a){b=a,d.call(f,"save")})},f.encryptFileContent=function(){g.encrypt(a.getContent(),function(a){c=a,d.call(f,"save")})},f.save=function(){var d=a.cloneOption(),f;d.success=function(){e.success()},d.error=function(a){e.error(a)},f=e.newCommand("saveDocument",{path:b,content:c,option:d}),e.addJob(e.newStorage(g.secondstorage_spec),f)},d.wait(f,"save",1),d.call(f,"encryptFilePath"),d.call(f,"encryptFileContent")},e.loadDocument=function(a){var b,c,d=g.newAsyncModule(),f={};f.encryptFilePath=function(){g.encrypt(a.getPath(),function(a){b=a,d.call(f,"loadDocument")})},f.loadDocument=function(){var c=a.cloneOption(),d;c.error=f.loadOnError,c.success=f.loadOnSuccess,d=e.newCommand("loadDocument",{path:b,option:c}),e.addJob(e.newStorage(g.secondstorage_spec),d)},f.loadOnSuccess=function(b){b.name=a.getPath(),a.getOption("metadata_only")?e.success(b):g.decrypt(b.content,function(a,c){a?e.error(a):(b.content=c,e.success(b))})},f.loadOnError=function(a){e.error(a)},d.call(f,"encryptFilePath")},e.getDocumentList=function(a){var b=[],c=g.newAsyncModule(),d={};d.getDocumentList=function(){var b=a.cloneOption();b.success=d.getListOnSuccess,b.error=d.getListOnError,e.addJob(e.newStorage(g.secondstorage_spec),e.newCommand("getDocumentList",{path:a.getPath(),option:b}))},d.getListOnSuccess=function(e){b=e;var f,h=function(e){g.decrypt(b[e].name,function(a,b){a?c.call(d,"error",[a]):c.call(d,"pushResult",[b,e,"name"])}),a.getOption("metadata_only")||g.decrypt(b[e].content,function(a,b){a?c.call(d,"error",[a]):c.call(d,"pushResult",[b,e,"content"])})};a.getOption("metadata_only")?c.wait(d,"success",e.length-1):c.wait(d,"success",e.length*2-1);for(f=0;f<b.length;f+=1)h(f)},d.getListOnError=function(a){c.call(d,"error",[a])},d.pushResult=function(a,e,f){b[e][f]=a,c.call(d,"success")},d.error=function(a){c.end(),e.error(a)},d.success=function(){c.end(),e.success(b)},c.call(d,"getDocumentList")},e.removeDocument=function(a){var b,c={};c.encryptFilePath=function(){g.encrypt(a.getPath(),function(a){b=a,c.removeDocument()})},c.removeDocument=function(){var d=a.cloneOption();d.error=c.removeOnError,d.success=c.removeOnSuccess,e.addJob(e.newStorage(g.secondstorage_spec),e.newCommand("removeDocument",{path:b,option:d}))},c.removeOnSuccess=function(a){e.success()},c.removeOnError=function(a){e.error(a)},c.encryptFilePath()},e};f.addStorageType("crypt",k);var l=function(a,b){var c=f.storage(a,b,"handler"),d={};a=a||{},b=b||{};var g=a.storage?!0:!1;d.secondstorage_spec=a.storage||{type:"base"},d.secondstorage_string=JSON.stringify(d.secondstorage_spec);var h="jio/conflictmanager/"+d.secondstorage_string+"/",i=function(){},j=c.serialized;return c.serialized=function(){var a=j();return a.storage=d.secondstorage_spec,a},c.validateState=function(){return g?"":'Need at least one parameter: "storage".'},d.getDistantMetadata=function(a,b,e,f){var g=a.cloneOption();g.metadata_only=!1,g.max_retry=a.getOption("max_retry")||3,g.error=f,g.success=e;var h=c.newCommand("loadDocument",{path:b,option:g});c.addJob(c.newStorage(d.secondstorage_spec),h)},d.saveMetadataToDistant=function(a,b,e,f,g){var h=a.cloneOption();h.error=g,h.success=f;var i=c.newCommand("saveDocument",{path:b,content:JSON.stringify(e),option:h});c.addJob(c.newStorage(d.secondstorage_spec),i)},d.saveNewRevision=function(a,b,e,f,g){var h=a.cloneOption();h.error=g,h.success=f;var i=c.newCommand("saveDocument",{path:b,content:e,option:h});c.addJob(c.newStorage(d.secondstorage_spec),i)},d.loadRevision=function(a,b,e,f){var g=a.cloneOption();g.error=f,g.success=e;var h=c.newCommand("loadDocument",{path:b,option:g});c.addJob(c.newStorage(d.secondstorage_spec),h)},d.deleteAFile=function(a,b,e,f){var g=a.cloneOption();g.max_retry=0,g.error=f,g.success=e;var h=c.newCommand("removeDocument",{path:b,option:g});c.addJob(c.newStorage(d.secondstorage_spec),h)},d.chooseARevision=function(a){var b=0,c="";for(var d in a)b<a[d].last_modified&&(b=a[d].last_modified,c=d);return c},d.solveConflict=function(a,b,c){var f={},g=d.newAsyncModule(),h=c.command,j=a+".metadata",k="",l="",m=null,n=!1,o={},p=c.deleted,q=c.previous_revision,r=c.revision_remove_object||{},s=r[q]||{},t=new Date,u;f.getDistantMetadata=function(){d.getDistantMetadata(h,j,function(c){var d=parseInt(q.split("-")[0],10);m=JSON.parse(c.content),k=d+1+"-"+e(""+b+q+JSON.stringify(m)),l=a+"."+k,p||(g.wait(f,"saveMetadataOnDistant",1),g.call(f,"saveNewRevision")),g.call(f,"previousUpdateMetadata")},function(a){g.call(f,"error",[a])})},f.saveNewRevision=function(){d.saveNewRevision(h,l,b,function(a){g.call(f,"saveMetadataOnDistant")},function(a){g.call(f,"error",[a])})},f.previousUpdateMetadata=function(){for(var a in r)delete m[a];g.call(f,"checkForConflicts")},f.checkForConflicts=function(){for(var a in m){var b;n=!0,u={status:20,statusText:"Conflict",message:"There is one or more conflicts"};break}g.call(f,"updateMetadata")},f.updateMetadata=function(){m[k]={creation_date:s.creation_date||t.getTime(),last_modified:t.getTime(),conflict:n,deleted:p},o=d.createConflictObject(h,m,k),g.call(f,"saveMetadataOnDistant")},f.saveMetadataOnDistant=function(){d.saveMetadataToDistant(h,j,m,function(a){g.call(f,"deleteAllConflictingRevision"),n?g.call(f,"error"):g.call(f,"success")},function(a){g.call(f,"error",[a])})},f.deleteAllConflictingRevision=function(){for(var b in r)d.deleteAFile(h,a+"."+b,i,i)},f.success=function(){g.neverCall(f,"error"),g.neverCall(f,"success"),c.success&&c.success({revision:k})},f.error=function(a){var b=a||u||{};n&&(b.conflict_object=o),g.neverCall(f,"error"),g.neverCall(f,"success"),c.error&&c.error(b)},g.call(f,"getDistantMetadata")},d.createConflictObject=function(a,b,c){var e=a.clone(),f={path:a.getPath(),revision:c,revision_object:b,getConflictRevisionList:function(){return this.revision_object},solveConflict:function(a,b){return typeof a=="undefined"?(b=b||{},b.deleted=!0):typeof a=="object"?(b=a,b.deleted=!0):(b=b||{},b.deleted=!1,a=a||""),b.previous_revision=this.revision,b.revision_remove_object=this.revision_object,b.command=e,d.solveConflict(this.path,a,b)}};return f},d.newAsyncModule=function(){var a={};return a.call=function(a,b,c){a._wait=a._wait||{};if(a._wait[b])return a._wait[b]--,i;c=c||[],setTimeout(function(){a[b].apply(a[b],c)})},a.neverCall=function(a,b){a._wait=a._wait||{},a._wait[b]=-1},a.wait=function(a,b,c){a._wait=a._wait||{},a._wait[b]=c},a.end=function(){a.call=i},a},c.saveDocument=function(a){var b={},f=d.newAsyncModule(),g=a.getPath()+".metadata",h="",j="",k=null,l=!1,m={},n=a.getOption("previous_revision"),o=a.getPath()+"."+n,p=new Date,q;if(!n)return setTimeout(function(){c.error({status:0,statusText:"Parameter missing",message:"Need a previous revision."})});b.getDistantMetadata=function(){d.getDistantMetadata(a,g,function(c){var d=parseInt(n.split("-")[0],10);k=JSON.parse(c.content),h=d+1+"-"+e(""+a.getContent()+n+JSON.stringify(k)),j=a.getPath()+"."+h,f.wait(b,"saveMetadataOnDistant",1),f.call(b,"saveNewRevision"),f.call(b,"checkForConflicts")},function(c){c.status===404?(h="1-"+e(a.getContent()),j=a.getPath()+"."+h,f.wait(b,"saveMetadataOnDistant",1),f.call(b,"saveNewRevision"),f.call(b,"createMetadata")):f.call(b,"error",[c])})},b.saveNewRevision=function(){d.saveNewRevision(a,j,a.getContent(),function(a){f.call(b,"saveMetadataOnDistant")},function(a){f.call(b,"error",[a])})},b.checkForConflicts=function(){for(var a in k)if(a!==n){l=!0,q={status:20,statusText:"Conflict",message:"There is one or more conflicts"};break}f.call(b,"updateMetadata")},b.createMetadata=function(){k={},k[h]={creation_date:p.getTime(),last_modified:p.getTime(),conflict:!1,deleted:!1},f.call(b,"saveMetadataOnDistant")},b.updateMetadata=function(){var c;k[n]&&(c=k[n].creation_date,delete k[n]),k[h]={creation_date:c||p.getTime(),last_modified:p.getTime(),conflict:l,deleted:!1},l&&(m=d.createConflictObject(a,k,h)),f.call(b,"saveMetadataOnDistant")},b.saveMetadataOnDistant=function(){d.saveMetadataToDistant(a,g,k,function(a){f.call(b,"deletePreviousRevision"),l?f.call(b,"error"):f.call(b,"success")},function(a){f.call(b,"error",[a])})},b.deletePreviousRevision=function(){n!=="0"&&d.deleteAFile(a,o,i,i)},b.success=function(){f.neverCall(b,"error"),f.neverCall(b,"success"),c.success({revision:h})},b.error=function(a){var d=a||q||{status:0,statusText:"Unknown",message:"Unknown error."};l&&(d.conflict_object=m),f.neverCall(b,"error"),f.neverCall(b,"success"),c.error(d)},f.call(b,"getDistantMetadata")},c.loadDocument=function(a){var b={},e=d.newAsyncModule(),f=a.getPath()+".metadata",g=a.getOption("revision")||"",h=null,i=a.getOption("metadata_only"),j=!1,k={},l=new Date,m={name:a.getPath()},n=function(a){e.call(b,"error",[{status:404,statusText:"Not Found",message:a}])};b.getDistantMetadata=function(){d.getDistantMetadata(a,f,function(a){h=JSON.parse(a.content),i||e.wait(b,"success",1),e.call(b,"affectMetadata"),e.call(b,"checkForConflicts")},function(a){e.call(b,"error",[a])})},b.affectMetadata=function(){if(g){if(!h[g])return n("Document revision does not exists.")}else g=d.chooseARevision(h);m.last_modified=h[g].last_modified,m.creation_date=h[g].creation_date,m.revision=g,m.revision_object=h,i?e.call(b,"success"):e.call(b,"loadRevision")},b.loadRevision=function(){if(!g||h[g].deleted)return n("Document has been removed.");d.loadRevision(a,m.name+"."+g,function(a){m.content=a.content,e.call(b,"success")},function(a){e.call(b,"error",[a])})},b.checkForConflicts=function(){h[g].conflict&&(j=!0,k=d.createConflictObject(a,h,g),m.conflict_object=k),e.call(b,"success")},b.success=function(){e.neverCall(b,"error"),e.neverCall(b,"success"),c.success(m)},b.error=function(a){var d=a||{status:0,statusText:"Unknown",message:"Unknown error."};j&&(d.conflict_object=k),e.neverCall(b,"error"),e.neverCall(b,"success"),c.error(d)},e.call(b,"getDistantMetadata")},c.getDocumentList=function(a){var b={},e=d.newAsyncModule(),f=a.getOption("metadata_only"),g=[],h=0,i=0,j=0;b.retreiveList=function(){var f=a.cloneOption();f.metadata_only=!0,f.error=function(a){e.call(b,"error",[a])},f.success=function(a){e.call(b,"filterTheList",[a])};var g=c.newCommand("getDocumentList",{path:a.getPath(),option:f});c.addJob(c.newStorage(d.secondstorage_spec),g)},b.filterTheList=function(a){var c;j++;for(c=0;c<a.length;c+=1){var d=a[c].name.split(".")||[];d.length>0&&d[d.length-1]==="metadata"&&(j++,d.length--,e.call(b,"loadMetadataFile",[d.join(".")]))}e.call(b,"success")},b.loadMetadataFile=function(c){d.getDistantMetadata(a,c+".metadata",function(a){a=JSON.parse(a.content);var f=d.chooseARevision(a);a[f].deleted?e.call(b,"success"):e.call(b,"loadFile",[c,f,a])},function(a){e.call(b,"error",[a])})},b.loadFile=function(c,h,i){var j={name:c,last_modified:i[h].last_modified,creation_date:i[h].creation_date,revision:h,revision_object:i};i[h].conflict&&(j.conflict_object=d.createConflictObject(a,i,h)),f?(g.push(j),e.call(b,"success")):d.loadRevision(a,c+"."+h,function(a){j.content=a.content,g.push(j),e.call(b,"success")},function(a){e.call(b,"error",[a])})},b.success=function(){i++,i>=j&&(e.end(),c.success(g))},b.error=function(a){e.end(),c.error(a)},e.call(b,"retreiveList")},c.removeDocument=function(a){var b={},f=d.newAsyncModule(),g=a.getPath()+".metadata",h="",j="",k=null,l=!1,m={},n=a.getOption("revision"),o=a.getPath()+"."+n,p=new Date,q;if(!n)return setTimeout(function(){c.error({status:0,statusText:"Parameter missing",message:"Need a revision."})});b.getDistantMetadata=function(){d.getDistantMetadata(a,g,function(c){k=JSON.parse(c.content),n==="last"&&(n=d.chooseARevision(k),o=a.getPath()+"."+n);var g=parseInt(n.split("-")[0],10);h=g+1+"-"+e(""+n+JSON.stringify(k)),j=a.getPath()+"."+h,f.call(b,"checkForConflicts")},function(a){a.status===404?f.call(b,"success",["0"]):f.call(b,"error",[a])})},b.checkForConflicts=function(){for(var a in k)if(a!==n){l=!0,q={status:20,statusText:"Conflict",message:"There is one or more conflicts"};break}f.call(b,"updateMetadata")},b.updateMetadata=function(){var c;k[n]&&(c=k[n].creation_date,delete k[n]),k[h]={creation_date:c||p.getTime(),last_modified:p.getTime(),conflict:l,deleted:!0},l&&(m=d.createConflictObject(a,k,h)),f.call(b,"saveMetadataOnDistant")},b.saveMetadataOnDistant=function(){d.saveMetadataToDistant(a,g,k,function(a){f.call(b,"deletePreviousRevision"),l?f.call(b,"error"):f.call(b,"success")},function(a){f.call(b,"error",[a])})},b.deletePreviousRevision=function(){n!=="0"&&d.deleteAFile(a,o,i,i)},b.success=function(a){f.neverCall(b,"error"),f.neverCall(b,"success"),c.success({revision:a||h})},b.error=function(a){var d=a||q||{status:0,statusText:"Unknown",message:"Unknown error."};l&&(d.conflict_object=m),f.neverCall(b,"error"),f.neverCall(b,"success"),c.error(d)},f.call(b,"getDistantMetadata")},c};f.addStorageType("conflictmanager",l)})(LocalOrCookieStorage,jQuery,Base64,sjcl,hex_sha256,jio); (function(a,b,c,d,e,f){var g=function(b,c){var d=f.storage(b,c,"base"),e={};e.secureDocId=function(a){var b=a.split("/"),c;b[0]===""&&(b=b.slice(1));for(c=0;c<b.length;c+=1)if(b[c]==="")return"";return b.join("%2F")},e.convertSlashes=function(a){return a.split("/").join("%2F")},e.restoreSlashes=function(a){return a.split("%2F").join("/")},e.username=b.username||"",e.secured_username=e.convertSlashes(e.username),e.applicationname=b.applicationname||"untitled",e.secured_applicationname=e.convertSlashes(e.applicationname);var g="jio/local_user_array",h="jio/local_file_name_array/"+e.secured_username+"/"+e.secured_applicationname,i=d.serialized;return d.serialized=function(){var a=i();return a.applicationname=e.applicationname,a.username=e.username,a},d.validateState=function(){return e.secured_username?"":'Need at least one parameter: "username".'},e.getUserArray=function(){return a.getItem(g)||[]},e.addUser=function(b){var c=e.getUserArray();c.push(b),a.setItem(g,c)},e.userExists=function(a){var b=e.getUserArray(),c,d;for(c=0,d=b.length;c<d;c+=1)if(b[c]===a)return!0;return!1},e.getFileNameArray=function(){return a.getItem(h)||[]},e.addFileName=function(b){var c=e.getFileNameArray();c.push(b),a.setItem(h,c)},e.removeFileName=function(b){var c,d,f=e.getFileNameArray(),g=[];for(c=0,d=f.length;c<d;c+=1)f[c]!==b&&g.push(f[c]);a.setItem(h,g)},e.checkSecuredDocId=function(a,b,c){return a?!0:(d.error({status:403,statusText:"Method Not Allowed",error:"method_not_allowed",message:"Cannot "+c+' "'+b+'", file name is incorrect.',reason:"Cannot "+c+' "'+b+'", file name is incorrect'}),!1)},d.post=function(a){d.put(a)},d.put=function(b){setTimeout(function(){var c=e.secureDocId(b.getDocId()),f=null,g="jio/local/"+e.secured_username+"/"+e.secured_applicationname+"/"+c;if(!e.checkSecuredDocId(c,b.getDocId(),"put"))return;f=a.getItem(g),f?(f.content=b.getDocContent(),f._last_modified=Date.now()):(f={_id:b.getDocId(),content:b.getDocContent(),_creation_date:Date.now(),_last_modified:Date.now()},e.userExists(e.secured_username)||e.addUser(e.secured_username),e.addFileName(c)),a.setItem(g,f),d.success({ok:!0,id:b.getDocId()})})},d.get=function(b){setTimeout(function(){var c=e.secureDocId(b.getDocId()),f=null;if(!e.checkSecuredDocId(c,b.getDocId(),"get"))return;f=a.getItem("jio/local/"+e.secured_username+"/"+e.secured_applicationname+"/"+c),f?(b.getOption("metadata_only")&&delete f.content,d.success(f)):d.error({status:404,statusText:"Not Found.",error:"not_found",message:'Document "'+b.getDocId()+'" not found.',reason:"missing"})})},d.allDocs=function(b){setTimeout(function(){var c=[],f=[],g,h,i="key",j="jio/local/"+e.secured_username+"/"+e.secured_applicationname,k={};f=e.getFileNameArray();for(g=0,h=f.length;g<h;g+=1)k=a.getItem(j+"/"+f[g]),k&&(b.getOption("metadata_only")?c.push({id:k._id,key:k._id,value:{_creation_date:k._creation_date,_last_modified:k._last_modified}}):c.push({id:k._id,key:k._id,value:{content:k.content,_creation_date:k._creation_date,_last_modified:k._last_modified}}));d.success({total_rows:c.length,rows:c})})},d.remove=function(b){setTimeout(function(){var c=e.secureDocId(b.getDocId()),f="jio/local/"+e.secured_username+"/"+e.secured_applicationname+"/"+c;if(!e.checkSecuredDocId(c,b.getDocId(),"remove"))return;a.deleteItem(f),e.removeFileName(c),d.success({ok:!0,id:b.getDocId()})})},d};f.addStorageType("local",g);var h=function(a,d){var e=f.storage(a,d,"base"),g={};g.secureDocId=function(a){var b=a.split("/"),c;b[0]===""&&(b=b.slice(1));for(c=0;c<b.length;c+=1)if(b[c]==="")return"";return b.join("%2F")},g.convertSlashes=function(a){return a.split("/").join("%2F")},g.restoreSlashes=function(a){return a.split("%2F").join("/")},g.username=a.username||"",g.secured_username=g.convertSlashes(g.username),g.applicationname=a.applicationname||"untitled",g.secured_applicationname=g.convertSlashes(g.applicationname),g.url=a.url||"",g.password=a.password||"";var h=e.serialized;return e.serialized=function(){var a=h();return a.username=g.username,a.applicationname=g.applicationname,a.url=g.url,a.password=g.password,a},e.validateState=function(){return g.secured_username&&g.url?"":'Need at least 2 parameters: "username" and "url".'},g.newAsyncModule=function(){var a={};return a.call=function(a,b,c){return a._wait=a._wait||{},a._wait[b]?(a._wait[b]--,function(){}):(c=c||[],a[b].apply(a[b],c))},a.neverCall=function(a,b){a._wait=a._wait||{},a._wait[b]=-1},a.wait=function(a,b,c){a._wait=a._wait||{},a._wait[b]=c},a.end=function(){a.call=function(){}},a},e.post=function(a){e.put(a)},e.put=function(a){var d=g.secureDocId(a.getDocId());b.ajax({url:g.url+"/"+g.secured_username+"/"+g.secured_applicationname+"/"+d,type:"PUT",data:a.getDocContent(),async:!0,dataType:"text",headers:{Authorization:"Basic "+c.encode(g.username+":"+g.password)},success:function(){e.success({ok:!0,id:a.getDocId()})},error:function(b){b.error=b.statusText,b.reason='Cannot save "'+a.getDocId()+'"',b.message=b.reason+".",e.retry(b)}})},e.get=function(a){var d=g.secureDocId(a.getDocId()),f={},h=function(){b.ajax({url:g.url+"/"+g.secured_username+"/"+g.secured_applicationname+"/"+d,type:"GET",async:!0,dataType:"text",headers:{Authorization:"Basic "+c.encode(g.username+":"+g.password)},success:function(a){f.content=a,e.success(f)},error:function(b){b.error=b.statusText,b.status===404?(b.message='Document "'+a.getDocId()+'" not found.',b.reason="missing",e.error(b)):(b.reason='An error occured when trying to get "'+a.getDocId()+'"',b.message=b.reason+".",e.retry(b))}})};f._id=a.getDocId(),b.ajax({url:g.url+"/"+g.secured_username+"/"+g.secured_applicationname+"/"+d,type:"PROPFIND",async:!0,dataType:"xml",headers:{Authorization:"Basic "+c.encode(g.username+":"+g.password)},success:function(c){b(c).find("lp1\\:getlastmodified, getlastmodified").each(function(){f._last_modified=(new Date(b(this).text())).getTime()}),b(c).find("lp1\\:creationdate, creationdate").each(function(){f._creation_date=(new Date(b(this).text())).getTime()}),a.getOption("metadata_only")?e.success(f):h()},error:function(b){b.status===404?(b.message='Cannot find "'+a.getDocId()+'" informations.',b.reason="missing",e.error(b)):(b.reason='Cannot get "'+a.getDocId()+'" informations',b.message=b.reason+".",e.retry(b))}})},e.allDocs=function(a){var d=[],f=g.newAsyncModule(),h={};h.getContent=function(a){b.ajax({url:g.url+"/"+g.secured_username+"/"+g.secured_applicationname+"/"+g.secureDocId(a.id),type:"GET",async:!0,dataType:"text",headers:{Authorization:"Basic "+c.encode(g.username+":"+g.password)},success:function(b){a.value.content=b,d.push(a),f.call(h,"success")},error:function(a){a.error=a.statusText,a.reason="Cannot get a document content from DAVStorage",a.message=a.message+".",f.call(h,"error",[a])}})},h.getDocumentList=function(){b.ajax({url:g.url+"/"+g.secured_username+"/"+g.secured_applicationname+"/",async:!0,type:"PROPFIND",dataType:"xml",headers:{Authorization:"Basic "+c.encode(g.username+":"+g.password),Depth:"1"},success:function(c){var e=b(c).find("D\\:response, response"),i=e.length;if(i===1)return f.call(h,"success");f.wait(h,"success",i-2),e.each(function(c,e){if(c>0){var i={value:{}};b(e).find("D\\:href, href").each(function(){var a=b(this).text().split("/");i.id=a[a.length-1],i.id=g.restoreSlashes(i.id),i.key=i.id});if(i.id===".htaccess"||i.id===".htpasswd")return;b(e).find("lp1\\:getlastmodified, getlastmodified").each(function(){i.value._last_modified=(new Date(b(this).text())).getTime()}),b(e).find("lp1\\:creationdate, creationdate").each(function(){i.value._creation_date=(new Date(b(this).text())).getTime()}),a.getOption("metadata_only")?(d.push(i),f.call(h,"success")):f.call(h,"getContent",[i])}})},error:function(a){a.status===404?(a.error="not_found",a.reason="missing",f.call(h,"error",[a])):(a.error=a.statusText,a.reason="Cannot get a document list from DAVStorage",a.message=a.reason+".",f.call(h,"retry",[a]))}})},h.retry=function(a){f.neverCall(h,"retry"),f.neverCall(h,"success"),f.neverCall(h,"error"),e.retry(a)},h.error=function(a){f.neverCall(h,"retry"),f.neverCall(h,"success"),f.neverCall(h,"error"),e.error(a)},h.success=function(){f.neverCall(h,"retry"),f.neverCall(h,"success"),f.neverCall(h,"error"),e.success({total_rows:d.length,rows:d})},f.call(h,"getDocumentList")},e.remove=function(a){var d=g.secureDocId(a.getDocId());b.ajax({url:g.url+"/"+g.secured_username+"/"+g.secured_applicationname+"/"+d,type:"DELETE",async:!0,headers:{Authorization:"Basic "+c.encode(g.username+":"+g.password)},success:function(b,c,d){e.success({ok:!0,id:a.getDocId()})},error:function(a,b,c){a.status===404?(a.error="not_found",a.reason="missing",a.message="Cannot remove missing file.",e.error(a)):(a.reason='Cannot remove "'+e.getDocId()+'"',a.message=a.reason+".",e.retry(a))}})},e};f.addStorageType("dav",h);var i=function(a,b){var c=f.storage(a,b,"handler"),d={};d.return_value_array=[],d.storagelist=a.storagelist||[],d.nb_storage=d.storagelist.length;var e=c.serialized;return c.serialized=function(){var a=e();return a.storagelist=d.storagelist,a},c.validateState=function(){return d.storagelist.length===0?'Need at least one parameter: "storagelist" containing at least one storage.':""},d.isTheLast=function(a){return a.length===d.nb_storage},d.doJob=function(a,b,e){var f=!1,g=[],h,i=function(h){f||(g.push(h),d.isTheLast(g)&&c.error({status:207,statusText:"Multi-Status",error:"multi_status",message:"All "+b+(e?" ":' "'+a.getDocId()+'"')+" requests have failed.",reason:"requests fail",array:g}))},j=function(a){f||(f=!0,c.success(a))};for(h=0;h<d.nb_storage;h+=1){var k=a.cloneOption();c.addJob(a.getLabel(),d.storagelist[h],a.cloneDoc(),k,j,i)}},c.post=function(a){d.doJob(a,"post"),c.end()},c.put=function(a){d.doJob(a,"put"),c.end()},c.get=function(a){d.doJob(a,"get"),c.end()},c.allDocs=function(a){d.doJob(a,"allDocs",!0),c.end()},c.remove=function(a){d.doJob(a,"remove"),c.end()},c};f.addStorageType("replicate",i);var j=function(b,c){var d=f.storage(b,c,"handler"),e={},g=b.storage||!1;e.secondstorage_spec=b.storage||{type:"base"},e.secondstorage_string=JSON.stringify(e.secondstorage_spec);var h="jio/indexed_storage_object",i="jio/indexed_file_object/"+e.secondstorage_string,j=d.serialized;return d.serialized=function(){var a=j();return a.storage=e.secondstorage_spec,a},d.validateState=function(){return g?"":'Need at least one parameter: "storage" containing storage specifications.'},e.secureDocId=function(a){var b=a.split("/"),c;b[0]===""&&(b=b.slice(1));for(c=0;c<b.length;c+=1)if(b[c]==="")return"";return b.join("%2F")},e.indexStorage=function(){var b=a.getItem(h)||{};b[e.secondstorage_spec]=(new Date).getTime(),a.setItem(h,b)},e.formatToFileObject=function(a){var b,c={_id:a.id};for(b in a.value)c[b]=a.value[b];return c},e.allDocs=function(a){var b,c={rows:[]},d=0;for(b in a)c.rows[d]={},c.rows[d].value=a[b],c.rows[d].id=c.rows[d].key=c.rows[d].value._id,delete c.rows[d].value._id,d++;return c.total_rows=c.rows.length,c},e.setFileArray=function(b){var c,d={};for(c=0;c<b.length;c+=1)d[b[c].id]=e.formatToFileObject(b[c]);a.setItem(i,d)},e.getFileObject=function(b){var c=a.getItem(i)||{};return c[b]},e.addFile=function(b){var c=a.getItem(i)||{};c[b._id]=b,a.setItem(i,c)},e.removeFile=function(b){var c=a.getItem(i)||{};delete c[b],a.setItem(i,c)},e.update=function(){var a=function(a){e.setFileArray(a.rows)};d.addJob("allDocs",e.secondstorage_spec,null,{max_retry:3},a,function(){})},d.post=function(a){d.put(a)},d.put=function(a){var b=a.cloneDoc(),c=a.cloneOption(),f=function(a){e.update(),d.success(a)},g=function(a){d.error(a)};e.indexStorage(),d.addJob("put",e.secondstorage_spec,b,c,f,g)},d.get=function(a){var b,c=function(a){d.success(a)},f=function(a){d.error(a)},g=function(){var b=a.cloneOption();d.addJob("get",e.secondstorage_spec,a.cloneDoc(),b,c,f),d.end()};e.indexStorage(),e.update(),a.getOption("metadata_only")?setTimeout(function(){var b=e.getFileObject(a.getDocId());b&&(b._last_modified||b._creation_date)?d.success(b):g()}):g()},d.allDocs=function(b){var c=a.getItem(i);if(c)e.update(),setTimeout(function(){d.success(e.allDocs(c))});else{var f=function(a){e.setFileArray(a.rows),d.success(a)},g=function(a){d.error(a)};d.addJob("allDocs",e.secondstorage_spec,null,b.cloneOption(),f,g)}},d.remove=function(a){var b=function(b){e.removeFile(a.getDocId()),e.update(),d.success(b)},c=function(a){d.error(a)};d.addJob("remove",e.secondstorage_spec,a.cloneDoc(),a.cloneOption(),b,c)},d};f.addStorageType("indexed",j);var k=function(a,c){var e=f.storage(a,c,"handler"),g={},h=a.storage?!0:!1;g.username=a.username||"",g.password=a.password||"",g.secondstorage_spec=a.storage||{type:"base"},g.secondstorage_string=JSON.stringify(g.secondstorage_string);var i=e.serialized;return e.serialized=function(){var a=i();return a.username=g.username,a.password=g.password,a.storage=g.secondstorage_string,a},e.validateState=function(){return g.username&&h?"":'Need at least two parameters: "username" and "storage".'},g.encrypt_param_object={iv:"kaprWwY/Ucr7pumXoTHbpA",v:1,iter:1e3,ks:256,ts:128,mode:"ccm",adata:"",cipher:"aes",salt:"K4bmZG9d704"},g.decrypt_param_object={iv:"kaprWwY/Ucr7pumXoTHbpA",ks:256,ts:128,salt:"K4bmZG9d704"},g.encrypt=function(a,b){var c=d.encrypt(g.username+":"+g.password,a,g.encrypt_param_object);b(JSON.parse(c).ct)},g.decrypt=function(a,c){var e,f=b.extend(!0,{},g.decrypt_param_object);f.ct=a||"",f=JSON.stringify(f);try{e=d.decrypt(g.username+":"+g.password,f)}catch(h){c({status:403,statusText:"Forbidden",error:"forbidden",message:"Unable to decrypt.",reason:"unable to decrypt"});return}c(undefined,e)},g.newAsyncModule=function(){var a={};return a.call=function(a,b,c){a._wait=a._wait||{};if(a._wait[b])return a._wait[b]--,function(){};c=c||[],setTimeout(function(){a[b].apply(a[b],c)})},a.neverCall=function(a,b){a._wait=a._wait||{},a._wait[b]=-1},a.wait=function(a,b,c){a._wait=a._wait||{},a._wait[b]=c},a.end=function(){a.call=function(){}},a},e.post=function(a){e.put(a)},e.put=function(a){var b,c,d=g.newAsyncModule(),f={};f.encryptFilePath=function(){g.encrypt(a.getDocId(),function(a){b=a,d.call(f,"save")})},f.encryptFileContent=function(){g.encrypt(a.getDocContent(),function(a){c=a,d.call(f,"save")})},f.save=function(){var d=function(b){b.id=a.getDocId(),e.success(b)},f=function(a){e.error(a)},h=a.cloneDoc();h._id=b,h.content=c,e.addJob("put",g.secondstorage_spec,h,a.cloneOption(),d,f)},d.wait(f,"save",1),d.call(f,"encryptFilePath"),d.call(f,"encryptFileContent")},e.get=function(a){var b,c,d=g.newAsyncModule(),f={};f.encryptFilePath=function(){g.encrypt(a.getDocId(),function(a){b=a,d.call(f,"get")})},f.get=function(){e.addJob("get",g.secondstorage_spec,b,a.cloneOption(),f.success,f.error)},f.success=function(b){b._id=a.getDocId(),a.getOption("metadata_only")?e.success(b):g.decrypt(b.content,function(a,c){a?e.error(a):(b.content=c,e.success(b))})},f.error=function(a){e.error(a)},d.call(f,"encryptFilePath")},e.allDocs=function(a){var b=[],c=g.newAsyncModule(),d={};d.allDocs=function(){e.addJob("allDocs",g.secondstorage_spec,null,a.cloneOption(),d.onSuccess,d.error)},d.onSuccess=function(e){if(e.total_rows===0)return c.call(d,"success");b=e.rows;var f,h=function(e){g.decrypt(b[e].id,function(a,f){a?c.call(d,"error",[a]):(b[e].id=f,b[e].key=f,c.call(d,"success"))}),a.getOption("metadata_only")||g.decrypt(b[e].value.content,function(a,f){a?c.call(d,"error",[a]):(b[e].value.content=f,c.call(d,"success"))})};a.getOption("metadata_only")?c.wait(d,"success",e.total_rows*1-1):c.wait(d,"success",e.total_rows*2-1);for(f=0;f<b.length;f+=1)h(f)},d.error=function(a){c.end(),e.error(a)},d.success=function(){c.end(),e.success({total_rows:b.length,rows:b})},c.call(d,"allDocs")},e.remove=function(a){var b,c={};c.encryptDocId=function(){g.encrypt(a.getDocId(),function(a){b=a,c.removeDocument()})},c.removeDocument=function(){var d=a.cloneDoc();d._id=b,e.addJob("remove",g.secondstorage_spec,d,a.cloneOption(),c.success,e.error)},c.success=function(b){b.id=a.getDocId(),e.success(b)},c.encryptDocId()},e};f.addStorageType("crypt",k);var l=function(a,b){var c=f.storage(a,b,"handler"),d={};a=a||{},b=b||{};var g=a.storage?!0:!1;d.secondstorage_spec=a.storage||{type:"base"},d.secondstorage_string=JSON.stringify(d.secondstorage_spec);var h="jio/conflictmanager/"+d.secondstorage_string+"/",i=function(){},j=c.serialized;return c.serialized=function(){var a=j();return a.storage=d.secondstorage_spec,a},c.validateState=function(){return g?"":'Need at least one parameter: "storage".'},d.getDistantMetadata=function(a,b,e,f){var g=a.cloneOption();g.metadata_only=!1,g.max_retry=a.getOption("max_retry")||3,c.addJob("get",d.secondstorage_spec,b,g,e,f)},d.saveMetadataToDistant=function(a,b,e,f,g){c.addJob("put",d.secondstorage_spec,{_id:b,content:JSON.stringify(e)},a.cloneOption(),f,g)},d.saveNewRevision=function(a,b,e,f,g){c.addJob("put",d.secondstorage_spec,{_id:b,content:e},a.cloneOption(),f,g)},d.loadRevision=function(a,b,e,f){c.addJob("get",d.secondstorage_spec,b,a.cloneOption(),e,f)},d.deleteAFile=function(a,b,e,f){var g=a.cloneOption();g.max_retry=0,c.addJob("remove",d.secondstorage_spec,{_id:b},a.cloneOption(),e,f)},d.chooseARevision=function(a){var b=0,c="",d;for(d in a)b<a[d]._last_modified&&(b=a[d]._last_modified,c=d);return c},d._revs=function(a,b){return a[b]?{start:a[b]._revisions.length,ids:a[b]._revisions}:null},d._revs_info=function(a){var b,c=[];for(b in a)c.push({rev:b,status:a[b]?a[b]._deleted?"deleted":"available":"missing"});return c},d.solveConflict=function(a,b,c){var f={},g=d.newAsyncModule(),h=c.command,j=c.docid+".metadata",k="",l="",m=null,n=!1,o={total_rows:0,rows:[]},p=c._deleted,q=c.previous_revision,r=null,s=new Date,t;f.getDistantMetadata=function(){d.getDistantMetadata(h,j,function(b){var d=parseInt(q.split("-")[0],10);m=JSON.parse(b.content),k=d+1+"-"+e(""+a.content+q+JSON.stringify(m)),l=c.docid+"."+k,r=m[q]||{},p||(g.wait(f,"saveMetadataOnDistant",1),g.call(f,"saveNewRevision")),g.call(f,"previousUpdateMetadata")},function(a){g.call(f,"error",[a])})},f.saveNewRevision=function(){d.saveNewRevision(h,l,a.content,function(a){g.call(f,"saveMetadataOnDistant")},function(a){g.call(f,"error",[a])})},f.previousUpdateMetadata=function(){var a;for(a=0;a<c.key.length;a+=1)delete m[c.key[a]];g.call(f,"checkForConflicts")},f.checkForConflicts=function(){var a;for(a in m){var b;n=!0,t={status:409,error:"conflict",statusText:"Conflict",reason:"document update conflict",message:"There is one or more conflicts"};break}g.call(f,"updateMetadata")},f.updateMetadata=function(){var a,b="";b=k.split("-"),b.shift(),b=b.join("-"),a=r._revisions,a.unshift(b),m[k]={_creation_date:r._creation_date||s.getTime(),_last_modified:s.getTime(),_revisions:a,_conflict:n,_deleted:p},n&&(o=d.createConflictObject(h,m,k)),g.call(f,"saveMetadataOnDistant")},f.saveMetadataOnDistant=function(){d.saveMetadataToDistant(h,j,m,function(a){g.call(f,"deleteAllConflictingRevision"),n?g.call(f,"error"):g.call(f,"success")},function(a){g.call(f,"error",[a])})},f.deleteAllConflictingRevision=function(){var a;for(a=0;a<c.key.length;a+=1)d.deleteAFile(h,c.docid+"."+c.key[a],i,i)},f.success=function(){var a={ok:!0,id:c.docid,rev:k};g.neverCall(f,"error"),g.neverCall(f,"success"),b.revs&&(a.revisions=d._revs(m,k)),b.revs_info&&(a.revs_info=d._revs_info(m)),b.conflicts&&(a.conflicts=o),c.success(a)},f.error=function(a){var e=a||t||{status:0,statusText:"Unknown",error:"unknown_error",message:"Unknown error.",reason:"unknown error"};k&&(e.rev=k),b.revs&&(e.revisions=d._revs(m,k)),b.revs_info&&(e.revs_info=d._revs_info(m)),b.conflicts&&(e.conflicts=o),g.neverCall(f,"error"),g.neverCall(f,"success"),c.error(e)},g.call(f,"getDistantMetadata")},d.createConflictObject=function(a,b,c){return{total_rows:1,rows:[d.createConflictRow(a,a.getDocId(),b,c)]}},d.getParam=function(a){var b={},c=0;return typeof a[c]=="string"&&(b.content=a[c],c++),typeof a[c]=="object"?(b.options=a[c],c++):b.options={},b.callback=function(a,b){},b.success=function(a){b.callback(undefined,a)},b.error=function(a){b.callback(a,undefined)},typeof a[c]=="function"&&(typeof a[c+1]=="function"?(b.success=a[c],b.error=a[c+1]):b.callback=a[c]),b},d.createConflictRow=function(a,b,c,e){var f={id:b,key:[],value:{_solveConflict:function(){var c={},g=d.getParam(arguments);return g.content===undefined?c._deleted=!0:c._deleted=!1,c.success=g.success,c.error=g.error,c.previous_revision=e,c.docid=b,c.key=f.key,c.command=a.clone(),d.solveConflict({_id:b,content:g.content,_rev:e},g.options,c)}}},g;for(g in c)f.key.push(g);return f},d.newAsyncModule=function(){var a={};return a.call=function(a,b,c){a._wait=a._wait||{};if(a._wait[b])return a._wait[b]--,i;c=c||[],setTimeout(function(){a[b].apply(a[b],c)})},a.neverCall=function(a,b){a._wait=a._wait||{},a._wait[b]=-1},a.wait=function(a,b,c){a._wait=a._wait||{},a._wait[b]=c},a.end=function(){a.call=i},a},c.post=function(a){c.put(a)},c.put=function(a){var b={},f=d.newAsyncModule(),g=a.getDocId()+".metadata",h="",j="",k=null,l=!1,m={total_rows:0,rows:[]},n=a.getDocInfo("_rev")||"0",o=a.getDocId()+"."+n,p=new Date,q;b.getDistantMetadata=function(){d.getDistantMetadata(a,g,function(c){var d=parseInt(n.split("-")[0],10);k=JSON.parse(c.content),h=d+1+"-"+e(""+a.getDocContent()+n+JSON.stringify(k)),j=a.getDocId()+"."+h,f.wait(b,"saveMetadataOnDistant",1),f.call(b,"saveNewRevision"),f.call(b,"checkForConflicts")},function(c){c.status===404?(h="1-"+e(a.getDocContent()),j=a.getDocId()+"."+h,f.wait(b,"saveMetadataOnDistant",1),f.call(b,"saveNewRevision"),f.call(b,"createMetadata")):f.call(b,"error",[c])})},b.saveNewRevision=function(){d.saveNewRevision(a,j,a.getDocContent(),function(a){f.call(b,"saveMetadataOnDistant")},function(a){f.call(b,"error",[a])})},b.checkForConflicts=function(){var a;for(a in k)if(a!==n){l=!0,q={status:409,error:"conflict",statusText:"Conflict",reason:"document update conflict",message:"Document update conflict."};break}f.call(b,"updateMetadata")},b.createMetadata=function(){var a=h;a=a.split("-"),a.shift(),a=a.join("-"),k={},k[h]={_creation_date:p.getTime(),_last_modified:p.getTime(),_revisions:[a],_conflict:!1,_deleted:!1},f.call(b,"saveMetadataOnDistant")},b.updateMetadata=function(){var c,e=[],g="";k[n]&&(c=k[n]._creation_date,e=k[n]._revisions,delete k[n]),g=h.split("-"),g.shift(),g=g.join("-"),e.unshift(g),k[h]={_creation_date:c||p.getTime(),_last_modified:p.getTime(),_revisions:e,_conflict:l,_deleted:!1},l&&(m=d.createConflictObject(a,k,h)),f.call(b,"saveMetadataOnDistant")},b.saveMetadataOnDistant=function(){d.saveMetadataToDistant(a,g,k,function(a){f.call(b,"deletePreviousRevision"),l?f.call(b,"error"):f.call(b,"success")},function(a){f.call(b,"error",[a])})},b.deletePreviousRevision=function(){n!=="0"&&d.deleteAFile(a,o,i,i)},b.success=function(){var e={ok:!0,id:a.getDocId(),rev:h};f.neverCall(b,"error"),f.neverCall(b,"success"),a.getOption("revs")&&(e.revisions=d._revs(k,h)),a.getOption("revs_info")&&(e.revs_info=d._revs_info(k)),a.getOption("conflicts")&&(e.conflicts=m),c.success(e)},b.error=function(e){var g=e||q||{status:0,statusText:"Unknown",error:"unknown_error",message:"Unknown error.",reason:"unknown error"};h&&(g.rev=h),a.getOption("revs")&&(g.revisions=d._revs(k,h)),a.getOption("revs_info")&&(g.revs_info=d._revs_info(k)),a.getOption("conflicts")&&(g.conflicts=m),f.neverCall(b,"error"),f.neverCall(b,"success"),c.error(g)},f.call(b,"getDistantMetadata")},c.get=function(a){var b={},e=d.newAsyncModule(),f=a.getDocId()+".metadata",g=a.getOption("rev")||"",h=null,i=a.getOption("metadata_only"),j=!1,k={total_rows:0,rows:[]},l=new Date,m={_id:a.getDocId()},n=function(a){e.call(b,"error",[{status:404,statusText:"Not Found",error:"not_found",message:a,reason:a}])};b.getDistantMetadata=function(){d.getDistantMetadata(a,f,function(a){h=JSON.parse(a.content),i||e.wait(b,"success",1),e.call(b,"affectMetadata"),e.call(b,"checkForConflicts")},function(a){e.call(b,"error",[a])})},b.affectMetadata=function(){if(g){if(!h[g])return n("Document revision does not exists.")}else g=d.chooseARevision(h);m._last_modified=h[g]._last_modified,m._creation_date=h[g]._creation_date,m._rev=g,a.getOption("revs")&&(m._revisions=d._revs(h,g)),a.getOption("revs_info")&&(m._revs_info=d._revs_info(h)),i?e.call(b,"success"):e.call(b,"loadRevision")},b.loadRevision=function(){if(!g||h[g]._deleted)return n("Document has been removed.");d.loadRevision(a,m._id+"."+g,function(a){m.content=a.content,e.call(b,"success")},function(a){e.call(b,"error",[a])})},b.checkForConflicts=function(){h[g].conflict&&(j=!0,k=d.createConflictObject(a,h,g)),a.getOption("conflicts")&&(m._conflicts=k),e.call(b,"success")},b.success=function(){e.neverCall(b,"error"),e.neverCall(b,"success"),c.success(m)},b.error=function(a){var d=a||{status:0,statusText:"Unknown",message:"Unknown error."};j&&(d.conflict_object=k),e.neverCall(b,"error"),e.neverCall(b,"success"),c.error(d)},e.call(b,"getDistantMetadata")},c.allDocs=function(a){var b={},e=d.newAsyncModule(),f=a.getOption("metadata_only"),g=[],h=0,i=0,j=0;b.retreiveList=function(){var f=a.cloneOption(),g=function(a){e.call(b,"filterTheList",[a])},h=function(a){e.call(b,"error",[a])};f.metadata_only=!0,c.addJob("allDocs",d.secondstorage_spec,null,f,g,h)},b.filterTheList=function(a){var c;j++;for(c=0;c<a.total_rows;c+=1){var d=a.rows[c].id.split(".")||[];d.length>0&&d[d.length-1]==="metadata"&&(j++,d.length--,e.call(b,"loadMetadataFile",[d.join(".")]))}e.call(b,"success")},b.loadMetadataFile=function(c){d.getDistantMetadata(a,c+".metadata",function(a){a=JSON.parse(a.content);var f=d.chooseARevision(a);a[f]._deleted?e.call(b,"success"):e.call(b,"loadFile",[c,f,a])},function(a){e.call(b,"error",[a])})},b.loadFile=function(c,h,i){var j={id:c,key:c,value:{_last_modified:i[h]._last_modified,_creation_date:i[h]._creation_date,_rev:h}};a.getOption("revs_info")&&(j.value._revs_info=d._revs_info(i,h)),a.getOption("conflicts")&&(i[h]._conflict?j.value._conflicts=d.createConflictObject(a,i,h):j.value._conflicts={total_rows:0,rows:[]}),f?(g.push(j),e.call(b,"success")):d.loadRevision(a,c+"."+h,function(a){j.content=a.content,g.push(j),e.call(b,"success")},function(a){e.call(b,"error",[a])})},b.success=function(){i++,i>=j&&(e.end(),c.success({total_rows:g.length,rows:g}))},b.error=function(a){e.end(),c.error(a)},e.call(b,"retreiveList")},c.remove=function(a){var b={},f=d.newAsyncModule(),g=a.getDocId()+".metadata",h="",j="",k=null,l=!1,m={total_rows:0,rows:[]},n=a.getOption("rev")||"0",o=a.getDocId()+"."+n,p=new Date,q;b.getDistantMetadata=function(){d.getDistantMetadata(a,g,function(c){k=JSON.parse(c.content),n==="last"&&(n=d.chooseARevision(k),o=a.getDocId()+"."+n);var g=parseInt(n.split("-")[0],10)||0;h=g+1+"-"+e(""+n+JSON.stringify(k)),j=a.getDocId()+"."+h,f.call(b,"checkForConflicts")},function(a){a.status===404?f.call(b,"error",[{status:404,statusText:"Not Found",error:"not_found",reason:"missing",message:"Document not found."}]):f.call(b,"error",[a])})},b.checkForConflicts=function(){var a;for(a in k)if(a!==n){l=!0,q={status:409,error:"conflict",statusText:"Conflict",reason:"document update conflict",message:"There is one or more conflicts"};break}f.call(b,"updateMetadata")},b.updateMetadata=function(){var c,e=[],g="";k[n]&&(c=k[n]._creation_date,e=k[n]._revisions,delete k[n]),g=h,g=g.split("-"),g.shift(),g=g.join("-"),e.unshift(g),k[h]={_creation_date:c||p.getTime(),_last_modified:p.getTime(),_revisions:e,_conflict:l,_deleted:!0},l&&(m=d.createConflictObject(a,k,h)),f.call(b,"saveMetadataOnDistant")},b.saveMetadataOnDistant=function(){d.saveMetadataToDistant(a,g,k,function(a){f.call(b,"deletePreviousRevision"),l?f.call(b,"error"):f.call(b,"success")},function(a){f.call(b,"error",[a])})},b.deletePreviousRevision=function(){n!=="0"&&d.deleteAFile(a,o,i,i)},b.success=function(e){var g={ok:!0,id:a.getDocId(),rev:e||h};f.neverCall(b,"error"),f.neverCall(b,"success"),a.getOption("revs")&&(g.revisions=d._revs(k,h)),a.getOption("revs_info")&&(g.revs_info=d._revs_info(k)),a.getOption("conflicts")&&(g.conflicts=m),c.success(g)},b.error=function(e){var g=e||q||{status:0,statusText:"Unknown",error:"unknown_error",message:"Unknown error.",reason:"unknown error"};h&&(g.rev=h),a.getOption("revs")&&(g.revisions=d._revs(k,h)),a.getOption("revs_info")&&(g.revs_info=d._revs_info(k)),a.getOption("conflicts")&&(g.conflicts=m),f.neverCall(b,"error"),f.neverCall(b,"success"),c.error(g)},f.call(b,"getDistantMetadata")},c};f.addStorageType("conflictmanager",l)})(LocalOrCookieStorage,jQuery,Base64,sjcl,hex_sha256,jio);
\ No newline at end of file \ No newline at end of file
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