Commit 90d37ed6 authored by Sven Franck's avatar Sven Franck

PUTATTACHEMENT working, removed methods to util

parent eca94a2a
...@@ -19,14 +19,14 @@ var utilities = { ...@@ -19,14 +19,14 @@ var utilities = {
isObjectEmpty : function(obj) { isObjectEmpty : function(obj) {
var key; var key;
if (obj.length && obj.length > 0){ if (obj.length && obj.length > 0) {
return false; return false;
} }
if (obj.length && obj.length === 0){ if (obj.length && obj.length === 0) {
return true; return true;
} }
for (key in obj) { for (key in obj) {
if ({}.hasOwnProperty.call(obj, key)){ if ({}.hasOwnProperty.call(obj, key)) {
return false; return false;
} }
} }
...@@ -41,7 +41,7 @@ var utilities = { ...@@ -41,7 +41,7 @@ var utilities = {
isObjectSize : function(obj) { isObjectSize : function(obj) {
var size = 0, key; var size = 0, key;
for (key in obj) { for (key in obj) {
if (obj.hasOwnProperty(key)){ if (obj.hasOwnProperty(key)) {
size++; size++;
} }
} }
...@@ -54,11 +54,11 @@ var utilities = { ...@@ -54,11 +54,11 @@ var utilities = {
* @param {haystack} array - active leaves (versions of a document) * @param {haystack} array - active leaves (versions of a document)
* @returns {boolean} string- true/false * @returns {boolean} string- true/false
*/ */
isInObject : function (needle, haystack){ isInObject : function (needle, haystack) {
var length = haystack.length; var length = haystack.length;
for(var i = 0; i < length; i++) { for(var i = 0; i < length; i++) {
if(haystack[i] === needle){ if(haystack[i] === needle) {
return true; return true;
} }
} }
...@@ -70,7 +70,7 @@ var utilities = { ...@@ -70,7 +70,7 @@ var utilities = {
* @param {needle} string - docId * @param {needle} string - docId
* @returns {boolean} string- true/false * @returns {boolean} string- true/false
*/ */
isUUID : function (documentId){ isUUID : function (documentId) {
var reg = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test( documentId ); var reg = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test( documentId );
return reg; return reg;
}, },
...@@ -81,10 +81,10 @@ var utilities = { ...@@ -81,10 +81,10 @@ var utilities = {
* @param {reason} string - the error reason * @param {reason} string - the error reason
* @returns {e} object - error object * @returns {e} object - error object
*/ */
throwError : function ( code, reason ) { throwError : function (code, reason) {
var statusText, error, message, errorObject; var statusText, error, message, errorObject;
switch( code ){ switch(code) {
case 409: case 409:
statusText = 'Conflict'; statusText = 'Conflict';
...@@ -195,7 +195,7 @@ var utilities = { ...@@ -195,7 +195,7 @@ var utilities = {
* @stored - 'jio/local/USR/APP/FILE_NAME' * @stored - 'jio/local/USR/APP/FILE_NAME'
* @returns {doc} object - document object * @returns {doc} object - document object
*/ */
createDocument : function (docId, docPath){ createDocument : function (docId, docPath) {
var now = Date.now(), var now = Date.now(),
doc = {}, doc = {},
hash = utilities.hashCode('' + doc + ' ' + now + ''); hash = utilities.hashCode('' + doc + ' ' + now + '');
...@@ -221,13 +221,31 @@ var utilities = { ...@@ -221,13 +221,31 @@ var utilities = {
* @param {docid} string - id for the new document * @param {docid} string - id for the new document
* @param {docpath} string - the path where to store the document * @param {docpath} string - the path where to store the document
* @param {previousRevision} string - the previous revision * @param {previousRevision} string - the previous revision
* @param {attachmentId} - string - in case attachments are handled
* @returns {doc} object - new document * @returns {doc} object - new document
*/ */
updateDocument : function (doc, docPath, previousRevision){ updateDocument : function (doc, docPath, previousRevision, attachmentId) {
var now = Date.now(), var now = Date.now(),
rev = utilities.generateNextRevision(previousRevision, ''+ rev = utilities.generateNextRevision(previousRevision, ''+
doc+' '+now+''); doc+' '+now+'');
// in case the update is made because of an attachment
if (attachmentId !== undefined) {
// create _attachments
if (doc._attachments === undefined){
doc._attachments = {};
}
// create _attachments object for this attachment
if (doc._attachments[attachmentId] === undefined){
doc._attachments[attachmentId] = {};
}
// set revpos
doc._attachments[attachmentId].revpos =
parseInt(doc._rev.split('-')[0],10);
}
// update document // update document
doc._rev = rev.join('-'); doc._rev = rev.join('-');
doc._revisions.ids.unshift(rev[1]); doc._revisions.ids.unshift(rev[1]);
...@@ -237,7 +255,6 @@ var utilities = { ...@@ -237,7 +255,6 @@ var utilities = {
"rev": rev.join('-'), "rev": rev.join('-'),
"status": "available" "status": "available"
}); });
return doc; return doc;
}, },
...@@ -255,14 +272,13 @@ var utilities = { ...@@ -255,14 +272,13 @@ var utilities = {
* @info - deleted versions/branches = "status deleted" * @info - deleted versions/branches = "status deleted"
* @info - no active leaves will delete tree, too * @info - no active leaves will delete tree, too
*/ */
createDocumentTree : function (doc){ createDocumentTree : function(doc) {
var tree = { var tree = {
type:'leaf', type:'leaf',
status:'available', status:'available',
rev:doc._rev, rev:doc._rev,
kids:[] kids:[]
}; };
return tree; return tree;
}, },
...@@ -273,50 +289,57 @@ var utilities = { ...@@ -273,50 +289,57 @@ var utilities = {
* @param {new_rev } string - revison of the tree node to add as leaf * @param {new_rev } string - revison of the tree node to add as leaf
* @param {revs_info} object- history of new_rev to merge with remote tree * @param {revs_info} object- history of new_rev to merge with remote tree
*/ */
updateDocumentTree : function ( docTreeNode, old_rev, new_rev, revs_info ){ updateDocumentTree : function (docTreeNode, old_rev, new_rev,
if ( typeof revs_info === "object" ){ revs_info, deletedLeaf ) {
if (typeof revs_info === "object") {
// a new document version is being stored from another storage // a new document version is being stored from another storage
utilities.mergeRemoteTree( docTreeNode, docTreeNode, old_rev, new_rev, utilities.mergeRemoteTree(docTreeNode, docTreeNode, old_rev, new_rev,
revs_info, [], false ); revs_info, [], false, deletedLeaf);
} else { } else {
// update an existing version of document = add a node to the tree // update an existing version of document = add a node to the tree
utilities.setTreeNode( docTreeNode, old_rev, new_rev ); utilities.setTreeNode(docTreeNode, old_rev, new_rev, 'available');
} }
return docTreeNode; return docTreeNode;
}, },
// ==================== SET/MERGE/CHECK TREE NODES ================== // ==================== SET/MERGE/CHECK TREE NODES ==================
/** /**
* @method setTreeNode - adds a new tree node/changes leaf to branch * @method setTreeNode - adds a new tree node/changes leaf to branch
* @param {docTreeNode} object - document tree * @param {docTreeNode} object - document tree
* @param {old_rev} string - revision of the tree node to set to "branch" * @param {old_rev} string - revision of the tree node to set to "branch"
* @param {new_rev } string - revison of the tree node to add as leaf * @param {new_rev } string - revison of the tree node to add as leaf
* @param {new_status}string- status the new node should have
* @info - status is necessary, because we may also
* add deleted nodes to the tree from a
* remote storage
*/ */
setTreeNode : function (docTreeNode, old_rev, new_rev){ setTreeNode : function (docTreeNode, old_rev, new_rev, new_status){
var kids = docTreeNode['kids'], var kids = docTreeNode['kids'],
rev = docTreeNode['rev'], rev = docTreeNode['rev'],
numberOfKids, numberOfKids,
i, i,
key; key;
for( key in docTreeNode ){ for(key in docTreeNode){
if ( key === "rev" ){ if (key === "rev"){
// grow the tree // grow the tree
if ( old_rev === rev && new_rev !== rev ){ if (old_rev === rev && new_rev !== rev) {
docTreeNode.type = 'branch'; docTreeNode.type = 'branch';
docTreeNode.status = 'deleted'; docTreeNode.status = 'deleted';
docTreeNode.kids.push({ docTreeNode.kids.push({
type:'leaf', type:'leaf',
status: 'available', status:new_status,
rev:new_rev, rev:new_rev,
kids:[] kids:[]
}); });
} else { } else {
// traverse until correct node is found! // traverse until correct node is found!
if ( utilities.isObjectEmpty( kids ) === false ){ if ( utilities.isObjectEmpty( kids ) === false ) {
numberOfKids = utilities.isObjectSize(kids); numberOfKids = utilities.isObjectSize(kids);
for ( i = 0; i < numberOfKids; i+=1 ){ for ( i = 0; i < numberOfKids; i+=1 ){
utilities.setTreeNode(kids[i], old_rev, new_rev); utilities.setTreeNode(kids[i], old_rev, new_rev, new_status);
} }
} }
} }
...@@ -337,30 +360,29 @@ var utilities = { ...@@ -337,30 +360,29 @@ var utilities = {
* for the new tree node (we are copy&pasting * for the new tree node (we are copy&pasting
* from another storage) * from another storage)
*/ */
mergeRemoteTree : function ( initialTree, docTreeNode, old_rev, new_rev, mergeRemoteTree : function (initialTree, docTreeNode, old_rev, new_rev,
newDocumentRevisions, addNodes, onTree ){ newDocumentRevisions, addNodes, onTree, deletedLeaf){
var sync_rev = newDocumentRevisions[0].rev, var sync_rev = newDocumentRevisions[0].rev,
current_tree_rev = docTreeNode['rev'], current_tree_rev = docTreeNode['rev'],
kids = docTreeNode['kids'], kids = docTreeNode['kids'],
nodeStatus = 'available',
addNodesLen, addNodesLen,
numberOfKids, numberOfKids,
key, key,
i, i,
j; j;
for ( key in docTreeNode ){ for (key in docTreeNode) {
if ( key === "rev" ){ if (key === "rev") {
// commeon ancestor? = does the revision on the current // common ancestor? = does the revision on the current
// tree node match the currently checked remote tree // tree node match the currently checked remote tree
// revision // revision
// match = common ancestor // match = common ancestor
if ( sync_rev === current_tree_rev ){ if (sync_rev === current_tree_rev){
onTree = true; onTree = true;
// in order to loop we also add the revision of // in order to loop we also add the revision of
// the common ancestor node to the array // the common ancestor node to the array
// using push! // using push!
...@@ -370,19 +392,20 @@ var utilities = { ...@@ -370,19 +392,20 @@ var utilities = {
// the addNodes array will now look like this // the addNodes array will now look like this
// [current_node, all_missing_nodes] // [current_node, all_missing_nodes]
for ( j = 0; j < addNodesLen; j+=1 ){ for (j = 0; j < addNodesLen; j+=1){
utilities.setTreeNode( initialTree, addNodes[j], // last node being added is deleted
addNodes[j+1] if (deletedLeaf === true && j === addNodesLen-1){
); nodeStatus = 'deleted';
}
utilities.setTreeNode(initialTree, addNodes[j],
addNodes[j+1], nodeStatus);
} }
// no match = continue down the tree // no match = continue down the tree
} else if ( utilities.isObjectEmpty( kids ) === false ){ } else if ( utilities.isObjectEmpty( kids ) === false ){
numberOfKids = utilities.isObjectSize( kids ); numberOfKids = utilities.isObjectSize( kids );
for ( i = 0; i < numberOfKids; i+=1 ){ for ( i = 0; i < numberOfKids; i+=1 ){
utilities.mergeRemoteTree( initialTree, kids[i], old_rev, new_rev, utilities.mergeRemoteTree( initialTree, kids[i], old_rev, new_rev,
newDocumentRevisions, addNodes, onTree ); newDocumentRevisions, addNodes, onTree, deletedLeaf );
} }
// end of tree = start over checking the next remote revision // end of tree = start over checking the next remote revision
...@@ -403,13 +426,22 @@ var utilities = { ...@@ -403,13 +426,22 @@ var utilities = {
// this should start over with the full document tree // this should start over with the full document tree
// otherwise it will only continue on the current (last) node // otherwise it will only continue on the current (last) node
utilities.mergeRemoteTree( initialTree, initialTree, old_rev, new_rev, utilities.mergeRemoteTree( initialTree, initialTree, old_rev, new_rev,
newDocumentRevisions, addNodes, onTree ); newDocumentRevisions, addNodes, onTree, deletedLeaf );
} }
} }
} }
return docTreeNode; return docTreeNode;
}, },
getActiveLeaves : function (docTreeNode) {
var activeLeaves = utilities.getLeavesOnTree( docTreeNode );
activeLeaves = typeof activeLeaves === "string" ?
[activeLeaves] : activeLeaves;
return activeLeaves;
},
/** /**
* @method getLeavesOnTree - finds all leaves on a tree * @method getLeavesOnTree - finds all leaves on a tree
* @param {docTree} string - the tree for this document * @param {docTree} string - the tree for this document
...@@ -461,7 +493,10 @@ var utilities = { ...@@ -461,7 +493,10 @@ var utilities = {
status = docTreeNode['status'], status = docTreeNode['status'],
kids = docTreeNode['kids'], kids = docTreeNode['kids'],
rev = docTreeNode['rev'], rev = docTreeNode['rev'],
result = false, numberOfKids,i,key; result = false,
numberOfKids,
i,
key;
for ( key in docTreeNode ){ for ( key in docTreeNode ){
if ( key === "rev" ){ if ( key === "rev" ){
...@@ -470,8 +505,7 @@ var utilities = { ...@@ -470,8 +505,7 @@ var utilities = {
( type === 'branch' || status === 'deleted' ) ){ ( type === 'branch' || status === 'deleted' ) ){
result = true; result = true;
} }
if ( typeof kids === "object" && if ( utilities.isObjectEmpty( kids ) === false ){
utilities.isObjectEmpty( kids ) === false ){
numberOfKids = utilities.isObjectSize( kids ); numberOfKids = utilities.isObjectSize( kids );
for ( i = 0; i < numberOfKids; i+=1 ){ for ( i = 0; i < numberOfKids; i+=1 ){
......
...@@ -165,9 +165,102 @@ var newLocalStorage = function ( spec, my ) { ...@@ -165,9 +165,102 @@ var newLocalStorage = function ( spec, my ) {
}; };
/** /**
* @method post * runDocumentUpdate - run the whole update process for localstorage
* * @param {object} doc - the original document object.
* Create a document in local storage. * @param {object} docTree - the document tree
* @param {object} command - command object
* @param {string} docId - document id
* @param {string} attachmentId - attachmentId
* @param {string} docPath - document paths
* @param {string} prev_rev- previous revision
* @param {string} treePath- document tree paths
* @param {boolean} sync - whether this is an update or sync operation!
* @returns {object} success- success object
*/
priv.runDocumentUpdate = function ( doc, docTree, command, docId, attachmentId,
docPath, prev_rev, treePath, sync ){
var docPathRev,
newRevision,
revs_info,
deletedLeaf;
// update ...I don't know what this is doing?
priv.documentObjectUpdate(doc,command.cloneDoc());
// update document - not when put sync-ing
if ( sync === false ){
// create a new revision
doc = utilities.updateDocument(doc, docPath, prev_rev, attachmentId);
docPathRev = docPath+'/'+doc._rev;
newRevision = doc._rev;
revs_info = undefined;
// delete old doc (.../DOCID/old_REVISION)
localstorage.deleteItem(docPath+'/'+prev_rev);
} else {
docPathRev = docPath +'/'+doc._revs_info[0].rev;
newRevision = null;
revs_info = doc._revs_info;
if ( revs_info[0].status === 'deleted' ){
deletedLeaf = true;
}
}
if ( deletedLeaf === undefined ){
// store new doc (.../DOCID/new_REVISION)
localstorage.setItem(docPathRev, doc);
}
// update tree and store
localstorage.setItem(treePath, utilities.updateDocumentTree(
docTree, prev_rev, newRevision,
revs_info, deletedLeaf)
);
// return SUCCESS
return priv.manageOptions({ok:true,id:docId,rev:doc._rev}, command, doc);
};
/**
* runDocumentCreate - run the whole create process for localstorage
* @param {string} docId - document id
* @param {object} command - command object
* @returns {object} success- success object
*/
priv.runDocumenCreate = function (docId, command){
// create new document and tree
var docPath = 'jio/local/'+priv.secured_username+'/'+
priv.secured_applicationname+'/'+docId,
doc = utilities.createDocument( docId, docPath ),
tree = utilities.createDocumentTree( doc ),
treePath = docPath+'/revision_tree';
// store document
localstorage.setItem(docPath + '/' + doc._rev, doc);
// store tree
localstorage.setItem(treePath, tree);
// add user
if (!priv.doesUserExist(priv.secured_username)) {
priv.addUser(priv.secured_username);
}
// add fileName
priv.addFileName(docId);
// return SUCCESS
return priv.manageOptions({ok:true,id:docId,rev:doc._rev}, command, doc);
};
// =============================== METHODS ======================
/**
* @method post - Create a document in local storage.
* @stored - 'jio/local/USR/APP/FILE_NAME/REVISION'.
* *
* Available options: * Available options:
* - {boolean} conflicts - Add a conflicts object to the response * - {boolean} conflicts - Add a conflicts object to the response
...@@ -178,17 +271,10 @@ var newLocalStorage = function ( spec, my ) { ...@@ -178,17 +271,10 @@ var newLocalStorage = function ( spec, my ) {
that.post = function (command) { that.post = function (command) {
setTimeout (function () { setTimeout (function () {
var docId = command.getDocId(),
var doc,
docId = command.getDocId(),
docPath = 'jio/local/'+priv.secured_username+'/'+
priv.secured_applicationname+'/'+docId,
tree,
treePath = docPath+'/revision_tree',
docTree = localstorage.getItem(treePath),
reg = utilities.isUUID(docId); reg = utilities.isUUID(docId);
// no attachments allowed // 403 - no attachments allowed
if (command.getAttachmentId()) { if (command.getAttachmentId()) {
that.error( utilities.throwError( 403, that.error( utilities.throwError( 403,
'Attachment cannot be added with a POST request') 'Attachment cannot be added with a POST request')
...@@ -196,50 +282,25 @@ var newLocalStorage = function ( spec, my ) { ...@@ -196,50 +282,25 @@ var newLocalStorage = function ( spec, my ) {
return; return;
} }
if ( reg !== true ) { // 403 id was supplied, use PUT
if (reg !== true) {
// id was supplied, use PUT
that.error( utilities.throwError( 403, that.error( utilities.throwError( 403,
'ID cannot be supplied with a POST request. Please use PUT') 'ID cannot be supplied with a POST request. Please use PUT')
); );
return; return;
// ok
} else { } else {
// create new document that.success(
doc = utilities.createDocument( docId, docPath ); priv.runDocumenCreate(docId, command)
// store
localstorage.setItem(docPath + '/' + doc._rev, doc);
// create and store new document.tree
tree = utilities.createDocumentTree( doc );
// store
localstorage.setItem(treePath, tree);
// add user
if (!priv.doesUserExist (priv.secured_username)) {
priv.addUser (priv.secured_username);
}
// add fileName
priv.addFileName(docId);
that.success (
priv.manageOptions(
{ok:true,id:docId,rev:doc._rev},
command,
doc
)
); );
} }
}); });
}; // end post };
/** /**
* @method put * @method put - Create or Update a document in local storage.
* * @stored - 'jio/local/USR/APP/FILE_NAME/REVISION'.
* Create or Update a document in local storage.
* *
* Available options: * Available options:
* - {boolean} conflicts - Add a conflicts object to the response * - {boolean} conflicts - Add a conflicts object to the response
...@@ -254,14 +315,17 @@ var newLocalStorage = function ( spec, my ) { ...@@ -254,14 +315,17 @@ var newLocalStorage = function ( spec, my ) {
prev_rev = command.getDocInfo('_rev'), prev_rev = command.getDocInfo('_rev'),
docPath ='jio/local/'+priv.secured_username+'/'+ docPath ='jio/local/'+priv.secured_username+'/'+
priv.secured_applicationname+'/'+docId, priv.secured_applicationname+'/'+docId,
treePath = docPath+'/revision_tree',tree, treePath = docPath+'/revision_tree',
docTree = localstorage.getItem(treePath), docTree = localstorage.getItem(treePath),
doc, docPathRev, activeLeaves, reg = utilities.isUUID(docId), newDocTree; doc,
docPathRev,
activeLeaves,
reg = utilities.isUUID(docId);
// no tree = create document or error // no tree = create document or error
if (!docTree) { if (!docTree) {
// id/revision provided = update, revision must be incorrect // 404 id/revision provided = update, incorrect revision
if ( prev_rev !== undefined && reg === false ){ if ( prev_rev !== undefined && reg === false ){
that.error( utilities.throwError( 404, that.error( utilities.throwError( 404,
'Document not found, please check revision and/or ID') 'Document not found, please check revision and/or ID')
...@@ -269,7 +333,7 @@ var newLocalStorage = function ( spec, my ) { ...@@ -269,7 +333,7 @@ var newLocalStorage = function ( spec, my ) {
return; return;
} }
// no revision and UUID = create, no id provided // 409 no revision and UUID = create, no id provided
if ( prev_rev === undefined && reg === true){ if ( prev_rev === undefined && reg === true){
that.error( utilities.throwError( 409, that.error( utilities.throwError( 409,
'Missing Document ID and or Revision') 'Missing Document ID and or Revision')
...@@ -278,238 +342,179 @@ var newLocalStorage = function ( spec, my ) { ...@@ -278,238 +342,179 @@ var newLocalStorage = function ( spec, my ) {
} }
// if passed here, we create. // if passed here, we create.
// it could be create (id+content) or update (without revision) // it could be create (id+content) or update (sans revision)
// but since no tree was found and the tree includes id only // but since no tree was found we end here with a NEW id only
// we only end here with a NEW id, so update sans revision cannot // (otherwise tree would be have been found).
// be the case. that.success(
priv.runDocumenCreate(docId, command)
);
// create and store new document } else {
doc = utilities.createDocument( docId, docPath ); // found a tree
activeLeaves = utilities.getActiveLeaves( docTree );
// store // check if revision is on doc-tree and if it is an active leaf
localstorage.setItem(docPath + '/' + doc._rev, doc); if ( !utilities.isInObject( prev_rev, activeLeaves ) ) {
// create and store new document.tree // check if it's a dead leaf (wrong revision)
tree = utilities.createDocumentTree( doc ); if ( utilities.isDeadLeaf( prev_rev, docTree ) ){
// 409 deleted leaf/branch = wrong revision
that.error( utilities.throwError( 409,
'Revision supplied is not the latest revision')
);
return;
}
// store // maybe a sync-PUT from another storage, we must
localstorage.setItem(treePath, tree); // have revs_info option, otherwise we cannot know
// where to put the file and update the storage tree
if ( !utilities.isDeadLeaf( prev_rev, docTree ) &&
command.getDocInfo('_revs_info') === undefined ){
// add user // 409 no revs_info provided
if (!priv.doesUserExist (priv.secured_username)) { that.error( utilities.throwError( 409,
priv.addUser (priv.secured_username); 'Missing revs_info required for sync-put')
);
return;
} else {
// SYNC PUT
// revs_info is provided, this is a new version
// store this document and merge
// NOTE: we also have to SYNC PUT deleted versions
// otherwise the tree will not be the same AND
// other storages will not know which versions of a
// document have been deleted!!!!
// get the new document
doc = command.getDoc();
// ok
that.success(
priv.runDocumentUpdate(doc, docTree, command,
docId, undefined, docPath, prev_rev,
treePath, true)
);
}
} else {
// revision matches a currently active leaf
// = update of an existing document version
// get doc
docPathRev = docPath +'/'+prev_rev;
doc = localstorage.getItem(docPathRev);
if (!doc ){
// 404 document not available, should not happen!
that.error( utilities.throwError( 404,
'Referenced document not found')
);
return;
} else {
// ok
that.success(
priv.runDocumentUpdate(doc, docTree, command,
docId, undefined, docPath, prev_rev,
treePath, false)
);
}
} }
}
});
};
/**
* @method putAttachment - Saves/updates an attachment of a document
* @stored at - 'jio/local/USR/APP/FILE_NAME/REVISION/ATTACHMENTID'.
*
* Available options:
* - {boolean} conflicts - Add a conflicts object to the response
* - {boolean} revs - Add the revisions history of the document
* - {boolean} revs_info - Add revisions informations
*/
that.putAttachment = function (command) {
setTimeout( function () {
var docId = command.getDocId(),
docPath ='jio/local/'+priv.secured_username+'/'+
priv.secured_applicationname+'/'+docId,
prev_rev = command.getDocInfo('_rev'),
treePath = docPath+'/revision_tree',
docTree = localstorage.getItem(treePath),
doc,
docPathRev,
activeLeaves,
attachmentId,
attachment,
attachmentPath;
// add fileName if (!docTree) {
priv.addFileName(docId);
that.success ( // 404 document wasn't found = wrong id or revision
priv.manageOptions( that.error( utilities.throwError( 404,
{ok:true,id:docId,rev:doc._rev}, 'Document not found, please check document ID')
command,
doc
)
); );
return;
} else { } else {
// found a tree - get active leaves // found a tree
activeLeaves = utilities.getLeavesOnTree( docTree ); activeLeaves = utilities.getActiveLeaves( docTree );
// this should return an array of all active leaves // check if revision is on tree
// or a single leaf, which needs to be put into an array if ( utilities.isInObject( prev_rev, activeLeaves ) ) {
activeLeaves = typeof activeLeaves === "string" ?
[activeLeaves] : activeLeaves;
// check if revision is on doc-tree and is an active leaf
if ( !utilities.isInObject( prev_rev, activeLeaves ) ) {
// check if it's a branch/dead leaf (deleted/updated version)
if ( utilities.isDeadLeaf( prev_rev, docTree ) ){
that.error( utilities.throwError( 409,
'Revision supplied is not the latest revision')
);
return;
}
// maybe a sync-PUT from another storage, we must // check if dead leaf
// have revs_info option, otherwise we cannot know if ( utilities.isDeadLeaf( prev_rev, docTree ) ){
// where to put the file and update the storage tree
if ( !utilities.isDeadLeaf( prev_rev, docTree ) &&
command.getDocInfo('_revs_info') === undefined ){
that.error( utilities.throwError( 409,
'Missing revs_info required for sync-put')
);
return;
} else {
// SYNC PUT
// revs_info is provided, this is a new version
// store this document and merge
// get the new document
doc = command.getDoc();
// we are not updating, this is a copy&paste sync
// therefore the path should have the revision of
// the current document. No new revision hash
// needs to be created
docPathRev = docPath +'/'+doc._revs_info[0].rev;
// update ...???
priv.documentObjectUpdate(doc,command.cloneDoc());
// store the new item.
localstorage.setItem( docPathRev, doc );
// update tree and store
localstorage.setItem(treePath,
utilities.updateDocumentTree( docTree, prev_rev, null,
doc._revs_info )
);
that.success (
priv.manageOptions(
{ok:true,id:docId,rev:prev_rev},
command,
doc
)
);
}
} else {
// revision matches a currently active leaf // 409 deleted leaf/branch = wrong revision
// update of an existing document version that.error( utilities.throwError( 409,
'Trying to update on a previous document version')
);
return;
// get doc } else {
docPathRev = docPath +'/'+prev_rev; // revision is ok
doc = localstorage.getItem(docPathRev); attachmentId = command.getAttachmentId();
if (!doc ){ // 409 missing attachment id
// documen not available, should not happen! if ( !attachmentId ){
that.error( utilities.throwError( 404, that.error( utilities.throwError( 409,
'Referenced document not found') 'No attachment id specified')
); );
return; return;
} else { } else {
// update ...? // set attachment
priv.documentObjectUpdate(doc,command.cloneDoc()); attachmentPath = docPath+'/'+prev_rev+'/'+attachmentId;
attachment = localstorage.getItem(attachmentPath);
// update document
doc = utilities.updateDocument( doc, docPath, prev_rev ); // store/update attachment
localstorage.setItem(attachmentPath,command.getContent());
// store new doc (.../DOCID/new_REVISION)
localstorage.setItem(docPath+'/'+doc._rev, doc); // get doc
docPathRev = docPath +'/'+prev_rev;
// delete old doc (.../DOCID/old_REVISION) doc = localstorage.getItem(docPathRev);
localstorage.deleteItem(docPath+'/'+prev_rev);
// ok
// update tree and store that.success(
localstorage.setItem(treePath, priv.runDocumentUpdate(doc, docTree, command,
utilities.updateDocumentTree( docId, attachmentId, docPath, prev_rev,
docTree, prev_rev, doc._rev, undefined ) treePath, false)
);
that.success (
priv.manageOptions(
{ok:true,id:docId,rev:doc._rev},
command,
doc
)
); );
} // found a doc to update }
} // updating existing document }
} // found a tree
}); // set timeout
}; // end put
/**
* Saves/updates an attachment of a specified document.
* attachment will be stored @ 'jio/local/USR/APP/FILE_NAME/ATTACHMENTID'.
* @method putAttachment
*/
that.putAttachment = function (command) {
var now = Date.now();
// wait a little in order to simulate asynchronous saving
setTimeout (function () {
var docid, doc, docpath, attmtid, attmt, attmtpath, prev_rev, rev;
docid = command.getDocId();
prev_rev = command.getDocInfo('_rev');
docpath ='jio/local/'+priv.secured_username+'/'+
priv.secured_applicationname+'/'+docid;
// 404
doc = localstorage.getItem(docpath);
if (!doc) {
that.error({
status:404,statusText:'Not found',error:'not_found',
message:'Document not found.',
reason:'Document with specified id does not exist'
});
return;
}
// 409
if (doc._rev !== prev_rev) {
// want to update an older document
that.error({
status:409,statusText:'Conflict',error:'conflict',
message:'Document update conflict.',
reason:'Trying to update a previous document version'
});
return;
}
// check attachment id
attmtid = command.getAttachmentId();
if (attmtid) {
attmtpath = docpath+'/'+attmtid;
attmt = localstorage.getItem(attmtpath);
// create _attachments
if ( doc._attachments === undefined ){
doc._attachments = {};
}
// create _attachments object for this attachment } else {
if ( doc._attachments[attmtid] === undefined ){ // 404 revision supplied is not on tree
doc._attachments[attmtid] = {}; that.error( utilities.throwError( 404,
'Document not found, please check revision')
);
return;
} }
// set revpos
doc._attachments[attmtid].revpos =
parseInt(doc._rev.split('-')[0],10);
// store/update attachment
localstorage.setItem(attmtpath,command.getContent());
} else {
// no attachment id specified
that.error({
status:409,statusText:'Conflict',error:'conflict',
message:'Document update conflict.',
reason:'No attachment id specified'
});
return;
} }
// rev = [number, hash]
rev = utilities.generateNextRevision(prev_rev, ''+doc+' '+now+'');
doc._rev = rev.join('-');
doc._revisions.ids.unshift(rev[1]);
doc._revisions.start = rev[0];
doc._revs_info[0].status = 'deleted';
doc._revs_info.unshift({
"rev": rev.join('-'),
"status": "available"
});
localstorage.setItem(docpath, doc);
that.success (
priv.manageOptions(
{"ok":true,"id":docid,"rev":doc._rev},
command,
doc
)
);
}); });
}; // end putAttachment }; // end putAttachment
...@@ -573,13 +578,14 @@ var newLocalStorage = function ( spec, my ) { ...@@ -573,13 +578,14 @@ var newLocalStorage = function ( spec, my ) {
* the user. * the user.
* @method allDocs * @method allDocs
*/ */
// ============== NOT MODIFIED YET =============== // ============== NOT MODIFIED YET ===============
that.allDocs = function (command) { that.allDocs = function (command) {
setTimeout(function () { setTimeout(function () {
var new_array = [], array = [], i, l, k = 'key', var new_array = [], array = [], i, l, k = 'key',
path = 'jio/local/'+priv.secured_username+'/'+ path = 'jio/local/'+priv.secured_username+'/'+
priv.secured_applicationname, 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) {
...@@ -614,7 +620,7 @@ var newLocalStorage = function ( spec, my ) { ...@@ -614,7 +620,7 @@ var newLocalStorage = function ( spec, my ) {
// wait a little in order to simulate asynchronous saving // wait a little in order to simulate asynchronous saving
setTimeout (function () { setTimeout (function () {
var docid, doc, docpath, prev_rev, attmtid, attmt, attpath; var docid, doc, docpath, prev_rev, attmtid, attmt, attpath;
docid = command.getDocId(); docid = command.getDocId(),
docpath = 'jio/local/'+priv.secured_username+'/'+ docpath = 'jio/local/'+priv.secured_username+'/'+
priv.secured_applicationname+'/'+docid; priv.secured_applicationname+'/'+docid;
prev_rev = command.getDocInfo('_rev'); prev_rev = command.getDocInfo('_rev');
......
...@@ -80,6 +80,8 @@ var command = function(spec, my) { ...@@ -80,6 +80,8 @@ var command = function(spec, my) {
* @return {object} the document. * @return {object} the document.
*/ */
that.getDoc = function() { that.getDoc = function() {
console.log("where is my doc");
console.log( priv.doc );
return priv.doc; return priv.doc;
}; };
......
...@@ -359,10 +359,12 @@ test ('All tests', function () { ...@@ -359,10 +359,12 @@ test ('All tests', function () {
_creation_date:10000},'dummyallok loading'); _creation_date:10000},'dummyallok loading');
o.jio.get('file',o.f); o.jio.get('file',o.f);
o.tick(o); o.tick(o);
// remove // remove
o.spy(o,'value',{ok:true,id:"file"},'dummyallok removing'); o.spy(o,'value',{ok:true,id:"file"},'dummyallok removing');
o.jio.remove({_id:'file'},o.f); o.jio.remove({_id:'file'},o.f);
o.tick(o); o.tick(o);
// get list // get list
o.spy (o,'value',{ o.spy (o,'value',{
total_rows:2, total_rows:2,
...@@ -726,25 +728,37 @@ test ('Post', function(){ ...@@ -726,25 +728,37 @@ test ('Post', function(){
test ('Put', function(){ test ('Put', function(){
// runs following assertions // runs following assertions
// 1) PUT without ID = 409 // 1) PUT without ID = 409
// 2) PUT with wrong ID/rev = 404 // 2) PUT with wrong ID/rev = 404
// 3) PUT CREATE // 3) PUT CREATE response
// 4) check file was created // 4) check file was created
// 5) check tree was created // 5) check tree was created
// 6) PUT UPDATE // 6) PUT UPDATE response
// 7) check file was replaced // 7) check file was replaced
// 8) check tree was updated // 8) check tree was updated
// 9) PUT UPDATE 2 // 9) PUT UPDATE 2 response
// 10) check file was replaced // 10) check file was replaced
// 11) check tree was updated // 11) check tree was updated
// 12) PUT UPDATE false revision = 409 // 12) PUT UPDATE false revision = 409
// 13) SYNC-PUT no revs_info = 409 // 13) SYNC-PUT no revs_info = 409
// 14) SYNC-PUT revs_info // 14) SYNC-PUT revs_info response
// 15) check if file created
var o = {}; // 16) check if tree was merged
// 17) SYNC-PUT revs_info dead leaf response
// 18) check that file was NOT created
// 19) check that tree was updated
var fake_rev_0,
fake_rev_1,
fake_rev_2,
fake_id_0,
fake_id_1,
fake_id_2,
o = {};
o.t = this; o.t = this;
o.clock = o.t.sandbox.useFakeTimers(), o.clock = o.t.sandbox.useFakeTimers();
o.falseRevision, o.falseRevision;
localstorage = { localstorage = {
getItem: function (item) { getItem: function (item) {
return JSON.parse (localStorage.getItem(item)); return JSON.parse (localStorage.getItem(item));
...@@ -791,6 +805,8 @@ test ('Put', function(){ ...@@ -791,6 +805,8 @@ test ('Put', function(){
"_rev":'1-ABCDEFG'},o.f); "_rev":'1-ABCDEFG'},o.f);
checkReply(o,null,true); checkReply(o,null,true);
o.clock.tick(base_tick);
// start adding content // start adding content
o.jio.put({"content":'content',"_id":'myDoc'}, o.jio.put({"content":'content',"_id":'myDoc'},
function(err, response) { function(err, response) {
...@@ -813,9 +829,10 @@ test ('Put', function(){ ...@@ -813,9 +829,10 @@ test ('Put', function(){
}); });
// 3) TEST PUT content // 3) TEST PUT content
// no idea why this is working for 3/6/9/12, but it does...
checkReply(o,null,true); checkReply(o,null,true);
o.clock.tick(base_tick);
// update document // update document
o.jio.put({"content":'content_modified',"_id":'myDoc', o.jio.put({"content":'content_modified',"_id":'myDoc',
"_rev":o.testRevisionStorage[0]}, "_rev":o.testRevisionStorage[0]},
...@@ -839,12 +856,13 @@ test ('Put', function(){ ...@@ -839,12 +856,13 @@ test ('Put', function(){
// 6) TEST PUT UPDATE // 6) TEST PUT UPDATE
checkReply(o,null,true); checkReply(o,null,true);
o.clock.tick(base_tick);
// update document 2nd time // update document 2nd time
o.jio.put({"content":'content_modified_again', o.jio.put({"content":'content_modified_again',
"_id":'myDoc', "_id":'myDoc',
"_rev":o.testRevisionStorage[0]}, "_rev":o.testRevisionStorage[0]},
function(err, response) { function(err, response) {
var fake_rev_0,fake_rev_1,fake_id_0,fake_id_1;
o.spy(o,'value',{"ok":true,"id":response.id, o.spy(o,'value',{"ok":true,"id":response.id,
"rev":response.rev}, 'PUT content = ok'); "rev":response.rev}, 'PUT content = ok');
...@@ -867,11 +885,9 @@ test ('Put', function(){ ...@@ -867,11 +885,9 @@ test ('Put', function(){
// 9) TEST PUT UPDATE // 9) TEST PUT UPDATE
checkReply(o,null,true); checkReply(o,null,true);
// continue to work with this instance o.clock.tick(base_tick);
//o.jio.stop();
//o.clean;
// try updating with false revision // TEST 12) PUT false revision
o.spy (o,'value',{ o.spy (o,'value',{
"error": 'conflict', "error": 'conflict',
"message": 'Document update conflict.', "message": 'Document update conflict.',
...@@ -884,11 +900,11 @@ test ('Put', function(){ ...@@ -884,11 +900,11 @@ test ('Put', function(){
o.jio.put({"content":'content_modified_false', o.jio.put({"content":'content_modified_false',
"_id":'myDoc', "_id":'myDoc',
"_rev":o.falseRevision},o.f); "_rev":o.falseRevision},o.f);
// TEST 12) PUT false revision
checkReply(o,null,true); checkReply(o,null,true);
o.clock.tick(base_tick);
// try updating without revs_info // TEST 13) SYNC-PUT no revs_info
o.spy (o,'value',{ o.spy (o,'value',{
"error": 'conflict', "error": 'conflict',
"message": 'Document update conflict.', "message": 'Document update conflict.',
...@@ -901,9 +917,10 @@ test ('Put', function(){ ...@@ -901,9 +917,10 @@ test ('Put', function(){
o.jio.put({"content":'content_modified_false', o.jio.put({"content":'content_modified_false',
"_id":'myDoc', "_id":'myDoc',
"_rev":'1-abcdefg'},o.f); "_rev":'1-abcdefg'},o.f);
// TEST 13) SYNC-PUT no revs_info
checkReply(o,null,true); checkReply(o,null,true);
o.clock.tick(base_tick);
// add a new document version with fake revs_info // add a new document version with fake revs_info
// the new document has the same origin and first edit, // the new document has the same origin and first edit,
// then it was changed to a new version (3-a9d...), // then it was changed to a new version (3-a9d...),
...@@ -912,10 +929,12 @@ test ('Put', function(){ ...@@ -912,10 +929,12 @@ test ('Put', function(){
// and add the two new dummy revisions into the final // and add the two new dummy revisions into the final
// tree. Also the new document should be stored // tree. Also the new document should be stored
// in local storage. // in local storage.
fake_rev_2 = o.testRevisionStorage[2];
fake_rev_1 = o.testRevisionStorage[1]; fake_rev_1 = o.testRevisionStorage[1];
fake_rev_0 = o.testRevisionStorage[0]; fake_rev_0 = o.testRevisionStorage[0];
fake_id_0 = o.testRevisionStorage[0].split('-')[1]; fake_id_2 = o.testRevisionStorage[2].split('-')[1];
fake_id_1 = o.testRevisionStorage[1].split('-')[1]; fake_id_1 = o.testRevisionStorage[1].split('-')[1];
fake_id_0 = o.testRevisionStorage[0].split('-')[1];
// put a new document version // put a new document version
o.jio.put({ o.jio.put({
...@@ -927,7 +946,7 @@ test ('Put', function(){ ...@@ -927,7 +946,7 @@ test ('Put', function(){
{"rev":"3-a9dac9ff5c8e1b2fce58e5397e9b6a8de729d5c6eff8f26a7b71df6348986123","status":"deleted"}, {"rev":"3-a9dac9ff5c8e1b2fce58e5397e9b6a8de729d5c6eff8f26a7b71df6348986123","status":"deleted"},
{"rev":fake_rev_1,"status":"deleted"}, {"rev":fake_rev_1,"status":"deleted"},
{"rev":fake_rev_0,"status":"deleted"} {"rev":fake_rev_0,"status":"deleted"}
], ],
"_revisions":{ "_revisions":{
"start":4, "start":4,
"ids":[ "ids":[
...@@ -970,7 +989,80 @@ test ('Put', function(){ ...@@ -970,7 +989,80 @@ test ('Put', function(){
// 14) TEST PUT UPDATE // 14) TEST PUT UPDATE
checkReply(o,null,true); checkReply(o,null,true);
o.clock.tick(base_tick);
/*
// put a new deleted version
o.jio.put({
"content":'a_deleted_version',
"_id":'myDoc',
"_rev":"3-05210795b6aa8cb5e1e7f021960d233cf963f1052b1a41777ca1a2aff8fd4b61",
"_revs_info":[
{"rev":"3-05210795b6aa8cb5e1e7f021960d233cf963f1052b1a41777ca1a2aff8fd4b61","status":"deleted"},
{"rev":"2-67ac10df5b7e2582f2ea2344b01c68d461f44b98fef2c5cba5073cc3bdb5a844","status":"deleted"},
{"rev":fake_rev_2,"status":"deleted"}
],
"_revisions":{
"start":3,
"ids":[
"05210795b6aa8cb5e1e7f021960d233cf963f1052b1a41777ca1a2aff8fd4b61",
"67ac10df5b7e2582f2ea2344b01c68d461f44b98fef2c5cba5073cc3bdb5a844",
fake_id_2
]}
},
function(err, response) {
//o.testRevisionStorage.unshift(response.rev);
o.buildTestTree = {
"kids":[{
"kids":[
{"kids":[],
"rev":o.testRevisionStorage[0],
"status":'available',
"type":'leaf'
},
{"kids":[{
"kids":[],
"rev":"4-b5bb2f1657ac5ac270c14b2335e51ef1ffccc0a7259e14bce46380d6c446eb89",
"status":'available', "type":'leaf'
}],
"rev":"3-a9dac9ff5c8e1b2fce58e5397e9b6a8de729d5c6eff8f26a7b71df6348986123",
"status":'deleted',
"type":'branch'
}],
"rev":o.testRevisionStorage[1],
"status":'deleted',
"type":'branch'
},{
"kids":[
{
"kids":[],
"rev":"3-05210795b6aa8cb5e1e7f021960d233cf963f1052b1a41777ca1a2aff8fd4b61",
"status":'deleted',
"type":'leaf'
}],
"rev":"2-67ac10df5b7e2582f2ea2344b01c68d461f44b98fef2c5cba5073cc3bdb5a844",
"status":'deleted',
"typ":'branch'
}],
"rev":o.testRevisionStorage[2],
"status":'deleted',
"type":'branch'
};
o.spy(o,'value',{"ok":true,"id":response.id,
"rev":response.rev}, 'PUT SYNC dead leaf = ok');
o.f(response);
// TEST 18) check document was stored
//checkFile(response, o, null, true);
// TEST 19) check tree was updated
//checkTreeNode(response, o, null, true);
});
// 17) TEST PUT UPDATE
//checkReply(o,null,true);
*/
}); });
......
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