Commit 2ae42bb4 authored by Tristan Cavelier's avatar Tristan Cavelier

dav: post, put, putAttachment and get updated + test

parent 6e6a56d0
...@@ -3,147 +3,259 @@ ...@@ -3,147 +3,259 @@
* Released under the LGPL license. * Released under the LGPL license.
* http://www.gnu.org/licenses/lgpl.html * http://www.gnu.org/licenses/lgpl.html
*/ */
/*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */ /*jslint indent: 2, maxlen: 80, sloppy: true, nomen: true */
/*global jIO: true, $: true, btoa: true */ /*global jIO: true, $: true, btoa: true */
jIO.addStorageType('dav', function (spec, my) {
// JIO Dav Storage Description :
spec = spec || {}; // {
var that, priv, super_serialized; // type: "dav",
that = my.basicStorage(spec, my); // url: {string}
priv = {}; // }
super_serialized = that.serialized;
// {
priv.secureDocId = function (string) { // type: "dav",
var split = string.split('/'), // url: {string},
i; // auth_type: {string}, (optional)
if (split[0] === '') { // - "auto" (default) (not implemented)
split = split.slice(1); // - "basic"
} // - "digest" (not implemented)
for (i = 0; i < split.length; i += 1) { // realm: {string}, (optional)
if (split[i] === '') { // - undefined (default) (not implemented)
return ''; // - "<string>" realm name (not implemented)
// username: {string},
// password: {string} (optional)
// }
// {
// type: "dav",
// url: {string},
// encoded_login: {string}
// }
// {
// type: "dav",
// url: {string},
// secured_login: {string} (not implemented)
// }
// NOTE: to get the authentication type ->
// curl --verbose -X OPTION http://domain/
// In the headers: "WWW-Authenticate: Basic realm="DAV-upload"
// URL Characters convertion:
// If I want to retrieve the file which id is -> http://100%.json
// http://domain/collection/http://100%.json cannot be applied
// - '/' is col separator,
// - '%' is special char
// - '.' document and attachment separator
// http://100%.json will become
// - http:%2F%2F100%25.json to avoid bad request ('/', '%' -> '%2F', '%25')
// - http:%2F%2F100%25_.json to avoid ids conflicts ('.' -> '_.')
// - http:%252F%252F100%2525_.json to avoid request bad interpretation
// ('%', '%25')
// The file will be saved as http:%2F%2F100%25_.json
jIO.addStorageType("dav", function (spec, my) {
var priv = {}, that = my.basicStorage(spec, my), dav = {};
// ATTRIBUTES //
priv.url = null;
priv.username = null;
priv.password = null;
priv.encoded_login = null;
// CONSTRUCTOR //
/**
* Init the dav storage connector thanks to the description
* @method __init__
* @param {object} description The description object
*/
priv.__init__ = function (description) {
priv.url = description.url || "";
priv.url = priv.removeSlashIfLast(priv.url);
// if (description.secured_login) {
// not implemented
// } else
if (description.encoded_login) {
priv.encoded_login = description.encoded_login;
} else if (description.auth_type) {
if (description.auth_type === "basic") {
priv.encoded_login = "Basic " +
btoa((description.username || "") + ":" +
(description.password || ""));
} }
} else {
priv.encoded_login = "";
} }
return split.join('%2F');
}; };
priv.convertSlashes = function (string) {
return string.split('/').join('%2F'); // OVERRIDES //
that.specToStore = function () {
// TODO: secured password
// The encoded_login can be seen by anyone, we must find a way to secure it!
// secured_login = encrypt(encoded_login)
// encoded_login = decrypt(secured_login)
return {
"url": priv.url,
"encoded_login": priv.encoded_login
};
};
that.validateState = function () {
if (typeof priv.url !== "string" || priv.url === "") {
return "The webDav server URL is not provided";
}
if (priv.encoded_login === null) {
return "Impossible to create the authorization";
}
return "";
}; };
priv.restoreSlashes = function (string) { // TOOLS //
return string.split('%2F').join('/'); /**
* Generate a new uuid
* @method generateUuid
* @return {string} The new uuid
*/
priv.generateUuid = function () {
var S4 = function () {
/* 65536 */
var i, string = Math.floor(
Math.random() * 0x10000
).toString(16);
for (i = string.length; i < 4; i += 1) {
string = "0" + string;
}
return string;
};
return S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() +
S4() + S4();
}; };
// /**
// * Clones an object in deep
// * @method clone
// * @param {object} object The object to clone
// * @return {object} The cloned object
// */
// priv.clone = function (object) {
// var tmp = JSON.stringify(object);
// if (tmp === undefined) {
// return undefined;
// }
// return JSON.parse(tmp);
// };
/** /**
* Checks if an object has no enumerable keys * Replace substrings to another strings
* @method objectIsEmpty * @method recursiveReplace
* @param {object} obj The object * @param {string} string The string to do replacement
* @return {boolean} true if empty, else false * @param {array} list_of_replacement An array of couple
* ["substring to select", "selected substring replaced by this string"].
* @return {string} The replaced string
*/ */
priv.objectIsEmpty = function (obj) { priv.recursiveReplace = function (string, list_of_replacement) {
var k; var i, split_string = string.split(list_of_replacement[0][0]);
for (k in obj) { if (list_of_replacement[1]) {
if (obj.hasOwnProperty(k)) { for (i = 0; i < split_string.length; i += 1) {
return false; split_string[i] = priv.recursiveReplace(
split_string[i],
list_of_replacement.slice(1)
);
} }
} }
return true; return split_string.join(list_of_replacement[0][1]);
}; };
priv.username = spec.username || ''; /**
priv.secured_username = priv.convertSlashes(priv.username); * Changes / to %2F, % to %25 and . to _.
priv.password = spec.password || ''; * @method secureName
priv.url = spec.url || ''; * @param {string} name The name to secure
* @return {string} The secured name
that.serialized = function () { */
var o = super_serialized(); priv.secureName = function (name) {
o.username = priv.username; return priv.recursiveReplace(name, [["/", "%2F"], ["%", "%25"]]);
o.url = priv.url;
o.password = priv.password;
return o;
}; };
priv.newAsyncModule = function () { /**
var async = {}; * Restores the original name from a secured name
async.call = function (obj, function_name, arglist) { * @method restoreName
obj._wait = obj._wait || {}; * @param {string} secured_name The secured name to restore
if (obj._wait[function_name]) { * @return {string} The original name
obj._wait[function_name] -= 1; */
return function () {}; priv.restoreName = function (secured_name) {
} return priv.recursiveReplace(secured_name, [["%2F", "/"], ["%25", "%"]]);
// ok if undef or 0
arglist = arglist || [];
return obj[function_name].apply(obj[function_name], arglist);
};
async.neverCall = function (obj, function_name) {
obj._wait = obj._wait || {};
obj._wait[function_name] = -1;
};
async.wait = function (obj, function_name, times) {
obj._wait = obj._wait || {};
obj._wait[function_name] = times;
};
async.end = function () {
async.call = function () {};
};
return async;
}; };
/** /**
* Checks if a browser supports cors (cross domain ajax requests) * Convert document id and attachment id to a file name
* @method checkCors * @method idsToFileName
* @return {boolean} true if supported, else false * @param {string} doc_id The document id
* @param {string} attachment_id The attachment id (optional)
* @return {string} The file name
*/ */
priv.checkCors = function () { priv.idsToFileName = function (doc_id, attachment_id) {
return $.support.cors; doc_id = priv.secureName(doc_id).split(".").join("_.");
if (typeof attachment_id === "string") {
attachment_id = priv.secureName(attachment_id).split(".").join("_.");
return doc_id + "." + attachment_id;
}
return doc_id;
}; };
/** /**
* Replaces last "." with "_." in document filenames * Removes the last character if it is a "/". "/a/b/c/" become "/a/b/c"
* @method underscoreFileExtenisons * @method removeSlashIfLast
* @param {string} url url to clean up * @param {string} string The string to modify
* @return {string} clean_url cleaned up URL * @return {string} The modified string
*/ */
priv.underscoreFileExtenisons = function (url) { priv.removeSlashIfLast = function (string) {
var clean_url = url.replace(/,\s(\w+)$/, "_.$1"); if (string[string.length - 1] === "/") {
return clean_url; return string.slice(0, -1);
}
return string;
}; };
/** /**
* Replaces "_." with "." in document filenames * Modify an ajax object to add default values
* @method restoreDots * @method makeAjaxObject
* @param {string} url url to clean up * @param {string} file_name The file name to add to the url
* @return {string} clean_url cleaned up URL * @param {object} ajax_object The ajax object to override
* @return {object} A new ajax object with default values
*/ */
priv.restoreDots = function (url) { priv.makeAjaxObject = function (file_name, method, ajax_object) {
var clean_url = url.replace(/_\./g, '.'); ajax_object.type = method || ajax_object.type || "GET";
return clean_url; ajax_object.url = priv.url + "/" + priv.secureName(file_name) +
"?_=" + Date.now();
ajax_object.async = ajax_object.async === false ? false : true;
ajax_object.crossdomain = ajax_object.crossdomain === false ? false : true;
ajax_object.headers = ajax_object.headers || {};
ajax_object.headers.Authorization = ajax_object.headers.Authorization ||
priv.encoded_login;
return ajax_object;
}; };
/** /**
* Runs all ajax requests for davStorage * Runs all ajax requests for davStorage
* @method ajax * @method ajax
* @param {object} ajax_object The request parameters * @param {string} doc_id The document id
* @param {string} attachment_id The attachment id, can be undefined
* @param {string} method The request method
* @param {object} ajax_object The request parameters (optional)
*/ */
priv.ajax = function (ajax_object) { priv.ajax = function (doc_id, attachment_id, method, ajax_object) {
$.ajax({ var new_ajax_object = JSON.parse(JSON.stringify(ajax_object) || "{}");
url: ajax_object.url, console.log(priv.makeAjaxObject(
type: ajax_object.type, priv.idsToFileName(doc_id, attachment_id),
async: true, method,
dataType: ajax_object.dataType || null, new_ajax_object
data: ajax_object.data || null, ));
crossdomain : true, return $.ajax(priv.makeAjaxObject(
headers : { priv.idsToFileName(doc_id, attachment_id),
Authorization: 'Basic ' + btoa( method,
priv.username + ':' + priv.password new_ajax_object
), ));//.always(then || function () {});
Depth: ajax_object.headers === undefined ? null :
ajax_object.headers.depth
},
// xhrFields: {withCredentials: 'true'},
success: ajax_object.success,
error: ajax_object.error
});
}; };
/** /**
...@@ -153,57 +265,123 @@ jIO.addStorageType('dav', function (spec, my) { ...@@ -153,57 +265,123 @@ jIO.addStorageType('dav', function (spec, my) {
* @return {object} error The error object * @return {object} error The error object
*/ */
priv.createError = function (status, message, reason) { priv.createError = function (status, message, reason) {
var error = {}; var error = {
"status": status,
"message": message,
"reason": reason
};
switch (status) { switch (status) {
case 404: case 404:
error.status = status;
error.statusText = "Not found"; error.statusText = "Not found";
error.error = "not_found";
error.message = message;
error.reason = reason;
break; break;
case 405: case 405:
error.status = status;
error.statusText = "Method Not Allowed"; error.statusText = "Method Not Allowed";
error.error = "method_not_allowed";
error.message = message;
error.reason = reason;
break; break;
case 409: case 409:
error.status = status;
error.statusText = "Conflicts"; error.statusText = "Conflicts";
error.error = "conflicts"; break;
error.message = message; case 24:
error.reason = reason; error.statusText = "Broken Document";
break; break;
} }
error.error = error.statusText.toLowerCase().split(" ").join("_");
return error; return error;
}; };
/** /**
* Check if method can be run on browser * Converts ajax error object to a JIO error object
* @method support * @method ajaxErrorToJioError
* @param {object} ajax_error_object The ajax error object
* @param {string} message The error message
* @param {string} reason The error reason
* @return {object} The JIO error object
*/ */
priv.support = function (docid) { priv.ajaxErrorToJioError = function (ajax_error_object, message, reason) {
// no docId var jio_error_object = {};
if (!(typeof docid === "string" && docid !== "")) { jio_error_object.status = ajax_error_object.status;
that.error(priv.createError(405, "Can't create document without id", jio_error_object.statusText = ajax_error_object.statusText;
"Document id is undefined" jio_error_object.error =
)); ajax_error_object.statusText.toLowerCase().split(" ").join("_");
return true; jio_error_object.message = message;
} jio_error_object.reason = reason;
// no cross domain ajax return jio_error_object;
if (priv.checkCors === false) { };
that.error(priv.createError(405,
"Browser does not support cross domain ajax", "CORS is undefined" /**
)); * Function that create an object containing jQuery like callbacks
return true; * @method makeJQLikeCallback
} * @return {object} jQuery like callback methods
*/
priv.makeJQLikeCallback = function () {
var result = null, emptyFun = function () {}, jql = {
"respond": function () {
result = arguments;
},
"to_return": {
"always": function (func) {
if (result) {
func.apply(func, result);
jql.to_return.always = emptyFun;
} else {
jql.respond = func;
}
return jql.to_return;
},
"then": function (func) {
if (result) {
func(result[1]);
jql.to_return.then = emptyFun;
} else {
jql.respond = function (err, response) {
func(response);
};
}
return jql.to_return;
}
}
};
return jql;
};
// DAV REQUESTS //
/**
* Retrieve a document
* @method dav.getDocument
* @param {string} doc_id The document id
* @param {function} then The callback(err, response)
*/
dav.getDocument = function (doc_id) {
var doc, jql = priv.makeJQLikeCallback();
priv.ajax(doc_id, undefined, "GET").always(function (one, state, three) {
if (state !== "success") {
jql.respond(priv.ajaxErrorToJioError(
one,
"Cannot retrieve document",
"Unknown error"
), undefined);
} else {
try {
doc = JSON.parse(one);
} catch (e) {
return jql.respond(priv.createError(
24,
"Cannot parse document",
"Document is broken"
), undefined);
}
// document health is good
jql.respond(undefined, doc);
}
});
return jql.to_return;
}; };
dav.putDocument = function (doc) {
// TODO
};
// JIO COMMANDS //
// wedDav methods rfc4918 (short summary) // wedDav methods rfc4918 (short summary)
// COPY Reproduces single resources (files) and collections (directory // COPY Reproduces single resources (files) and collections (directory
// trees). Will overwrite files (if specified by request) but will // trees). Will overwrite files (if specified by request) but will
...@@ -229,89 +407,54 @@ jIO.addStorageType('dav', function (spec, my) { ...@@ -229,89 +407,54 @@ jIO.addStorageType('dav', function (spec, my) {
// adding custom headers triggers preflight OPTIONS request! // adding custom headers triggers preflight OPTIONS request!
// http://remysharp.com/2011/04/21/getting-cors-working/ // http://remysharp.com/2011/04/21/getting-cors-working/
/**
priv.putOrPost = function (command, type) { * Creates a new document
var docid = command.getDocId(), secured_docid, url, ajax_object; * @method post
* @param {object} command The JIO command
if (priv.support(docid)) { */
return; that.post = function (command) {
} var doc_id = command.getDocId() || priv.generateUuid();
priv.ajax(doc_id, undefined, "GET").always(function (one, state, three) {
secured_docid = priv.secureDocId(command.getDocId()); if (state !== "success") {
url = priv.url + '/' + priv.underscoreFileExtenisons(secured_docid); if (one.status === 404) {
// the document does not already exist
ajax_object = { // updating document
url: url + '?_=' + Date.now(), priv.ajax(doc_id, undefined, "PUT", {
type: "GET", "dataType": "text",
dataType: "text", "data": JSON.stringify(command.cloneDoc())
success: function () { }).always(function (one, state, three) {
if (type === 'POST') { if (state !== "success") {
// POST the document already exists // an error occured
that.error(priv.createError(409, that.retry(priv.ajaxErrorToJioError(
"Cannot create a new document", "Document already exists" one,
)); "An error occured when trying to PUT data",
return; "Unknown"
}
ajax_object = {
url: url,
type: type,
data: JSON.stringify(command.getDoc()),
success: function () {
that.success({
ok: true,
id: command.getDocId()
});
},
error: function () {
that.error(priv.createError(409, "Cannot modify document",
"Error writing to remote storage"
)); ));
} } else {
}; // document updated
priv.ajax(ajax_object);
},
error: function (err) {
// Firefox returns 0 instead of 404 on CORS?
if (err.status === 404 || err.status === 0) {
ajax_object = {
url: url,
type: "PUT",
data: JSON.stringify(command.getDoc()),
success: function () {
that.success({ that.success({
ok: true, "ok": true,
id: command.getDocId() "id": doc_id
}); });
},
error: function () {
that.error(priv.createError(409,
"Cannot modify document", "Error writing to remote storage"
));
} }
};
priv.ajax(ajax_object);
} else {
// error accessing remote storage
that.error({
"status": err.status,
"statusText": err.statusText,
"error": "error",
"message": err.message,
"reason": "Failed to access remote storage"
}); });
} else {
// an error occured
that.retry(priv.ajaxErrorToJioError(
one,
"An error occured when trying to GET data",
"Unknown"
));
} }
} else {
// the document already exists
that.error(priv.createError(
405,
"Cannot create document",
"Document already exists"
));
} }
}; });
priv.ajax(ajax_object);
};
/**
* Creates a new document
* @method post
* @param {object} command The JIO command
*/
that.post = function (command) {
priv.putOrPost(command, 'POST');
}; };
/** /**
...@@ -320,7 +463,26 @@ jIO.addStorageType('dav', function (spec, my) { ...@@ -320,7 +463,26 @@ jIO.addStorageType('dav', function (spec, my) {
* @param {object} command The JIO command * @param {object} command The JIO command
*/ */
that.put = function (command) { that.put = function (command) {
priv.putOrPost(command, 'PUT'); var doc_id = command.getDocId();
priv.ajax(doc_id, undefined, "PUT", {
"dataType": "text",
"data": JSON.stringify(command.cloneDoc())
}).always(function (one, state, three) {
if (state !== "success") {
// an error occured
that.retry(priv.ajaxErrorToJioError(
one,
"Cannot update document",
"Unknown error"
));
} else {
// document updated
that.success({
"ok": true,
"id": doc_id
});
}
});
}; };
/** /**
...@@ -329,149 +491,90 @@ jIO.addStorageType('dav', function (spec, my) { ...@@ -329,149 +491,90 @@ jIO.addStorageType('dav', function (spec, my) {
* @param {object} command The JIO command * @param {object} command The JIO command
*/ */
that.putAttachment = function (command) { that.putAttachment = function (command) {
var docid = command.getDocId(), var doc = null, doc_id = command.getDocId(), attachment_id, tmp;
doc, attachment_id = command.getAttachmentId();
url, priv.ajax(doc_id, undefined, "GET").always(function (one, state, three) {
secured_docid, if (state !== "success") {
secured_attachmentid, // document not found or error
attachment_url, tmp = that.retry;
ajax_object; if (one.status === 404) {
tmp = that.error;
priv.support(docid); }
tmp(priv.ajaxErrorToJioError(
secured_docid = priv.secureDocId(docid); one,
url = priv.url + '/' + priv.underscoreFileExtenisons(secured_docid); "Cannot update document",
"Unknown error"
ajax_object = { ));
url: url + '?_=' + Date.now(), } else {
type: 'GET', try {
dataType: 'text', doc = JSON.parse(one);
success: function (response) { } catch (e) {
doc = JSON.parse(response); return that.error(priv.createError(
24,
// the document exists - update document "Cannot upload attachment",
"Document is broken"
));
}
// document health is good
doc._attachments = doc._attachments || {}; doc._attachments = doc._attachments || {};
doc._attachments[command.getAttachmentId()] = { doc._attachments[attachment_id] = {
"content_type": command.getAttachmentMimeType(), "length": command.getAttachmentLength(),
"digest": "md5-" + command.md5SumAttachmentData(), "digest": "md5-" + command.md5SumAttachmentData(),
"length": command.getAttachmentLength() "content_type": command.getAttachmentMimeType()
}; };
// put updated document data // put the attachment
ajax_object = { priv.ajax(doc_id, attachment_id, "PUT", {
url: url + '?_=' + Date.now(), "dataType": "text",
type: 'PUT', "data": command.getAttachmentData()
data: JSON.stringify(doc), }).always(function (one, state, three) {
success: function () { if (state !== "success") {
secured_attachmentid = priv.secureDocId(command.getAttachmentId()); // an error occured
attachment_url = url + '.' + that.retry(priv.ajaxErrorToJioError(
priv.underscoreFileExtenisons(secured_attachmentid); one,
ajax_object = { "An error occured when trying to PUT data",
url: attachment_url + '?_=' + Date.now(), "Unknown"
type: 'PUT', ));
data: JSON.stringify(command.getDoc()), } else {
success: function () { // update the document
priv.ajax(doc_id, undefined, "PUT", {
"dataType": "text",
"data": JSON.stringify(doc)
}).always(function (one, state, three) {
if (state !== "success") {
that.retry(priv.ajaxErrorToJioError(
one,
"An error occured when trying to PUT data",
"Unknown"
));
} else {
that.success({ that.success({
ok: true, "ok": true,
id: command.getDocId() + '/' + command.getAttachmentId() "id": doc_id,
"attachment": attachment_id
}); });
},
error: function () {
that.error(priv.createError(409,
"Cannot modify document", "Error when saving attachment"
));
return;
} }
}; });
priv.ajax(ajax_object);
},
error: function () {
that.error(priv.createError(409,
"Cannot modify document", "Error writing to remote storage"
));
return;
} }
}; });
priv.ajax(ajax_object);
},
error: function () {
// the document does not exist
that.error(priv.createError(404,
"Impossible to add attachment", "Document not found"
));
return;
} }
}; });
// see if the underlying document exists
priv.ajax(ajax_object);
}; };
/** /**
* Get a document or attachment from distant storage * Get a document
* Options:
* - {boolean} revs Add simple revision history (false by default).
* - {boolean} revs_info Add revs info (false by default).
* - {boolean} conflicts Add conflict object (false by default).
* @method get * @method get
* @param {object} command The JIO command * @param {object} command The JIO command
*/ */
that.get = function (command) { that.get = function (command) {
var docid = command.getDocId(), dav.getDocument(command.getDocId()).always(function (err, response) {
doc, if (err) {
url, if (err.status === 404) {
secured_docid, return that.error(err);
secured_attachmentid,
attachment_url,
ajax_object;
if (priv.support(docid)) {
return;
}
secured_docid = priv.secureDocId(command.getDocId());
url = priv.url + '/' + priv.underscoreFileExtenisons(secured_docid);
if (typeof command.getAttachmentId() === "string") {
secured_attachmentid = priv.secureDocId(command.getAttachmentId());
attachment_url = url + '.' + priv.underscoreFileExtenisons(
secured_attachmentid
);
// get attachment
ajax_object = {
url: attachment_url + '?_=' + Date.now(),
type: "GET",
dataType: "text",
success: function (response) {
doc = JSON.parse(response);
that.success(doc);
},
error: function () {
that.error(priv.createError(404,
"Cannot find the attachment", "Attachment does not exist"
));
} }
}; return that.retry(err);
priv.ajax(ajax_object); }
} else { return that.success(response);
// get document });
ajax_object = {
url: url + '?_=' + Date.now(),
type: "GET",
dataType: "text",
success: function (response) {
// metadata_only should not be handled by jIO, as it is a
// webDav only option, shouldn't it?
// ditto for content_only
doc = JSON.parse(response);
that.success(doc);
},
error: function () {
that.error(priv.createError(404,
"Cannot find the document", "Document does not exist"
));
}
};
priv.ajax(ajax_object);
}
}; };
/** /**
...@@ -479,7 +582,7 @@ jIO.addStorageType('dav', function (spec, my) { ...@@ -479,7 +582,7 @@ jIO.addStorageType('dav', function (spec, my) {
* @method remove * @method remove
* @param {object} command The JIO command * @param {object} command The JIO command
*/ */
that.remove = function (command) { that._remove = function (command) {
var docid = command.getDocId(), doc, url, var docid = command.getDocId(), doc, url,
secured_docid, secured_attachmentid, attachment_url, secured_docid, secured_attachmentid, attachment_url,
attachment_list = [], i, j, k = 1, deleteAttachment, ajax_object; attachment_list = [], i, j, k = 1, deleteAttachment, ajax_object;
...@@ -666,7 +769,7 @@ jIO.addStorageType('dav', function (spec, my) { ...@@ -666,7 +769,7 @@ jIO.addStorageType('dav', function (spec, my) {
// },{...} // },{...}
// ] // ]
//} //}
that.allDocs = function (command) { that._allDocs = function (command) {
var rows = [], url, var rows = [], url,
am = priv.newAsyncModule(), am = priv.newAsyncModule(),
o = {}, o = {},
...@@ -762,5 +865,6 @@ jIO.addStorageType('dav', function (spec, my) { ...@@ -762,5 +865,6 @@ jIO.addStorageType('dav', function (spec, my) {
am.call(o, 'getDocumentList'); am.call(o, 'getDocumentList');
}; };
priv.__init__(spec);
return that; return that;
}); });
\ No newline at end of file
...@@ -164,7 +164,6 @@ generateTools = function (test_namespace) { ...@@ -164,7 +164,6 @@ generateTools = function (test_namespace) {
var o = {}; var o = {};
o.t = test_namespace; o.t = test_namespace;
o.server = o.t.sandbox.useFakeServer();
o.clock = sinon.useFakeTimers(); o.clock = sinon.useFakeTimers();
o.clock.tick(base_tick); o.clock.tick(base_tick);
o.spy = basicSpyFunction; o.spy = basicSpyFunction;
...@@ -3471,7 +3470,7 @@ module ("JIO Replicate Revision Storage"); ...@@ -3471,7 +3470,7 @@ module ("JIO Replicate Revision Storage");
}] }]
}, "2"); }, "2");
}); });
/*
module ("Jio DAVStorage"); module ("Jio DAVStorage");
test ("Post", function () { test ("Post", function () {
...@@ -3479,32 +3478,97 @@ test ("Post", function () { ...@@ -3479,32 +3478,97 @@ test ("Post", function () {
var o = generateTools(this); var o = generateTools(this);
o.jio = JIO.newJio({ o.jio = JIO.newJio({
"type": "dav", "type": "dav",
"username": "davpost", "url": "https://ca-davstorage:8080",
"password": "checkpwd", "auth_type": "basic",
"url": "https://ca-davstorage:8080" "username": "admin",
"password": "pwd"
}); });
// post without id // post without id
o.spy (o, "status", 405, "Post without id"); o.server = sinon.fakeServer.create();
o.jio.post({}, o.f); o.server.respondWith(
o.clock.tick(5000); "GET",
/https:\/\/ca-davstorage:8080\/[0-9a-fA-F]{4}/,
[
404,
{"Content-Type": "text/html"},
"<h1>Document not found</h1>"
]
);
o.server.respondWith(
"PUT",
/https:\/\/ca-davstorage:8080\/[0-9a-fA-F]{4}/,
[
200,
{"Content-Type": "text/html"},
"<h1>Document updated!</h1>"
]
);
o.spy(o, "jobstatus", "done", "Post without id");
o.jio.post({}, {"max_retry": 1}, function (err, response) {
o.f.apply(arguments);
if (response) {
ok(isUuid(response.id), "Uuid should look like " +
"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx : " + response.id);
}
});
o.clock.tick(1000);
o.server.respond();
o.tick(o);
o.server.restore();
// post non empty document // post document with id
o.addFakeServerResponse("dav", "PUT", "myFile", 201, "HTML RESPONSE"); o.server = sinon.fakeServer.create();
o.spy(o, "value", {"id": "myFile", "ok": true}, o.server.respondWith(
"Create = POST non empty document"); "GET",
o.jio.post({"_id": "myFile", "title": "hello there"}, o.f); /https:\/\/ca-davstorage:8080\/http:%252F%252F100%2525_\.json/,
o.clock.tick(5000); [
404,
{"Content-Type": "text/html"},
"<h1>Document not found</h1>"
]
);
o.server.respondWith(
"PUT",
/https:\/\/ca-davstorage:8080\/http:%252F%252F100%2525_\.json/,
[
200,
{"Content-Type": "text/html"},
"<h1>Document updated!</h1>"
]
);
o.spy(o, "value", {"id": "http://100%.json", "ok": true},
"Create document with an id");
o.jio.post({
"_id": "http://100%.json",
"title": "Hello There"
}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond(); o.server.respond();
o.tick(o);
o.server.restore();
// post but document already exists (post = error!, put = ok) // post already existant file
o.answer = JSON.stringify({"_id": "myFile", "title": "hello there"}); o.server = sinon.fakeServer.create();
o.addFakeServerResponse("dav", "GET", "myFile", 200, o.answer); o.server.respondWith(
o.spy (o, "status", 409, "Post but document already exists"); "GET",
o.jio.post({"_id": "myFile", "title": "hello again"}, o.f); /https:\/\/ca-davstorage:8080\/http:%252F%252F100%2525_\.json/,
o.clock.tick(5000); [
200,
{"Content-Type": "text/plain"},
'{"_id":"doc1","title":"Hello There"}'
]
);
o.spy(o, "status", 405, "Update document previous -> 405");
o.jio.post({
"_id": "http://100%.json",
"title": "Hello There Again"
}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond(); o.server.respond();
o.tick(o);
o.server.restore();
o.jio.stop(); o.jio.stop();
}); });
...@@ -3514,36 +3578,61 @@ test ("Put", function(){ ...@@ -3514,36 +3578,61 @@ test ("Put", function(){
var o = generateTools(this); var o = generateTools(this);
o.jio = JIO.newJio({ o.jio = JIO.newJio({
"type": "dav", "type": "dav",
"username": "davput", "url": "https://ca-davstorage:8080",
"password": "checkpwd", "auth_type": "basic",
"url": "https://ca-davstorage:8080" "username": "admin",
"password": "pwd"
}); });
// put without id => id required // put without id => 20 Id Required
o.spy (o, "status", 20, "Put without id"); o.spy (o, "status", 20, "Put without id -> 20");
o.jio.put({}, o.f); o.jio.put({}, o.f);
o.clock.tick(5000); o.tick(o);
// put non empty document // put non empty document
o.addFakeServerResponse("dav", "PUT", "put1", 201, "HTML RESPONSE"); o.server = sinon.fakeServer.create();
o.spy (o, "value", {"ok": true, "id": "put1"}, o.server.respondWith(
"Create = PUT non empty document"); "PUT",
o.jio.put({"_id": "put1", "title": "myPut1"}, o.f); /https:\/\/ca-davstorage:8080\/http:%252F%252F100%2525_\.json/,
o.clock.tick(5000); [
200,
{"Content-Type": "text/html"},
"<h1>OK1</h1>"
]
);
o.spy (o, "value", {"ok": true, "id": "http://100%.json"},
"Create document");
o.jio.put({
"_id": "http://100%.json",
"title": "Hi There"
}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond(); o.server.respond();
//console.log( o.server ); o.tick(o);
//console.log( o.server.requests[0].requestHeaders ); o.server.restore();
//console.log( o.server.requests[0].responseHeaders );
// update document
// put but document already exists = update o.server = sinon.fakeServer.create();
o.answer = JSON.stringify({"_id": "put1", "title": "myPut1"}); o.server.respondWith(
o.addFakeServerResponse("dav", "GET", "put1", 200, o.answer); "PUT",
o.addFakeServerResponse("dav", "PUT", "put1", 201, "HTML RESPONSE"); /https:\/\/ca-davstorage:8080\/http:%252F%252F100%2525_\.json/,
o.spy (o, "value", {"ok": true, "id": "put1"}, "Updated the document"); [
o.jio.put({"_id": "put1", "title": "myPut2abcdedg"}, o.f); 200,
o.clock.tick(5000); {"Content-Type": "text/html"},
"<h1>OK!</h1>"
]
);
o.spy (o, "value", {"ok": true, "id": "http://100%.json"},
"Update document");
o.jio.put({
"_id": "http://100%.json",
"title": "Hi There Again"
}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond(); o.server.respond();
o.tick(o);
o.server.restore();
o.jio.stop(); o.jio.stop();
}); });
...@@ -3553,52 +3642,88 @@ test ("PutAttachment", function(){ ...@@ -3553,52 +3642,88 @@ test ("PutAttachment", function(){
var o = generateTools(this); var o = generateTools(this);
o.jio = JIO.newJio({ o.jio = JIO.newJio({
"type": "dav", "type": "dav",
"username": "davputattm", "url": "https://ca-davstorage:8080",
"password": "checkpwd", "auth_type": "basic",
"url": "https://ca-davstorage:8080" "username": "admin",
"password": "pwd"
}); });
// putAttachment without doc id => id required // putAttachment without document id => 20 Id Required
o.spy(o, "status", 20, "PutAttachment without doc id"); o.spy(o, "status", 20, "PutAttachment without doc id -> 20");
o.jio.putAttachment({}, o.f); o.jio.putAttachment({"_attachment": "body.html"}, o.f);
o.clock.tick(5000); o.tick(o);
// putAttachment without attachment id => attachment id required
o.spy(o, "status", 22, "PutAttachment without attachment id");
o.jio.putAttachment({"id": "putattmt1"}, o.f);
o.clock.tick(5000);
// putAttachment without underlying document => not found // putAttachment without attachment id => 22 Attachment Id Required
o.addFakeServerResponse("dav", "GET", "putattmtx", 22, "HTML RESPONSE"); o.spy(o, "status", 22, "PutAttachment without attachment id -> 22");
o.spy(o, "status", 22, "PutAttachment without document"); o.jio.putAttachment({"_id": "http://100%.json"}, o.f);
o.jio.putAttachment({"id": "putattmtx.putattmt2"}, o.f); o.tick(o);
o.clock.tick(5000);
o.server.respond();
// putAttachment with document without data // putAttachment without underlying document => 404 Not Found
o.answer = JSON.stringify({"_id": "putattmt1", "title": "myPutAttm1"}); o.server = sinon.fakeServer.create();
o.addFakeServerResponse("dav", "GET", "putattmt1", 200, o.answer); o.server.respondWith(
o.addFakeServerResponse("dav", "PUT", "putattmt1", 201, "HTML RESPONSE"); "GET",
o.addFakeServerResponse("dav", "PUT", "putattmt1.putattmt2", 201,"HTML"+ /https:\/\/ca-davstorage:8080\/http:%252F%252F100%2525_\.json/,
+ "RESPONSE"); [
o.spy(o, "value", {"ok": true, "id": "putattmt1/putattmt2"}, 404,
"PutAttachment with document, without data"); {"Content-Type": "text/html"},
o.jio.putAttachment({"id": "putattmt1/putattmt2"}, o.f); "<h1>Not Found</h1>"
o.clock.tick(5000); ]
);
o.spy(o, "status", 404, "PutAttachment without document -> 404");
o.jio.putAttachment({
"_id": "http://100%.json",
"_attachment": "putattmt2"
}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond(); o.server.respond();
o.tick(o);
o.server.restore();
// update attachment // upload attachment
o.answer = JSON.stringify({"_id": "putattmt1", "title": "myPutAttm1"}); o.server = sinon.fakeServer.create();
o.addFakeServerResponse("dav", "GET", "putattmt1", 200, o.answer); o.server.respondWith(
o.addFakeServerResponse("dav", "PUT", "putattmt1", 201, "HTML RESPONSE"); "GET",
o.addFakeServerResponse("dav", "PUT", "putattmt1.putattmt2", 201,"HTML"+ /https:\/\/ca-davstorage:8080\/http:%252F%252F100%2525_\.json/,
"RESPONSE"); [
o.spy(o, "value", {"ok": true, "id": "putattmt1/putattmt2"}, 200,
"Update Attachment, with data"); {"Content-Type": "text/plain"},
o.jio.putAttachment({"id": "putattmt1/putattmt2", "data": "abc"}, o.f); '{"_id":"http://100%.json","title":"Hi There!"}'
o.clock.tick(5000); ]
);
o.server.respondWith(
"PUT",
/https:\/\/ca-davstorage:8080\/http:%252F%252F100%2525_\.json.body_\.html/,
[
200,
{"Content-Type": "text/html"},
"<h1>OK!</h1>"
]
);
o.server.respondWith(
"PUT",
/https:\/\/ca-davstorage:8080\/http:%252F%252F100%2525_\.json/,
[
200,
{"Content-Type": "text/html"},
"<h1>OK!</h1>"
]
);
o.spy(o, "value", {
"ok": true,
"id": "http://100%.json",
"attachment": "body.html"
}, "Upload attachment");
o.jio.putAttachment({
"_id": "http://100%.json",
"_attachment": "body.html",
"_mimetype": "text/html",
"_data": "<h1>Hi There!!</h1><p>How are you?</p>"
}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond(); o.server.respond();
o.tick(o);
o.server.restore();
o.jio.stop(); o.jio.stop();
}); });
...@@ -3608,53 +3733,53 @@ test ("Get", function(){ ...@@ -3608,53 +3733,53 @@ test ("Get", function(){
var o = generateTools(this); var o = generateTools(this);
o.jio = JIO.newJio({ o.jio = JIO.newJio({
"type": "dav", "type": "dav",
"username": "davget", "url": "https://ca-davstorage:8080",
"password": "checkpwd", "auth_type": "basic",
"url": "https://ca-davstorage:8080" "username": "admin",
"password": "pwd"
}); });
// get inexistent document // get inexistent document
o.addFakeServerResponse("dav", "GET", "get1", 404, "HTML RESPONSE"); o.server = sinon.fakeServer.create();
o.spy(o, "status", 404, "Get non existing document"); o.server.respondWith(
o.jio.get("get1", o.f); "GET",
o.clock.tick(5000); /https:\/\/ca-davstorage:8080\/http:%252F%252F100%2525_\.json/,
o.server.respond(); [
404,
// get inexistent attachment {"Content-Type": "text/html"},
o.addFakeServerResponse("dav", "GET", "get1.get2", 404, "HTML RESPONSE"); "<h1>Not Found</h1>"
o.spy(o, "status", 404, "Get non existing attachment"); ]
o.jio.get("get1/get2", o.f); );
o.clock.tick(5000); o.spy(o, "status", 404, "Get non existing document -> 404");
o.jio.get({"_id": "http://100%.json"}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
o.server.respond(); o.server.respond();
o.tick(o);
o.server.restore();
// get document // get document
o.answer = JSON.stringify({"_id": "get3", "title": "some title"}); o.server = sinon.fakeServer.create();
o.addFakeServerResponse("dav", "GET", "get3", 200, o.answer); o.server.respondWith(
o.spy(o, "value", {"_id": "get3", "title": "some title"}, "Get document"); "GET",
o.jio.get("get3", o.f); /https:\/\/ca-davstorage:8080\/http:%252F%252F100%2525_\.json/,
o.clock.tick(5000); [
o.server.respond(); 200,
{"Content-Type": "text/html"},
// get inexistent attachment (document exists) '{"_id":"http://100%.json","title":"Hi There!"}'
o.addFakeServerResponse("dav", "GET", "get3.getx", 404, "HTML RESPONSE"); ]
o.spy(o, "status", 404, "Get non existing attachment (doc exists)"); );
o.jio.get("get3/getx", o.f); o.spy(o, "value", {"_id": "http://100%.json", "title": "Hi There!"},
o.clock.tick(5000); "Get document");
o.server.respond(); o.jio.get({"_id": "http://100%.json"}, {"max_retry": 1}, o.f);
o.clock.tick(1000);
// get attachment
o.answer = JSON.stringify({"_id": "get4", "title": "some attachment"});
o.addFakeServerResponse("dav", "GET", "get3.get4", 200, o.answer);
o.spy(o, "value", {"_id": "get4", "title": "some attachment"},
"Get attachment");
o.jio.get("get3/get4", o.f);
o.clock.tick(5000);
o.server.respond(); o.server.respond();
o.tick(o);
o.server.restore();
o.jio.stop(); o.jio.stop();
}); });
/*
test ("Remove", function(){ test ("Remove", function(){
var o = generateTools(this); var o = generateTools(this);
......
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