Commit 01e87e2c authored by Romain Courteaud's avatar Romain Courteaud

[linshare] add linshare storage

LinshareStorage uses the linshare document name as jio key.

If multiple linshare documents have the same name, only the most recent modified is used.

Thanks to Vincent Bechu for his work on this storage.
parent 8143c5a8
...@@ -141,6 +141,7 @@ ${JIOVERSION}: ${EXTERNALDIR}/URI.js \ ...@@ -141,6 +141,7 @@ ${JIOVERSION}: ${EXTERNALDIR}/URI.js \
${SRCDIR}/jio.storage/davstorage.js \ ${SRCDIR}/jio.storage/davstorage.js \
${SRCDIR}/jio.storage/gdrivestorage.js \ ${SRCDIR}/jio.storage/gdrivestorage.js \
${SRCDIR}/jio.storage/unionstorage.js \ ${SRCDIR}/jio.storage/unionstorage.js \
${SRCDIR}/jio.storage/linsharestorage.js \
${SRCDIR}/jio.storage/erp5storage.js \ ${SRCDIR}/jio.storage/erp5storage.js \
${SRCDIR}/jio.storage/querystorage.js \ ${SRCDIR}/jio.storage/querystorage.js \
${SRCDIR}/jio.storage/drivetojiomapping.js \ ${SRCDIR}/jio.storage/drivetojiomapping.js \
......
...@@ -70,6 +70,23 @@ ...@@ -70,6 +70,23 @@
} }
}); });
///////////////////////////
// Linshare storage
///////////////////////////
// return g.run({
// type: "query",
// sub_storage: {
// type: "uuid",
// sub_storage: {
// type: "linshare",
// url: "https://demo.linshare.org/",
// credential_token: window.btoa(
// 'user1@linshare.org' + ':' + 'password1'
// )
// }
// }
// });
/////////////////////////// ///////////////////////////
// WebSQL storage // WebSQL storage
/////////////////////////// ///////////////////////////
......
/*
* Copyright 2019, Nexedi SA
*
* This program is free software: you can Use, Study, Modify and Redistribute
* it under the terms of the GNU General Public License version 3, or (at your
* option) any later version, as published by the Free Software Foundation.
*
* You can also Link and Combine this program with other software covered by
* the terms of any of the Free Software licenses or any of the Open Source
* Initiative approved licenses and Convey the resulting work. Corresponding
* source of such a combination shall include the source code for all other
* software used.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See COPYING file for full licensing terms.
* See https://www.nexedi.com/licensing for rationale and options.
*/
/**
* JIO Linshare Storage. Type = "linshare".
* Linshare "database" storage.
* http://download.linshare.org/components/linshare-core/2.2.2/
* Can't set up id, implied can't put new document
*/
/*global jIO, RSVP, UriTemplate, FormData, Blob*/
/*jslint nomen: true*/
(function (jIO, RSVP, UriTemplate, FormData, Blob) {
"use strict";
function makeRequest(storage, uuid, options, download) {
if (options === undefined) {
options = {};
}
if (options.xhrFields === undefined) {
options.xhrFields = {};
}
if (options.headers === undefined) {
options.headers = {};
}
// Prefer JSON by default
if (download === true) {
options.url = storage._blob_template.expand({uuid: uuid});
options.dataType = 'blob';
} else {
options.url = storage._url_template.expand({uuid: uuid || ""});
if (!options.headers.hasOwnProperty('Accept')) {
options.headers.Accept = 'application/json';
options.dataType = 'json';
}
}
// Use cookie based auth
if (storage.hasOwnProperty('_access_token')) {
options.headers.Authorization = "Basic " + storage._access_token;
} else {
options.xhrFields.withCredentials = true;
}
return new RSVP.Queue()
.push(function () {
return jIO.util.ajax(options);
})
.push(function (event) {
if (download === true) {
return (
event.target.response ||
// sinon does not fill the response attribute
new Blob([event.target.responseText], {type: 'text/plain'})
);
}
return (
event.target.response ||
// sinon does not fill the response attribute
JSON.parse(event.target.responseText)
);
});
}
/**
* The JIO Linshare Storage extension
*
* @class LinshareStorage
* @constructor
*/
function LinshareStorage(spec) {
if (typeof spec.url !== "string" || !spec.url) {
throw new TypeError("Linshare 'url' must be a string " +
"which contains more than one character.");
}
this._url_template = UriTemplate.parse(
spec.url + '/linshare/webservice/rest/user/v2/documents/{uuid}'
);
this._blob_template = UriTemplate.parse(
spec.url + '/linshare/webservice/rest/user/v2/documents/{uuid}/download'
);
if (spec.hasOwnProperty('access_token')) {
this._access_token = spec.access_token;
}
}
var capacity_list = ['list', 'include'];
LinshareStorage.prototype.hasCapacity = function (name) {
return (capacity_list.indexOf(name) !== -1);
};
function sortByModificationDate(entry1, entry2) {
var date1 = entry1.modificationDate,
date2 = entry2.modificationDate;
return (date1 === date2) ? 0 : ((date1 < date2) ? 1 : -1);
}
function getDocumentList(storage, options) {
return makeRequest(storage, "", {
type: "GET"
})
.push(function (entry_list) {
// Linshare only allow to get the full list of documents
// First, sort the entries by modificationDate in order to
// drop the 'old' entries with the same 'name'
// (as linshare does not to update an existing doc)
entry_list.sort(sortByModificationDate);
// Only return one document per name
// Keep the newer document
var entry_dict = {},
i,
len = entry_list.length,
entry_name,
entry,
result_list = [];
for (i = 0; i < len; i += 1) {
entry_name = entry_list[i].name;
// If we only need one precise name, no need to check the others
if (!options.hasOwnProperty('only_id') ||
(options.only_id === entry_name)) {
if (!entry_dict.hasOwnProperty(entry_name)) {
entry = {
id: entry_name,
value: {},
_linshare_uuid: entry_list[i].uuid
};
if (options.include_docs === true) {
entry.doc = JSON.parse(entry_list[i].metaData) || {};
}
result_list.push(entry);
if (options.all_revision !== true) {
// If we only want to fetch 'one revision',
// ie, the latest document matching this id
entry_dict[entry_name] = null;
if (options.only_id === entry_name) {
// Document has been found, no need to check all the others
break;
}
}
}
}
}
return result_list;
});
}
LinshareStorage.prototype.buildQuery = function (options) {
return getDocumentList(this, {
include_docs: options.include_docs
});
};
LinshareStorage.prototype.get = function (id) {
// It is not possible to get a document by its name
// The only way is to list all of them, and find it manually
return getDocumentList(this, {
include_docs: true,
only_id: id
})
.push(function (result_list) {
if (result_list.length === 1) {
return result_list[0].doc;
}
throw new jIO.util.jIOError(
"Can't find document with id : " + id,
404
);
});
};
function createLinshareDocument(storage, id, doc, blob) {
var data = new FormData();
data.append('file', blob, id);
data.append('filesize', blob.size);
data.append('filename', id);
data.append('description', doc.title || doc.description || '');
data.append('metadata', jIO.util.stringify(doc));
return makeRequest(storage, '', {
type: 'POST',
data: data
});
}
LinshareStorage.prototype.put = function (id, doc) {
var storage = this;
return getDocumentList(storage, {
include_docs: true,
only_id: id
})
.push(function (result_list) {
if (result_list.length === 1) {
// Update existing document metadata
var data = {
uuid: result_list[0]._linshare_uuid,
metaData: jIO.util.stringify(doc),
name: id,
description: doc.title || doc.description || ''
};
return makeRequest(storage, result_list[0]._linshare_uuid, {
type: 'PUT',
headers: {'Content-Type': 'application/json'},
data: jIO.util.stringify(data)
});
}
// Create a new one
return createLinshareDocument(storage, id, doc, new Blob());
});
};
LinshareStorage.prototype.remove = function (id) {
var storage = this;
// Delete all entries matching the id
return getDocumentList(storage, {
only_id: id,
all_revision: true
})
.push(function (result_list) {
var promise_list = [],
i,
len = result_list.length;
for (i = 0; i < len; i += 1) {
promise_list.push(
makeRequest(storage, result_list[i]._linshare_uuid, {
type: "DELETE"
})
);
}
return RSVP.all(promise_list);
});
};
LinshareStorage.prototype.allAttachments = function (id) {
return this.get(id)
.push(function () {
return {enclosure: {}};
});
};
function restrictAttachmentId(name) {
if (name !== "enclosure") {
throw new jIO.util.jIOError(
"attachment name " + name + " is forbidden in linshare",
400
);
}
}
LinshareStorage.prototype.putAttachment = function (id, name, blob) {
restrictAttachmentId(name);
var storage = this;
return storage.get(id)
.push(function (doc) {
// Create a new document with the same id but a different blob content
return createLinshareDocument(storage, id, doc, blob);
});
};
LinshareStorage.prototype.getAttachment = function (id, name) {
restrictAttachmentId(name);
var storage = this;
// It is not possible to get a document by its name
// The only way is to list all of them, and find it manually
return getDocumentList(storage, {
only_id: id
})
.push(function (result_list) {
if (result_list.length === 1) {
return makeRequest(storage, result_list[0]._linshare_uuid, {
}, true);
}
throw new jIO.util.jIOError(
"Can't find document with id : " + id,
404
);
});
};
jIO.addStorage('linshare', LinshareStorage);
}(jIO, RSVP, UriTemplate, FormData, Blob));
/*
* Copyright 2019, Nexedi SA
*
* This program is free software: you can Use, Study, Modify and Redistribute
* it under the terms of the GNU General Public License version 3, or (at your
* option) any later version, as published by the Free Software Foundation.
*
* You can also Link and Combine this program with other software covered by
* the terms of any of the Free Software licenses or any of the Open Source
* Initiative approved licenses and Convey the resulting work. Corresponding
* source of such a combination shall include the source code for all other
* software used.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See COPYING file for full licensing terms.
* See https://www.nexedi.com/licensing for rationale and options.
*/
/*jslint nomen: true */
/*global Blob, sinon, FormData*/
(function (jIO, QUnit, Blob, sinon, FormData) {
"use strict";
var test = QUnit.test,
stop = QUnit.stop,
start = QUnit.start,
ok = QUnit.ok,
expect = QUnit.expect,
equal = QUnit.equal,
deepEqual = QUnit.deepEqual,
module = QUnit.module,
domain = "https://example.org/foo";
/////////////////////////////////////////////////////////////////
// LinshareStorage constructor
/////////////////////////////////////////////////////////////////
module("LinshareStorage.constructor");
test("create storage", function () {
var jio = jIO.createJIO({
type: "linshare",
url: "https://example.org/foo"
});
equal(jio.__type, "linshare");
deepEqual(
jio.__storage._url_template.templateText,
"https://example.org/foo/linshare/webservice/rest/user/" +
"v2/documents/{uuid}"
);
deepEqual(
jio.__storage._blob_template.templateText,
"https://example.org/foo/linshare/webservice/rest/user/" +
"v2/documents/{uuid}/download"
);
equal(jio.__storage._credential_token, undefined);
});
test("create storage store access token", function () {
var jio = jIO.createJIO({
type: "linshare",
url: "https://example.org/bar",
access_token: "azerty"
});
equal(jio.__type, "linshare");
deepEqual(
jio.__storage._url_template.templateText,
"https://example.org/bar/linshare/webservice/rest/user/" +
"v2/documents/{uuid}"
);
deepEqual(
jio.__storage._blob_template.templateText,
"https://example.org/bar/linshare/webservice/rest/user/" +
"v2/documents/{uuid}/download"
);
equal(jio.__storage._access_token, "azerty");
});
/////////////////////////////////////////////////////////////////
// LinshareStorage hasCapacity
/////////////////////////////////////////////////////////////////
module("LinshareStorage.hasCapacity", {
setup: function () {
this.jio = jIO.createJIO({
type: "linshare",
url: "https://example.org/foo"
});
}
});
test("check capacities", function () {
ok(this.jio.hasCapacity("list"));
ok(this.jio.hasCapacity("include"));
});
/////////////////////////////////////////////////////////////////
// LinshareStorage.allDocs
/////////////////////////////////////////////////////////////////
module("LinshareStorage.allDocs", {
setup: function () {
this.server = sinon.fakeServer.create();
this.server.autoRespond = true;
this.server.autoRespondAfter = 5;
this.jio = jIO.createJIO({
type: "linshare",
url: domain
});
},
teardown: function () {
this.server.restore();
delete this.server;
}
});
test("get all documents", function () {
var search_url = domain + "/linshare/webservice/rest/user/v2/documents/",
search_result = JSON.stringify([
{
uuid: 'uuid1',
name: 'foo1',
modificationDate: '2',
}, {
uuid: 'uuid2',
name: 'foo2',
modificationDate: '1',
}
]),
server = this.server;
this.server.respondWith("GET", search_url, [200, {
"Content-Type": "application/json"
}, search_result]);
stop();
expect(7);
this.jio.allDocs()
.then(function (result) {
deepEqual(result, {
data: {
rows: [{
_linshare_uuid: "uuid1",
id: "foo1",
value: {}
}, {
_linshare_uuid: "uuid2",
id: "foo2",
value: {}
}],
total_rows: 2
}
}, "Check document");
equal(server.requests.length, 1);
equal(server.requests[0].method, "GET");
equal(server.requests[0].url, search_url);
equal(server.requests[0].requestBody, undefined);
equal(server.requests[0].withCredentials, true);
deepEqual(server.requests[0].requestHeaders, {
"Accept": "application/json"
});
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
test("get all documents with access token", function () {
var search_url = domain + "/linshare/webservice/rest/user/v2/documents/",
search_result = JSON.stringify([
{
uuid: 'uuid1',
name: 'foo1',
modificationDate: '2',
}, {
uuid: 'uuid2',
name: 'foo2',
modificationDate: '1',
}
]),
server = this.server,
token = 'barfoobar';
this.server.respondWith("GET", search_url, [200, {
"Content-Type": "application/json"
}, search_result]);
stop();
expect(7);
this.jio = jIO.createJIO({
type: "linshare",
url: domain,
access_token: token
});
this.jio.allDocs()
.then(function (result) {
deepEqual(result, {
data: {
rows: [{
_linshare_uuid: "uuid1",
id: "foo1",
value: {}
}, {
_linshare_uuid: "uuid2",
id: "foo2",
value: {}
}],
total_rows: 2
}
}, "Check document");
equal(server.requests.length, 1);
equal(server.requests[0].method, "GET");
equal(server.requests[0].url, search_url);
equal(server.requests[0].requestBody, undefined);
equal(server.requests[0].withCredentials, undefined);
deepEqual(server.requests[0].requestHeaders, {
"Accept": "application/json",
"Authorization": "Basic " + token
});
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
test("get all documents and include docs", function () {
var search_url = domain + "/linshare/webservice/rest/user/v2/documents/",
search_result = JSON.stringify([
{
uuid: 'uuid1',
name: 'foo1',
modificationDate: '2',
metaData: JSON.stringify({
title: 'foo1title'
})
}, {
uuid: 'uuid2',
name: 'foo2',
modificationDate: '1',
metaData: JSON.stringify({
reference: 'foo2reference'
})
}
]),
server = this.server;
this.server.respondWith("GET", search_url, [200, {
"Content-Type": "application/json"
}, search_result]);
stop();
expect(7);
this.jio.allDocs({include_docs: true})
.then(function (result) {
deepEqual(result, {
data: {
rows: [{
_linshare_uuid: "uuid1",
id: "foo1",
value: {},
doc: {title: "foo1title"}
}, {
_linshare_uuid: "uuid2",
id: "foo2",
value: {},
doc: {reference: "foo2reference"}
}],
total_rows: 2
}
}, "Check document");
equal(server.requests.length, 1);
equal(server.requests[0].method, "GET");
equal(server.requests[0].url, search_url);
equal(server.requests[0].requestBody, undefined);
equal(server.requests[0].withCredentials, true);
deepEqual(server.requests[0].requestHeaders, {
"Accept": "application/json"
});
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
test("get all documents and keep only one doc per name", function () {
var search_url = domain + "/linshare/webservice/rest/user/v2/documents/",
search_result = JSON.stringify([
{
uuid: 'uuid1',
name: 'foo',
modificationDate: '3',
}, {
uuid: 'uuid2',
name: 'foo',
modificationDate: '2',
}, {
uuid: 'uuid3',
name: 'foo',
modificationDate: '1',
}
]),
server = this.server;
this.server.respondWith("GET", search_url, [200, {
"Content-Type": "application/json"
}, search_result]);
stop();
expect(7);
this.jio.allDocs()
.then(function (result) {
deepEqual(result, {
data: {
rows: [{
_linshare_uuid: "uuid1",
id: "foo",
value: {}
}],
total_rows: 1
}
}, "Check document");
equal(server.requests.length, 1);
equal(server.requests[0].method, "GET");
equal(server.requests[0].url, search_url);
equal(server.requests[0].requestBody, undefined);
equal(server.requests[0].withCredentials, true);
deepEqual(server.requests[0].requestHeaders, {
"Accept": "application/json"
});
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
/////////////////////////////////////////////////////////////////
// LinshareStorage.get
/////////////////////////////////////////////////////////////////
module("LinshareStorage.get", {
setup: function () {
this.server = sinon.fakeServer.create();
this.server.autoRespond = true;
this.server.autoRespondAfter = 5;
this.jio = jIO.createJIO({
type: "linshare",
url: domain
});
},
teardown: function () {
this.server.restore();
delete this.server;
}
});
test("get inexistent document", function () {
var search_url = domain + "/linshare/webservice/rest/user/v2/documents/",
search_result = JSON.stringify([
{
uuid: 'uuid1',
name: 'foo1',
modificationDate: '2',
}, {
uuid: 'uuid2',
name: 'foo2',
modificationDate: '1'
}
]),
server = this.server;
this.server.respondWith("GET", search_url, [200, {
"Content-Type": "application/json"
}, search_result]);
stop();
expect(9);
this.jio.get('foo')
.fail(function (error) {
ok(error instanceof jIO.util.jIOError);
equal(error.message, "Can't find document with id : foo");
equal(error.status_code, 404);
equal(server.requests.length, 1);
equal(server.requests[0].method, "GET");
equal(server.requests[0].url, search_url);
equal(server.requests[0].requestBody, undefined);
equal(server.requests[0].withCredentials, true);
deepEqual(server.requests[0].requestHeaders, {
"Accept": "application/json"
});
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
test("get a document", function () {
var search_url = domain + "/linshare/webservice/rest/user/v2/documents/",
search_result = JSON.stringify([
{
uuid: 'uuid1',
name: 'foo1',
modificationDate: '2',
}, {
uuid: 'uuid2',
name: 'foo2',
modificationDate: '1',
}, {
uuid: 'uuid3',
name: 'foo',
modificationDate: '3',
metaData: JSON.stringify({
title: 'foouuid3'
})
}, {
uuid: 'uuid4',
name: 'foo',
modificationDate: '2',
}, {
uuid: 'uuid5',
name: 'foo',
modificationDate: '1',
}
]),
server = this.server;
this.server.respondWith("GET", search_url, [200, {
"Content-Type": "application/json"
}, search_result]);
stop();
expect(7);
this.jio.get('foo')
.then(function (result) {
deepEqual(result, {
title: 'foouuid3'
}, "Check document");
equal(server.requests.length, 1);
equal(server.requests[0].method, "GET");
equal(server.requests[0].url, search_url);
equal(server.requests[0].requestBody, undefined);
equal(server.requests[0].withCredentials, true);
deepEqual(server.requests[0].requestHeaders, {
"Accept": "application/json"
});
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
/////////////////////////////////////////////////////////////////
// LinshareStorage.put
/////////////////////////////////////////////////////////////////
module("LinshareStorage.put", {
setup: function () {
this.server = sinon.fakeServer.create();
this.server.autoRespond = true;
this.server.autoRespondAfter = 5;
this.jio = jIO.createJIO({
type: "linshare",
url: domain
});
this.spy = sinon.spy(FormData.prototype, "append");
},
teardown: function () {
this.server.restore();
delete this.server;
this.spy.restore();
delete this.spy;
}
});
test("create a document", function () {
var search_url = domain + "/linshare/webservice/rest/user/v2/documents/",
search_result = JSON.stringify([
{
uuid: 'uuid1',
name: 'foo1',
modificationDate: '2'
}, {
uuid: 'uuid2',
name: 'foo2',
modificationDate: '1'
}
]),
server = this.server,
context = this;
this.server.respondWith("GET", search_url, [200, {
"Content-Type": "application/json"
}, search_result]);
this.server.respondWith("POST", search_url, [200, {
"Content-Type": "application/json"
}, JSON.stringify({})]);
stop();
expect(24);
this.jio.put('foo', {foo: 'bar'})
.then(function (result) {
deepEqual(result, 'foo', "Check document");
equal(server.requests.length, 2);
equal(server.requests[0].method, "GET");
equal(server.requests[0].url, search_url);
equal(server.requests[0].requestBody, undefined);
equal(server.requests[0].withCredentials, true);
deepEqual(server.requests[0].requestHeaders, {
"Accept": "application/json"
});
equal(server.requests[1].method, "POST");
equal(server.requests[1].url, search_url);
ok(server.requests[1].requestBody instanceof FormData);
equal(context.spy.callCount, 5, "FormData.append count");
equal(context.spy.firstCall.args[0], "file", "First append call");
ok(context.spy.firstCall.args[1] instanceof Blob, "First append call");
equal(context.spy.firstCall.args[2], "foo", "First append call");
equal(context.spy.secondCall.args[0], "filesize",
"Second append call");
equal(context.spy.secondCall.args[1], 0, "Second append call");
equal(context.spy.thirdCall.args[0], "filename",
"Third append call");
equal(context.spy.thirdCall.args[1], "foo", "Third append call");
equal(context.spy.getCall(3).args[0], "description",
"Fourth append call");
equal(context.spy.getCall(3).args[1], "", "Fourth append call");
equal(context.spy.getCall(4).args[0], "metadata",
"Fourth append call");
equal(context.spy.getCall(4).args[1], JSON.stringify({foo: 'bar'}),
"Fourth append call");
equal(server.requests[1].withCredentials, true);
deepEqual(server.requests[1].requestHeaders, {
"Accept": "application/json",
"Content-Type": "text/plain;charset=utf-8"
});
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
test("update a document", function () {
var search_url = domain + "/linshare/webservice/rest/user/v2/documents/",
put_url = domain + "/linshare/webservice/rest/user/v2/documents/uuid3",
search_result = JSON.stringify([
{
uuid: 'uuid1',
name: 'foo1',
modificationDate: '2'
}, {
uuid: 'uuid2',
name: 'foo2',
modificationDate: '1'
}, {
uuid: 'uuid4',
name: 'foo',
modificationDate: '2',
}, {
uuid: 'uuid5',
name: 'foo',
modificationDate: '1',
}, {
uuid: 'uuid3',
name: 'foo',
modificationDate: '3',
metaData: JSON.stringify({
title: 'foouuid3'
})
}
]),
server = this.server,
context = this;
this.server.respondWith("GET", search_url, [200, {
"Content-Type": "application/json"
}, search_result]);
this.server.respondWith("PUT", put_url, [200, {
"Content-Type": "application/json"
}, JSON.stringify({})]);
stop();
expect(13);
this.jio.put('foo', {foo: 'bar'})
.then(function (result) {
deepEqual(result, 'foo', "Check document");
equal(server.requests.length, 2);
equal(server.requests[0].method, "GET");
equal(server.requests[0].url, search_url);
equal(server.requests[0].requestBody, undefined);
equal(server.requests[0].withCredentials, true);
deepEqual(server.requests[0].requestHeaders, {
"Accept": "application/json"
});
equal(server.requests[1].method, "PUT");
equal(server.requests[1].url, put_url);
ok(
server.requests[1].requestBody,
JSON.stringify({
foo: 'bar'
})
);
equal(context.spy.callCount, 0, "FormData.append count");
equal(server.requests[1].withCredentials, true);
deepEqual(server.requests[1].requestHeaders, {
"Accept": "application/json",
"Content-Type": "application/json;charset=utf-8"
});
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
/////////////////////////////////////////////////////////////////
// LinshareStorage.remove
/////////////////////////////////////////////////////////////////
module("LinshareStorage.remove", {
setup: function () {
this.server = sinon.fakeServer.create();
this.server.autoRespond = true;
this.server.autoRespondAfter = 5;
this.jio = jIO.createJIO({
type: "linshare",
url: domain
});
},
teardown: function () {
this.server.restore();
delete this.server;
}
});
test("non existing document", function () {
var search_url = domain + "/linshare/webservice/rest/user/v2/documents/",
search_result = JSON.stringify([
{
uuid: 'uuid1',
name: 'foo1',
modificationDate: '2'
}, {
uuid: 'uuid2',
name: 'foo2',
modificationDate: '1'
}
]),
server = this.server;
this.server.respondWith("GET", search_url, [200, {
"Content-Type": "application/json"
}, search_result]);
stop();
expect(7);
this.jio.remove('foo')
.then(function (result) {
deepEqual(result, 'foo', "Check document");
equal(server.requests.length, 1);
equal(server.requests[0].method, "GET");
equal(server.requests[0].url, search_url);
equal(server.requests[0].requestBody, undefined);
equal(server.requests[0].withCredentials, true);
deepEqual(server.requests[0].requestHeaders, {
"Accept": "application/json"
});
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
test("remove a document", function () {
var search_url = domain + "/linshare/webservice/rest/user/v2/documents/",
remove_url_1 =
domain + "/linshare/webservice/rest/user/v2/documents/uuid3",
remove_url_2 =
domain + "/linshare/webservice/rest/user/v2/documents/uuid4",
remove_url_3 =
domain + "/linshare/webservice/rest/user/v2/documents/uuid5",
search_result = JSON.stringify([
{
uuid: 'uuid1',
name: 'foo1',
modificationDate: '2'
}, {
uuid: 'uuid2',
name: 'foo2',
modificationDate: '1'
}, {
uuid: 'uuid4',
name: 'foo',
modificationDate: '2',
}, {
uuid: 'uuid5',
name: 'foo',
modificationDate: '1',
}, {
uuid: 'uuid3',
name: 'foo',
modificationDate: '3',
metaData: JSON.stringify({
title: 'foouuid3'
})
}
]),
server = this.server;
this.server.respondWith("GET", search_url, [200, {
"Content-Type": "application/json"
}, search_result]);
this.server.respondWith("DELETE", remove_url_1, [200, {
"Content-Type": "application/json"
}, JSON.stringify({})]);
this.server.respondWith("DELETE", remove_url_2, [200, {
"Content-Type": "application/json"
}, JSON.stringify({})]);
this.server.respondWith("DELETE", remove_url_3, [200, {
"Content-Type": "application/json"
}, JSON.stringify({})]);
stop();
expect(22);
this.jio.remove('foo')
.then(function (result) {
deepEqual(result, 'foo', "Check document");
equal(server.requests.length, 4);
equal(server.requests[0].method, "GET");
equal(server.requests[0].url, search_url);
equal(server.requests[0].requestBody, undefined);
equal(server.requests[0].withCredentials, true);
deepEqual(server.requests[0].requestHeaders, {
"Accept": "application/json"
});
equal(server.requests[1].method, "DELETE");
equal(server.requests[1].url, remove_url_1);
equal(server.requests[1].requestBody, undefined);
equal(server.requests[1].withCredentials, true);
deepEqual(server.requests[1].requestHeaders, {
"Accept": "application/json",
"Content-Type": "text/plain;charset=utf-8"
});
equal(server.requests[2].method, "DELETE");
equal(server.requests[2].url, remove_url_2);
equal(server.requests[2].requestBody, undefined);
equal(server.requests[2].withCredentials, true);
deepEqual(server.requests[2].requestHeaders, {
"Accept": "application/json",
"Content-Type": "text/plain;charset=utf-8"
});
equal(server.requests[3].method, "DELETE");
equal(server.requests[3].url, remove_url_3);
equal(server.requests[3].requestBody, undefined);
equal(server.requests[3].withCredentials, true);
deepEqual(server.requests[3].requestHeaders, {
"Accept": "application/json",
"Content-Type": "text/plain;charset=utf-8"
});
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
/////////////////////////////////////////////////////////////////
// LinshareStorage.allAttachments
/////////////////////////////////////////////////////////////////
module("LinshareStorage.allAttachments", {
setup: function () {
this.server = sinon.fakeServer.create();
this.server.autoRespond = true;
this.server.autoRespondAfter = 5;
this.jio = jIO.createJIO({
type: "linshare",
url: domain
});
},
teardown: function () {
this.server.restore();
delete this.server;
}
});
test("non existing document", function () {
var search_url = domain + "/linshare/webservice/rest/user/v2/documents/",
search_result = JSON.stringify([
{
uuid: 'uuid1',
name: 'foo1',
modificationDate: '2'
}, {
uuid: 'uuid2',
name: 'foo2',
modificationDate: '1'
}
]),
server = this.server;
this.server.respondWith("GET", search_url, [200, {
"Content-Type": "application/json"
}, search_result]);
stop();
expect(9);
this.jio.allAttachments('foo')
.fail(function (error) {
ok(error instanceof jIO.util.jIOError);
equal(error.message, "Can't find document with id : foo");
equal(error.status_code, 404);
equal(server.requests.length, 1);
equal(server.requests[0].method, "GET");
equal(server.requests[0].url, search_url);
equal(server.requests[0].requestBody, undefined);
equal(server.requests[0].withCredentials, true);
deepEqual(server.requests[0].requestHeaders, {
"Accept": "application/json"
});
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
test("existing document", function () {
var search_url = domain + "/linshare/webservice/rest/user/v2/documents/",
search_result = JSON.stringify([
{
uuid: 'uuid1',
name: 'foo1',
modificationDate: '2'
}, {
uuid: 'uuid2',
name: 'foo2',
modificationDate: '1'
}, {
uuid: 'uuid4',
name: 'foo',
modificationDate: '2',
}, {
uuid: 'uuid5',
name: 'foo',
modificationDate: '1',
}, {
uuid: 'uuid3',
name: 'foo',
modificationDate: '3',
metaData: JSON.stringify({
title: 'foouuid3'
})
}
]),
server = this.server;
this.server.respondWith("GET", search_url, [200, {
"Content-Type": "application/json"
}, search_result]);
stop();
expect(7);
this.jio.allAttachments('foo')
.then(function (result) {
deepEqual(result, {enclosure: {}}, "Check document");
equal(server.requests.length, 1);
equal(server.requests[0].method, "GET");
equal(server.requests[0].url, search_url);
equal(server.requests[0].requestBody, undefined);
equal(server.requests[0].withCredentials, true);
deepEqual(server.requests[0].requestHeaders, {
"Accept": "application/json"
});
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
/////////////////////////////////////////////////////////////////
// LinshareStorage.putAttachment
/////////////////////////////////////////////////////////////////
module("LinshareStorage.putAttachment", {
setup: function () {
this.server = sinon.fakeServer.create();
this.server.autoRespond = true;
this.server.autoRespondAfter = 5;
this.jio = jIO.createJIO({
type: "linshare",
url: domain
});
this.spy = sinon.spy(FormData.prototype, "append");
},
teardown: function () {
this.server.restore();
delete this.server;
this.spy.restore();
delete this.spy;
}
});
test("forbidden attachment", function () {
var server = this.server;
stop();
expect(4);
this.jio.putAttachment('foo', 'bar', new Blob())
.fail(function (error) {
ok(error instanceof jIO.util.jIOError);
equal(error.message, "attachment name bar is forbidden in linshare");
equal(error.status_code, 400);
equal(server.requests.length, 0);
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
test("non existing document", function () {
var search_url = domain + "/linshare/webservice/rest/user/v2/documents/",
search_result = JSON.stringify([
{
uuid: 'uuid1',
name: 'foo1',
modificationDate: '2'
}, {
uuid: 'uuid2',
name: 'foo2',
modificationDate: '1'
}
]),
server = this.server;
this.server.respondWith("GET", search_url, [200, {
"Content-Type": "application/json"
}, search_result]);
stop();
expect(9);
this.jio.putAttachment('foo', 'enclosure', new Blob())
.fail(function (error) {
ok(error instanceof jIO.util.jIOError);
equal(error.message, "Can't find document with id : foo");
equal(error.status_code, 404);
equal(server.requests.length, 1);
equal(server.requests[0].method, "GET");
equal(server.requests[0].url, search_url);
equal(server.requests[0].requestBody, undefined);
equal(server.requests[0].withCredentials, true);
deepEqual(server.requests[0].requestHeaders, {
"Accept": "application/json"
});
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
test("update a document", function () {
var search_url = domain + "/linshare/webservice/rest/user/v2/documents/",
search_result = JSON.stringify([
{
uuid: 'uuid1',
name: 'foo1',
modificationDate: '2'
}, {
uuid: 'uuid2',
name: 'foo2',
modificationDate: '1'
}, {
uuid: 'uuid4',
name: 'foo',
modificationDate: '2',
}, {
uuid: 'uuid5',
name: 'foo',
modificationDate: '1',
}, {
uuid: 'uuid3',
name: 'foo',
modificationDate: '3',
metaData: JSON.stringify({
title: 'foouuid3'
})
}
]),
server = this.server,
context = this,
blob = new Blob(['barfoo']);
this.server.respondWith("GET", search_url, [200, {
"Content-Type": "application/json"
}, search_result]);
this.server.respondWith("POST", search_url, [200, {
"Content-Type": "application/json"
}, JSON.stringify({})]);
stop();
expect(24);
this.jio.putAttachment('foo', 'enclosure', blob)
.then(function (result) {
deepEqual(result, {}, "Check document");
equal(server.requests.length, 2);
equal(server.requests[0].method, "GET");
equal(server.requests[0].url, search_url);
equal(server.requests[0].requestBody, undefined);
equal(server.requests[0].withCredentials, true);
deepEqual(server.requests[0].requestHeaders, {
"Accept": "application/json"
});
equal(server.requests[1].method, "POST");
equal(server.requests[1].url, search_url);
ok(server.requests[1].requestBody instanceof FormData);
equal(context.spy.callCount, 5, "FormData.append count");
equal(context.spy.firstCall.args[0], "file", "First append call");
equal(context.spy.firstCall.args[1], blob, "First append call");
equal(context.spy.firstCall.args[2], "foo", "First append call");
equal(context.spy.secondCall.args[0], "filesize",
"Second append call");
equal(context.spy.secondCall.args[1], blob.size, "Second append call");
equal(context.spy.thirdCall.args[0], "filename",
"Third append call");
equal(context.spy.thirdCall.args[1], "foo", "Third append call");
equal(context.spy.getCall(3).args[0], "description",
"Fourth append call");
equal(context.spy.getCall(3).args[1], "foouuid3", "Fourth append call");
equal(context.spy.getCall(4).args[0], "metadata",
"Fourth append call");
equal(context.spy.getCall(4).args[1],
JSON.stringify({title: 'foouuid3'}),
"Fourth append call");
equal(server.requests[1].withCredentials, true);
deepEqual(server.requests[1].requestHeaders, {
"Accept": "application/json",
"Content-Type": "text/plain;charset=utf-8"
});
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
/////////////////////////////////////////////////////////////////
// LinshareStorage.getAttachment
/////////////////////////////////////////////////////////////////
module("LinshareStorage.getAttachment", {
setup: function () {
this.server = sinon.fakeServer.create();
this.server.autoRespond = true;
this.server.autoRespondAfter = 5;
this.jio = jIO.createJIO({
type: "linshare",
url: domain
});
},
teardown: function () {
this.server.restore();
delete this.server;
}
});
test("forbidden attachment", function () {
var server = this.server;
stop();
expect(4);
this.jio.getAttachment('foo', 'bar')
.fail(function (error) {
ok(error instanceof jIO.util.jIOError);
equal(error.message, "attachment name bar is forbidden in linshare");
equal(error.status_code, 400);
equal(server.requests.length, 0);
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
test("non existing document", function () {
var search_url = domain + "/linshare/webservice/rest/user/v2/documents/",
search_result = JSON.stringify([
{
uuid: 'uuid1',
name: 'foo1',
modificationDate: '2'
}, {
uuid: 'uuid2',
name: 'foo2',
modificationDate: '1'
}
]),
server = this.server;
this.server.respondWith("GET", search_url, [200, {
"Content-Type": "application/json"
}, search_result]);
stop();
expect(9);
this.jio.getAttachment('foo', 'enclosure')
.fail(function (error) {
ok(error instanceof jIO.util.jIOError);
equal(error.message, "Can't find document with id : foo");
equal(error.status_code, 404);
equal(server.requests.length, 1);
equal(server.requests[0].method, "GET");
equal(server.requests[0].url, search_url);
equal(server.requests[0].requestBody, undefined);
equal(server.requests[0].withCredentials, true);
deepEqual(server.requests[0].requestHeaders, {
"Accept": "application/json"
});
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
test("retrieve a document", function () {
var search_url = domain + "/linshare/webservice/rest/user/v2/documents/",
search_result = JSON.stringify([
{
uuid: 'uuid1',
name: 'foo1',
modificationDate: '2'
}, {
uuid: 'uuid2',
name: 'foo2',
modificationDate: '1'
}, {
uuid: 'uuid4',
name: 'foo',
modificationDate: '2',
}, {
uuid: 'uuid5',
name: 'foo',
modificationDate: '1',
}, {
uuid: 'uuid3',
name: 'foo',
modificationDate: '3',
metaData: JSON.stringify({
title: 'foouuid3'
})
}
]),
download_url =
domain + "/linshare/webservice/rest/user/v2/documents/uuid3/download",
server = this.server;
this.server.respondWith("GET", search_url, [200, {
"Content-Type": "application/json"
}, search_result]);
this.server.respondWith("GET", download_url, [200, {
"Content-Type": "text/plain"
}, "foo\nbaré"]);
stop();
expect(14);
this.jio.getAttachment('foo', 'enclosure')
.then(function (result) {
equal(server.requests.length, 2);
equal(server.requests[0].method, "GET");
equal(server.requests[0].url, search_url);
equal(server.requests[0].requestBody, undefined);
equal(server.requests[0].withCredentials, true);
deepEqual(server.requests[0].requestHeaders, {
"Accept": "application/json"
});
equal(server.requests[1].method, "GET");
equal(server.requests[1].url, download_url);
equal(server.requests[1].requestBody, undefined);
equal(server.requests[1].withCredentials, true);
deepEqual(server.requests[1].requestHeaders, {});
ok(result instanceof Blob, "Data is Blob");
deepEqual(result.type, "text/plain", "Check mimetype");
return jIO.util.readBlobAsText(result);
})
.then(function (result) {
var expected = "foo\nbaré";
equal(result.target.result, expected, "Attachment correctly fetched");
})
.fail(function (error) {
ok(false, error);
})
.always(function () {
start();
});
});
}(jIO, QUnit, Blob, sinon, FormData));
...@@ -55,6 +55,7 @@ See https://www.nexedi.com/licensing for rationale and options. ...@@ -55,6 +55,7 @@ See https://www.nexedi.com/licensing for rationale and options.
<script src="jio.storage/davstorage.tests.js"></script> <script src="jio.storage/davstorage.tests.js"></script>
<script src="jio.storage/drivetojiomapping.tests.js"></script> <script src="jio.storage/drivetojiomapping.tests.js"></script>
<script src="jio.storage/unionstorage.tests.js"></script> <script src="jio.storage/unionstorage.tests.js"></script>
<script src="jio.storage/linsharestorage.tests.js"></script>
<script src="jio.storage/erp5storage.tests.js"></script> <script src="jio.storage/erp5storage.tests.js"></script>
<script src="jio.storage/indexeddbstorage.tests.js"></script> <script src="jio.storage/indexeddbstorage.tests.js"></script>
<script src="jio.storage/uuidstorage.tests.js"></script> <script src="jio.storage/uuidstorage.tests.js"></script>
......
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