Commit d00c7a79 authored by Vincent Bechu's avatar Vincent Bechu

[erp5_core] Release Jio 3.22.1

/reviewed-on nexedi/erp5!409
parent c176ff4a
......@@ -5716,7 +5716,7 @@ case 5: case 8: case 11: case 14: case 16:
this.$ = $$[$0];
break;
case 6:
this.$ = mkComplexQuery('OR', [$$[$0-1], $$[$0]]);
this.$ = mkComplexQuery('AND', [$$[$0-1], $$[$0]]);
break;
case 7:
this.$ = mkComplexQuery('OR', [$$[$0-2], $$[$0]]);
......@@ -6683,8 +6683,8 @@ return new Parser;
return new RegExp("^" + stringEscapeRegexpCharacters(string) + "$");
}
return new RegExp("^" + stringEscapeRegexpCharacters(string)
.replace(regexp_percent, '.*')
.replace(regexp_underscore, '.') + "$");
.replace(regexp_percent, '[\\s\\S]*')
.replace(regexp_underscore, '.') + "$", "i");
}
/**
......@@ -6985,7 +6985,8 @@ return new Parser;
matchMethod = null,
operator = this.operator,
value = null,
key = this.key;
key = this.key,
k;
if (!(regexp_comparaison.test(operator))) {
// `operator` is not correct, we have to change it to "like" or "="
......@@ -7004,6 +7005,22 @@ return new Parser;
key = this._key_schema.key_set[key];
}
// match with all the fields if key is empty
if (key === '') {
matchMethod = this.like;
value = '%' + this.value + '%';
for (k in item) {
if (item.hasOwnProperty(k)) {
if (k !== '__id' && item[k]) {
if (matchMethod(item[k], value) === true) {
return true;
}
}
}
}
return false;
}
if (typeof key === 'object') {
checkKey(key);
object_value = item[key.read_from];
......@@ -8428,6 +8445,15 @@ return new Parser;
CONFLICT_KEEP_REMOTE = 2,
CONFLICT_CONTINUE = 3;
function SkipError(message) {
if ((message !== undefined) && (typeof message !== "string")) {
throw new TypeError('You must pass a string.');
}
this.message = message || "Skip some asynchronous code";
}
SkipError.prototype = new Error();
SkipError.prototype.constructor = SkipError;
/****************************************************
Use a local jIO to read/write/search documents
Synchronize in background those document with a remote jIO.
......@@ -8446,20 +8472,33 @@ return new Parser;
function ReplicateStorage(spec) {
this._query_options = spec.query || {};
if (spec.signature_hash_key !== undefined) {
this._query_options.select_list = [spec.signature_hash_key];
}
this._signature_hash_key = spec.signature_hash_key;
this._local_sub_storage = jIO.createJIO(spec.local_sub_storage);
this._remote_sub_storage = jIO.createJIO(spec.remote_sub_storage);
if (spec.hasOwnProperty('signature_sub_storage')) {
this._signature_sub_storage = jIO.createJIO(spec.signature_sub_storage);
this._custom_signature_sub_storage = true;
} else {
this._signature_hash = "_replicate_" + generateHash(
stringify(spec.local_sub_storage) +
stringify(spec.remote_sub_storage) +
stringify(this._query_options)
);
this._signature_sub_storage = jIO.createJIO({
type: "query",
sub_storage: {
type: "document",
document_id: this._signature_hash,
sub_storage: spec.signature_storage || spec.local_sub_storage
sub_storage: spec.local_sub_storage
}
});
this._custom_signature_sub_storage = false;
}
this._use_remote_post = spec.use_remote_post || false;
// Number of request we allow browser execution for attachments
......@@ -8602,15 +8641,8 @@ return new Parser;
arguments);
};
ReplicateStorage.prototype.repair = function () {
var context = this,
argument_list = arguments,
skip_document_dict = {};
// Do not sync the signature document
skip_document_dict[context._signature_hash] = null;
function dispatchQueue(function_used, argument_list, number_queue) {
function dispatchQueue(context, function_used, argument_list,
number_queue) {
var result_promise_list = [],
i;
......@@ -8637,7 +8669,27 @@ return new Parser;
return result_promise_list[0];
}
function propagateAttachmentDeletion(skip_attachment_dict,
function callAllDocsOnStorage(context, storage, cache, cache_key) {
return new RSVP.Queue()
.push(function () {
if (!cache.hasOwnProperty(cache_key)) {
return storage.allDocs(context._query_options)
.push(function (result) {
var i,
cache_entry = {};
for (i = 0; i < result.data.total_rows; i += 1) {
cache_entry[result.data.rows[i].id] = result.data.rows[i].value;
}
cache[cache_key] = cache_entry;
});
}
})
.push(function () {
return cache[cache_key];
});
}
function propagateAttachmentDeletion(context, skip_attachment_dict,
destination,
id, name) {
return destination.removeAttachment(id, name)
......@@ -8649,7 +8701,7 @@ return new Parser;
});
}
function propagateAttachmentModification(skip_attachment_dict,
function propagateAttachmentModification(context, skip_attachment_dict,
destination,
blob, hash, id, name) {
return destination.putAttachment(id, name, blob)
......@@ -8664,7 +8716,8 @@ return new Parser;
});
}
function checkAndPropagateAttachment(skip_attachment_dict,
function checkAndPropagateAttachment(context,
skip_attachment_dict,
status_hash, local_hash, blob,
source, destination, id, name,
conflict_force, conflict_revert,
......@@ -8694,7 +8747,7 @@ return new Parser;
// Deleted on both side, drop signature
return context._signature_sub_storage.removeAttachment(id, name)
.push(function () {
skip_attachment_dict[id] = null;
skip_attachment_dict[name] = null;
});
}
......@@ -8703,7 +8756,7 @@ return new Parser;
hash: local_hash
}))
.push(function () {
skip_document_dict[id] = null;
skip_attachment_dict[name] = null;
});
}
......@@ -8711,11 +8764,12 @@ return new Parser;
// Modified only locally. No conflict or force
if (local_hash === null) {
// Deleted locally
return propagateAttachmentDeletion(skip_attachment_dict,
return propagateAttachmentDeletion(context, skip_attachment_dict,
destination,
id, name);
}
return propagateAttachmentModification(skip_attachment_dict,
return propagateAttachmentModification(context,
skip_attachment_dict,
destination, blob,
local_hash, id, name);
}
......@@ -8729,10 +8783,11 @@ return new Parser;
// Automatically resolve conflict or force revert
if (remote_hash === null) {
// Deleted remotely
return propagateAttachmentDeletion(skip_attachment_dict,
return propagateAttachmentDeletion(context, skip_attachment_dict,
source, id, name);
}
return propagateAttachmentModification(
context,
skip_attachment_dict,
source,
remote_blob,
......@@ -8745,7 +8800,8 @@ return new Parser;
// Minimize conflict if it can be resolved
if (remote_hash === null) {
// Copy remote modification remotely
return propagateAttachmentModification(skip_attachment_dict,
return propagateAttachmentModification(context,
skip_attachment_dict,
destination, blob,
local_hash, id, name);
}
......@@ -8756,7 +8812,8 @@ return new Parser;
});
}
function checkAttachmentSignatureDifference(queue, skip_attachment_dict,
function checkAttachmentSignatureDifference(queue, context,
skip_attachment_dict,
source,
destination, id, name,
conflict_force,
......@@ -8798,7 +8855,8 @@ return new Parser;
local_hash = generateHashFromArrayBuffer(array_buffer);
if (local_hash !== status_hash) {
return checkAndPropagateAttachment(skip_attachment_dict,
return checkAndPropagateAttachment(context,
skip_attachment_dict,
status_hash, local_hash, blob,
source, destination, id, name,
conflict_force, conflict_revert,
......@@ -8807,7 +8865,8 @@ return new Parser;
});
}
function checkAttachmentLocalDeletion(queue, skip_attachment_dict,
function checkAttachmentLocalDeletion(queue, context,
skip_attachment_dict,
destination, id, name, source,
conflict_force, conflict_revert,
conflict_ignore) {
......@@ -8819,7 +8878,8 @@ return new Parser;
})
.push(function (result) {
status_hash = result.hash;
return checkAndPropagateAttachment(skip_attachment_dict,
return checkAndPropagateAttachment(context,
skip_attachment_dict,
status_hash, null, null,
source, destination, id, name,
conflict_force, conflict_revert,
......@@ -8827,24 +8887,13 @@ return new Parser;
});
}
function pushDocumentAttachment(skip_attachment_dict, id, source,
destination, options) {
var queue = new RSVP.Queue(),
local_dict = {},
function pushDocumentAttachment(context,
skip_attachment_dict, id, source,
destination, signature_allAttachments,
options) {
var local_dict = {},
signature_dict = {};
return queue
.push(function () {
return RSVP.all([
source.allAttachments(id)
.push(undefined, function (error) {
if ((error instanceof jIO.util.jIOError) &&
(error.status_code === 404)) {
return {};
}
throw error;
}),
context._signature_sub_storage.allAttachments(id)
return source.allAttachments(id)
.push(undefined, function (error) {
if ((error instanceof jIO.util.jIOError) &&
(error.status_code === 404)) {
......@@ -8852,22 +8901,20 @@ return new Parser;
}
throw error;
})
]);
})
.push(function (result_list) {
.push(function (source_allAttachments) {
var is_modification,
is_creation,
key,
argument_list = [];
for (key in result_list[0]) {
if (result_list[0].hasOwnProperty(key)) {
for (key in source_allAttachments) {
if (source_allAttachments.hasOwnProperty(key)) {
if (!skip_attachment_dict.hasOwnProperty(key)) {
local_dict[key] = null;
}
}
}
for (key in result_list[1]) {
if (result_list[1].hasOwnProperty(key)) {
for (key in signature_allAttachments) {
if (signature_allAttachments.hasOwnProperty(key)) {
if (!skip_attachment_dict.hasOwnProperty(key)) {
signature_dict[key] = null;
}
......@@ -8882,6 +8929,7 @@ return new Parser;
&& options.check_creation;
if (is_modification === true || is_creation === true) {
argument_list.push([undefined,
context,
skip_attachment_dict,
source,
destination, id, key,
......@@ -8894,6 +8942,7 @@ return new Parser;
}
}
return dispatchQueue(
context,
checkAttachmentSignatureDifference,
argument_list,
context._parallel_operation_attachment_amount
......@@ -8906,6 +8955,7 @@ return new Parser;
if (signature_dict.hasOwnProperty(key)) {
if (!local_dict.hasOwnProperty(key)) {
argument_list.push([undefined,
context,
skip_attachment_dict,
destination, id, key,
source,
......@@ -8916,6 +8966,7 @@ return new Parser;
}
}
return dispatchQueue(
context,
checkAttachmentLocalDeletion,
argument_list,
context._parallel_operation_attachment_amount
......@@ -8924,19 +8975,215 @@ return new Parser;
});
}
function propagateFastAttachmentDeletion(queue, id, name, storage) {
return queue
.push(function () {
return storage.removeAttachment(id, name);
});
}
function propagateFastAttachmentModification(queue, id, key, source,
destination, signature, hash) {
return queue
.push(function () {
return signature.getAttachment(id, key, {format: 'json'})
.push(undefined, function (error) {
if ((error instanceof jIO.util.jIOError) &&
(error.status_code === 404)) {
return {hash: null};
}
throw error;
})
.push(function (result) {
if (result.hash !== hash) {
return source.getAttachment(id, key)
.push(function (blob) {
return destination.putAttachment(id, key, blob);
})
.push(function () {
return signature.putAttachment(id, key, JSON.stringify({
hash: hash
}));
});
}
});
});
}
function repairFastDocumentAttachment(context, id,
signature_hash,
signature_attachment_hash,
signature_from_local) {
if (signature_hash === signature_attachment_hash) {
// No replication to do
return;
}
return new RSVP.Queue()
.push(function () {
return RSVP.all([
context._signature_sub_storage.allAttachments(id),
context._local_sub_storage.allAttachments(id),
context._remote_sub_storage.allAttachments(id)
]);
})
.push(function (result_list) {
var key,
source_attachment_dict,
destination_attachment_dict,
source,
destination,
push_argument_list = [],
delete_argument_list = [],
signature_attachment_dict = result_list[0],
local_attachment_dict = result_list[1],
remote_attachment_list = result_list[2],
check_local_modification =
context._check_local_attachment_modification,
check_local_creation = context._check_local_attachment_creation,
check_local_deletion = context._check_local_attachment_deletion,
check_remote_modification =
context._check_remote_attachment_modification,
check_remote_creation = context._check_remote_attachment_creation,
check_remote_deletion = context._check_remote_attachment_deletion;
if (signature_from_local) {
source_attachment_dict = local_attachment_dict;
destination_attachment_dict = remote_attachment_list;
source = context._local_sub_storage;
destination = context._remote_sub_storage;
} else {
source_attachment_dict = remote_attachment_list;
destination_attachment_dict = local_attachment_dict;
source = context._remote_sub_storage;
destination = context._local_sub_storage;
check_local_modification = check_remote_modification;
check_local_creation = check_remote_creation;
check_local_deletion = check_remote_deletion;
check_remote_creation = check_local_creation;
check_remote_deletion = check_local_deletion;
}
// Push all source attachments
for (key in source_attachment_dict) {
if (source_attachment_dict.hasOwnProperty(key)) {
if ((check_local_creation &&
!signature_attachment_dict.hasOwnProperty(key)) ||
(check_local_modification &&
signature_attachment_dict.hasOwnProperty(key))) {
push_argument_list.push([
undefined,
id,
key,
source,
destination,
context._signature_sub_storage,
signature_hash
]);
}
}
}
// Delete remaining signature + remote attachments
for (key in signature_attachment_dict) {
if (signature_attachment_dict.hasOwnProperty(key)) {
if (check_local_deletion &&
!source_attachment_dict.hasOwnProperty(key)) {
delete_argument_list.push([
undefined,
id,
key,
context._signature_sub_storage
]);
}
}
}
for (key in destination_attachment_dict) {
if (destination_attachment_dict.hasOwnProperty(key)) {
if (!source_attachment_dict.hasOwnProperty(key)) {
if ((check_local_deletion &&
signature_attachment_dict.hasOwnProperty(key)) ||
(check_remote_creation &&
!signature_attachment_dict.hasOwnProperty(key))) {
delete_argument_list.push([
undefined,
id,
key,
destination
]);
}
}
}
}
return RSVP.all([
dispatchQueue(
context,
propagateFastAttachmentModification,
push_argument_list,
context._parallel_operation_attachment_amount
),
dispatchQueue(
context,
propagateFastAttachmentDeletion,
delete_argument_list,
context._parallel_operation_attachment_amount
)
]);
})
.push(function () {
// Mark that all attachments have been synchronized
return context._signature_sub_storage.put(id, {
hash: signature_hash,
attachment_hash: signature_hash,
from_local: signature_from_local
});
});
}
function repairDocumentAttachment(context, id, signature_hash_key,
signature_hash,
signature_attachment_hash,
signature_from_local) {
if (signature_hash_key !== undefined) {
return repairFastDocumentAttachment(context, id,
signature_hash,
signature_attachment_hash,
signature_from_local);
}
function repairDocumentAttachment(id) {
var skip_attachment_dict = {};
return new RSVP.Queue()
.push(function () {
if (context._check_local_attachment_modification ||
context._check_local_attachment_creation ||
context._check_local_attachment_deletion ||
context._check_remote_attachment_modification ||
context._check_remote_attachment_creation ||
context._check_remote_attachment_deletion) {
return context._signature_sub_storage.allAttachments(id);
}
return {};
})
.push(undefined, function (error) {
if ((error instanceof jIO.util.jIOError) &&
(error.status_code === 404)) {
return {};
}
throw error;
})
.push(function (signature_allAttachments) {
if (context._check_local_attachment_modification ||
context._check_local_attachment_creation ||
context._check_local_attachment_deletion) {
return pushDocumentAttachment(
context,
skip_attachment_dict,
id,
context._local_sub_storage,
context._remote_sub_storage,
signature_allAttachments,
{
conflict_force: (context._conflict_handling ===
CONFLICT_KEEP_LOCAL),
......@@ -8949,18 +9196,24 @@ return new Parser;
check_creation: context._check_local_attachment_creation,
check_deletion: context._check_local_attachment_deletion
}
);
)
.push(function () {
return signature_allAttachments;
});
}
return signature_allAttachments;
})
.push(function () {
.push(function (signature_allAttachments) {
if (context._check_remote_attachment_modification ||
context._check_remote_attachment_creation ||
context._check_remote_attachment_deletion) {
return pushDocumentAttachment(
context,
skip_attachment_dict,
id,
context._remote_sub_storage,
context._local_sub_storage,
signature_allAttachments,
{
use_revert_post: context._use_remote_post,
conflict_force: (context._conflict_handling ===
......@@ -8979,16 +9232,39 @@ return new Parser;
});
}
function propagateModification(source, destination, doc, hash, id,
function propagateModification(context, source, destination, doc, hash, id,
skip_document_dict,
skip_deleted_document_dict,
options) {
var result,
var result = new RSVP.Queue(),
post_id,
to_skip = true;
to_skip = true,
from_local;
if (options === undefined) {
options = {};
}
from_local = options.from_local;
if (doc === null) {
result
.push(function () {
return source.get(id);
})
.push(function (source_doc) {
doc = source_doc;
}, function (error) {
if ((error instanceof jIO.util.jIOError) &&
(error.status_code === 404)) {
throw new SkipError(id);
}
throw error;
});
}
if (options.use_post) {
result = destination.post(doc)
result
.push(function () {
return destination.post(doc);
})
.push(function (new_id) {
to_skip = false;
post_id = new_id;
......@@ -9030,17 +9306,30 @@ return new Parser;
.push(function () {
to_skip = true;
return context._signature_sub_storage.put(post_id, {
"hash": hash
hash: hash,
from_local: from_local
});
})
.push(function () {
skip_document_dict[post_id] = null;
});
} else {
result = destination.put(id, doc)
result
.push(function () {
// Drop signature if the destination document was empty
// but a signature exists
if (options.create_new_document === true) {
delete skip_deleted_document_dict[id];
return context._signature_sub_storage.remove(id);
}
})
.push(function () {
return destination.put(id, doc);
})
.push(function () {
return context._signature_sub_storage.put(id, {
"hash": hash
hash: hash,
from_local: from_local
});
});
}
......@@ -9049,15 +9338,29 @@ return new Parser;
if (to_skip) {
skip_document_dict[id] = null;
}
})
.push(undefined, function (error) {
if (error instanceof SkipError) {
return;
}
throw error;
});
}
function propagateDeletion(destination, id) {
function propagateDeletion(context, destination, id, skip_document_dict,
skip_deleted_document_dict) {
// Do not delete a document if it has an attachment
// ie, replication should prevent losing user data
// Synchronize attachments before, to ensure
// all of them will be deleted too
return repairDocumentAttachment(id)
var result;
if (context._signature_hash_key !== undefined) {
result = destination.remove(id)
.push(function () {
return context._signature_sub_storage.remove(id);
});
} else {
result = repairDocumentAttachment(context, id)
.push(function () {
return destination.allAttachments(id);
})
......@@ -9074,17 +9377,37 @@ return new Parser;
return;
}
throw error;
})
});
}
return result
.push(function () {
skip_document_dict[id] = null;
// No need to sync attachment twice on this document
skip_deleted_document_dict[id] = null;
});
}
function checkAndPropagate(status_hash, local_hash, doc,
function checkAndPropagate(context, skip_document_dict,
skip_deleted_document_dict,
cache, destination_key,
status_hash, local_hash, doc,
source, destination, id,
conflict_force, conflict_revert,
conflict_ignore,
options) {
var from_local = options.from_local;
return new RSVP.Queue()
.push(function () {
if (options.signature_hash_key !== undefined) {
return callAllDocsOnStorage(context, destination,
cache, destination_key)
.push(function (result) {
if (result.hasOwnProperty(id)) {
return [null, result[id][options.signature_hash_key]];
}
return [null, null];
});
}
return destination.get(id)
.push(function (remote_doc) {
return [remote_doc, generateHash(stringify(remote_doc))];
......@@ -9094,11 +9417,12 @@ return new Parser;
return [null, null];
}
throw error;
});
})
.push(function (remote_list) {
var remote_doc = remote_list[0],
remote_hash = remote_list[1];
if (local_hash === remote_hash) {
// Same modifications on both side
if (local_hash === null) {
......@@ -9110,7 +9434,8 @@ return new Parser;
}
return context._signature_sub_storage.put(id, {
"hash": local_hash
hash: local_hash,
from_local: from_local
})
.push(function () {
skip_document_dict[id] = null;
......@@ -9121,12 +9446,20 @@ return new Parser;
// Modified only locally. No conflict or force
if (local_hash === null) {
// Deleted locally
return propagateDeletion(destination, id);
return propagateDeletion(context, destination, id,
skip_document_dict,
skip_deleted_document_dict);
}
return propagateModification(source, destination, doc,
local_hash, id,
return propagateModification(context, source, destination, doc,
local_hash, id, skip_document_dict,
skip_deleted_document_dict,
{use_post: ((options.use_post) &&
(remote_hash === null))});
(remote_hash === null)),
from_local: from_local,
create_new_document:
((remote_hash === null) &&
(status_hash !== null))
});
}
// Conflict cases
......@@ -9138,34 +9471,50 @@ return new Parser;
// Automatically resolve conflict or force revert
if (remote_hash === null) {
// Deleted remotely
return propagateDeletion(source, id);
return propagateDeletion(context, source, id, skip_document_dict,
skip_deleted_document_dict);
}
return propagateModification(
context,
destination,
source,
remote_doc,
remote_hash,
id,
skip_document_dict,
skip_deleted_document_dict,
{use_post: ((options.use_revert_post) &&
(local_hash === null))}
(local_hash === null)),
from_local: !from_local,
create_new_document: ((local_hash === null) &&
(status_hash !== null))}
);
}
// Minimize conflict if it can be resolved
if (remote_hash === null) {
// Copy remote modification remotely
return propagateModification(source, destination, doc,
local_hash, id,
{use_post: options.use_post});
}
return propagateModification(context, source, destination, doc,
local_hash, id, skip_document_dict,
skip_deleted_document_dict,
{use_post: options.use_post,
from_local: from_local,
create_new_document:
(status_hash !== null)});
}
doc = doc || local_hash;
remote_doc = remote_doc || remote_hash;
throw new jIO.util.jIOError("Conflict on '" + id + "': " +
stringify(doc || '') + " !== " +
stringify(remote_doc || ''),
stringify(doc) + " !== " +
stringify(remote_doc),
409);
});
}
function checkLocalDeletion(queue, destination, id, source,
function checkLocalDeletion(queue, context, skip_document_dict,
skip_deleted_document_dict,
cache, destination_key,
destination, id, source,
conflict_force, conflict_revert,
conflict_ignore, options) {
var status_hash;
......@@ -9175,7 +9524,10 @@ return new Parser;
})
.push(function (result) {
status_hash = result.hash;
return checkAndPropagate(status_hash, null, null,
return checkAndPropagate(context, skip_document_dict,
skip_deleted_document_dict,
cache, destination_key,
status_hash, null, null,
source, destination, id,
conflict_force, conflict_revert,
conflict_ignore,
......@@ -9183,37 +9535,33 @@ return new Parser;
});
}
function checkSignatureDifference(queue, source, destination, id,
function checkSignatureDifference(queue, context, skip_document_dict,
skip_deleted_document_dict,
cache, destination_key,
source, destination, id,
conflict_force, conflict_revert,
conflict_ignore,
is_creation, is_modification,
getMethod, options) {
local_hash, status_hash,
options) {
queue
.push(function () {
// Optimisation to save a get call to signature storage
if (is_creation === true) {
return RSVP.all([
getMethod(id),
{hash: null}
]);
}
if (is_modification === true) {
return RSVP.all([
getMethod(id),
context._signature_sub_storage.get(id)
]);
if (local_hash === null) {
// Hash was not provided by the allDocs query
return source.get(id);
}
throw new jIO.util.jIOError("Unexpected call of"
+ " checkSignatureDifference",
409);
return null;
})
.push(function (result_list) {
var doc = result_list[0],
local_hash = generateHash(stringify(doc)),
status_hash = result_list[1].hash;
.push(function (doc) {
if (local_hash === null) {
// Hash was not provided by the allDocs query
local_hash = generateHash(stringify(doc));
}
if (local_hash !== status_hash) {
return checkAndPropagate(status_hash, local_hash, doc,
return checkAndPropagate(context, skip_document_dict,
skip_deleted_document_dict,
cache, destination_key,
status_hash, local_hash, doc,
source, destination, id,
conflict_force, conflict_revert,
conflict_ignore,
......@@ -9222,47 +9570,11 @@ return new Parser;
});
}
function checkBulkSignatureDifference(queue, source, destination, id_list,
document_status_list, options,
conflict_force, conflict_revert,
conflict_ignore) {
queue
.push(function () {
return source.bulk(id_list);
})
.push(function (result_list) {
var i,
argument_list = [];
function getResult(j) {
return function (id) {
if (id !== id_list[j].parameter_list[0]) {
throw new Error("Does not access expected ID " + id);
}
return result_list[j];
};
}
for (i = 0; i < result_list.length; i += 1) {
argument_list[i] = [undefined, source, destination,
id_list[i].parameter_list[0],
conflict_force, conflict_revert,
conflict_ignore,
document_status_list[i].is_creation,
document_status_list[i].is_modification,
getResult(i), options];
}
return dispatchQueue(
checkSignatureDifference,
argument_list,
options.operation_amount
);
});
}
function pushStorage(source, destination, options) {
var queue = new RSVP.Queue(),
argument_list = [],
function pushStorage(context, skip_document_dict,
skip_deleted_document_dict,
cache, source_key, destination_key,
source, destination, signature_allDocs, options) {
var argument_list = [],
argument_list_deletion = [];
if (!options.hasOwnProperty("use_post")) {
options.use_post = false;
......@@ -9270,127 +9582,162 @@ return new Parser;
if (!options.hasOwnProperty("use_revert_post")) {
options.use_revert_post = false;
}
return queue
.push(function () {
return RSVP.all([
source.allDocs(context._query_options),
context._signature_sub_storage.allDocs()
]);
})
.push(function (result_list) {
return callAllDocsOnStorage(context, source, cache, source_key)
.push(function (source_allDocs) {
var i,
local_dict = {},
document_list = [],
document_status_list = [],
signature_dict = {},
is_modification,
is_creation,
key;
for (i = 0; i < result_list[0].data.total_rows; i += 1) {
status_hash,
local_hash,
key,
queue = new RSVP.Queue();
for (key in source_allDocs) {
if (source_allDocs.hasOwnProperty(key)) {
if (!skip_document_dict.hasOwnProperty(key)) {
local_dict[key] = source_allDocs[key];
}
}
}
/*
for (i = 0; i < source_allDocs.data.total_rows; i += 1) {
if (!skip_document_dict.hasOwnProperty(
result_list[0].data.rows[i].id
source_allDocs.data.rows[i].id
)) {
local_dict[result_list[0].data.rows[i].id] = i;
local_dict[source_allDocs.data.rows[i].id] =
source_allDocs.data.rows[i].value;
}
}
for (i = 0; i < result_list[1].data.total_rows; i += 1) {
*/
for (i = 0; i < signature_allDocs.data.total_rows; i += 1) {
if (!skip_document_dict.hasOwnProperty(
result_list[1].data.rows[i].id
signature_allDocs.data.rows[i].id
)) {
signature_dict[result_list[1].data.rows[i].id] = i;
signature_dict[signature_allDocs.data.rows[i].id] =
signature_allDocs.data.rows[i].value.hash;
}
}
i = 0;
for (key in local_dict) {
if (local_dict.hasOwnProperty(key)) {
is_modification = signature_dict.hasOwnProperty(key)
&& options.check_modification;
is_creation = !signature_dict.hasOwnProperty(key)
&& options.check_creation;
if (is_modification === true || is_creation === true) {
if (options.use_bulk_get === true) {
document_list.push({
method: "get",
parameter_list: [key]
});
document_status_list.push({
is_creation: is_creation,
is_modification: is_modification
});
} else {
argument_list[i] = [undefined, source, destination,
if (is_creation === true) {
status_hash = null;
} else if (is_modification === true) {
status_hash = signature_dict[key];
}
local_hash = null;
if (options.signature_hash_key !== undefined) {
local_hash = local_dict[key][options.signature_hash_key];
if (is_modification === true) {
// Bypass fetching all documents and calculating the sha
// Compare the select list values returned by allDocs calls
is_modification = false;
if (local_hash !== status_hash) {
is_modification = true;
}
}
}
if (is_modification === true || is_creation === true) {
argument_list.push([undefined, context, skip_document_dict,
skip_deleted_document_dict,
cache, destination_key,
source, destination,
key,
options.conflict_force,
options.conflict_revert,
options.conflict_ignore,
is_creation, is_modification,
source.get.bind(source),
options];
i += 1;
}
local_hash, status_hash,
options]);
}
}
}
queue
.push(function () {
return dispatchQueue(
context,
checkSignatureDifference,
argument_list,
options.operation_amount
);
});
if (options.check_deletion === true) {
i = 0;
for (key in signature_dict) {
if (signature_dict.hasOwnProperty(key)) {
if (!local_dict.hasOwnProperty(key)) {
argument_list_deletion[i] = [undefined,
if (options.check_deletion === true) {
argument_list_deletion.push([undefined,
context,
skip_document_dict,
skip_deleted_document_dict,
cache, destination_key,
destination, key,
source,
options.conflict_force,
options.conflict_revert,
options.conflict_ignore,
options];
i += 1;
options]);
} else {
skip_deleted_document_dict[key] = null;
}
}
}
}
if (argument_list_deletion.length !== 0) {
queue.push(function () {
return dispatchQueue(
context,
checkLocalDeletion,
argument_list_deletion,
options.operation_amount
);
});
}
if ((options.use_bulk_get === true) && (document_list.length !== 0)) {
checkBulkSignatureDifference(queue, source, destination,
document_list, document_status_list,
options,
options.conflict_force,
options.conflict_revert,
options.conflict_ignore);
}
return queue;
});
}
function repairDocument(queue, id) {
function repairDocument(queue, context, id, signature_hash_key,
signature_hash, signature_attachment_hash,
signature_from_local) {
queue.push(function () {
return repairDocumentAttachment(id);
return repairDocumentAttachment(context, id, signature_hash_key,
signature_hash,
signature_attachment_hash,
signature_from_local);
});
}
ReplicateStorage.prototype.repair = function () {
var context = this,
argument_list = arguments,
skip_document_dict = {},
skip_deleted_document_dict = {},
cache = {};
return new RSVP.Queue()
.push(function () {
// Ensure that the document storage is usable
return context._signature_sub_storage.__storage._sub_storage.get(
if (context._custom_signature_sub_storage === false) {
// Do not sync the signature document
skip_document_dict[context._signature_hash] = null;
return context._signature_sub_storage.__storage._sub_storage
.__storage._sub_storage.get(
context._signature_hash
);
}
})
.push(undefined, function (error) {
if ((error instanceof jIO.util.jIOError) &&
(error.status_code === 404)) {
return context._signature_sub_storage.__storage._sub_storage.put(
return context._signature_sub_storage.__storage._sub_storage
.__storage._sub_storage.put(
context._signature_hash,
{}
);
......@@ -9417,11 +9764,28 @@ return new Parser;
})
.push(function () {
if (context._check_local_modification ||
context._check_local_creation ||
context._check_local_deletion ||
context._check_remote_modification ||
context._check_remote_creation ||
context._check_remote_deletion) {
return context._signature_sub_storage.allDocs({
select_list: ['hash']
});
}
})
.push(function (signature_allDocs) {
if (context._check_local_modification ||
context._check_local_creation ||
context._check_local_deletion) {
return pushStorage(context._local_sub_storage,
return pushStorage(context, skip_document_dict,
skip_deleted_document_dict,
cache, 'local', 'remote',
context._local_sub_storage,
context._remote_sub_storage,
signature_allDocs,
{
use_post: context._use_remote_post,
conflict_force: (context._conflict_handling ===
......@@ -9433,28 +9797,26 @@ return new Parser;
check_modification: context._check_local_modification,
check_creation: context._check_local_creation,
check_deletion: context._check_local_deletion,
operation_amount: context._parallel_operation_amount
});
}
operation_amount: context._parallel_operation_amount,
signature_hash_key: context._signature_hash_key,
from_local: true
})
.push(function () {
// Autoactivate bulk if substorage implements it
// Keep it like this until the bulk API is stabilized
var use_bulk_get = false;
try {
use_bulk_get = context._remote_sub_storage.hasCapacity("bulk_get");
} catch (error) {
if (!((error instanceof jIO.util.jIOError) &&
(error.status_code === 501))) {
throw error;
}
return signature_allDocs;
});
}
return signature_allDocs;
})
.push(function (signature_allDocs) {
if (context._check_remote_modification ||
context._check_remote_creation ||
context._check_remote_deletion) {
return pushStorage(context._remote_sub_storage,
context._local_sub_storage, {
use_bulk_get: use_bulk_get,
return pushStorage(context, skip_document_dict,
skip_deleted_document_dict,
cache, 'remote', 'local',
context._remote_sub_storage,
context._local_sub_storage,
signature_allDocs, {
use_revert_post: context._use_remote_post,
conflict_force: (context._conflict_handling ===
CONFLICT_KEEP_REMOTE),
......@@ -9465,7 +9827,9 @@ return new Parser;
check_modification: context._check_remote_modification,
check_creation: context._check_remote_creation,
check_deletion: context._check_remote_deletion,
operation_amount: context._parallel_operation_amount
operation_amount: context._parallel_operation_amount,
signature_hash_key: context._signature_hash_key,
from_local: false
});
}
})
......@@ -9478,20 +9842,31 @@ return new Parser;
context._check_remote_attachment_deletion) {
// Attachments are synchronized if and only if their parent document
// has been also marked as synchronized.
return context._signature_sub_storage.allDocs()
return context._signature_sub_storage.allDocs({
select_list: ['hash', 'attachment_hash', 'from_local']
})
.push(function (result) {
var i,
argument_list = [],
local_argument_list = [],
row,
len = result.data.total_rows;
for (i = 0; i < len; i += 1) {
argument_list.push(
[undefined, result.data.rows[i].id]
row = result.data.rows[i];
// Do not synchronize attachment if one version of the document
// is deleted but not pushed to the other storage
if (!skip_deleted_document_dict.hasOwnProperty(row.id)) {
local_argument_list.push(
[undefined, context, row.id, context._signature_hash_key,
row.value.hash, row.value.attachment_hash,
row.value.from_local]
);
}
}
return dispatchQueue(
context,
repairDocument,
argument_list,
local_argument_list,
context._parallel_operation_amount
);
});
......@@ -11154,56 +11529,6 @@ return new Parser;
});
};
ERP5Storage.prototype.bulk = function (request_list) {
var i,
storage = this,
bulk_list = [];
for (i = 0; i < request_list.length; i += 1) {
if (request_list[i].method !== "get") {
throw new Error("ERP5Storage: not supported " +
request_list[i].method + " in bulk");
}
bulk_list.push({
relative_url: request_list[i].parameter_list[0],
view: storage._default_view_reference
});
}
return getSiteDocument(storage)
.push(function (site_hal) {
var form_data = new FormData();
form_data.append("bulk_list", JSON.stringify(bulk_list));
return jIO.util.ajax({
"type": "POST",
"url": site_hal._actions.bulk.href,
"data": form_data,
// "headers": {
// "Content-Type": "application/json"
// },
"xhrFields": {
withCredentials: true
}
});
})
.push(function (response) {
var result_list = [],
hateoas = JSON.parse(response.target.responseText);
function pushResult(json) {
return extractPropertyFromFormJSON(json)
.push(function (json2) {
return convertJSONToGet(json2);
});
}
for (i = 0; i < hateoas.result_list.length; i += 1) {
result_list.push(pushResult(hateoas.result_list[i]));
}
return RSVP.all(result_list);
});
};
ERP5Storage.prototype.post = function (data) {
var context = this,
new_id;
......@@ -11430,7 +11755,7 @@ return new Parser;
ERP5Storage.prototype.hasCapacity = function (name) {
return ((name === "list") || (name === "query") ||
(name === "select") || (name === "limit") ||
(name === "sort")) || (name === "bulk_get");
(name === "sort"));
};
function isSingleLocalRoles(parsed_query) {
......@@ -12041,10 +12366,9 @@ return new Parser;
}(jIO, RSVP, Blob));
;/*jslint nomen: true*/
/*global Blob, atob, btoa, RSVP*/
(function (jIO, Blob, atob, btoa, RSVP) {
/*global Blob, RSVP, unescape, escape*/
(function (jIO, Blob, RSVP, unescape, escape) {
"use strict";
/**
* The jIO DocumentStorage extension
*
......@@ -12060,7 +12384,13 @@ return new Parser;
var DOCUMENT_EXTENSION = ".json",
DOCUMENT_REGEXP = new RegExp("^jio_document/([\\w=]+)" +
DOCUMENT_EXTENSION + "$"),
ATTACHMENT_REGEXP = new RegExp("^jio_attachment/([\\w=]+)/([\\w=]+)$");
ATTACHMENT_REGEXP = new RegExp("^jio_attachment/([\\w=]+)/([\\w=]+)$"),
btoa = function (str) {
return window.btoa(unescape(encodeURIComponent(str)));
},
atob = function (str) {
return decodeURIComponent(escape(window.atob(str)));
};
function getSubAttachmentIdFromParam(id, name) {
if (name === undefined) {
......@@ -12267,7 +12597,7 @@ return new Parser;
jIO.addStorage('document', DocumentStorage);
}(jIO, Blob, atob, btoa, RSVP));
}(jIO, Blob, RSVP, unescape, escape));
;/*
* Copyright 2013, Nexedi SA
* Released under the LGPL license.
......@@ -12527,9 +12857,7 @@ return new Parser;
return tx;
}
function handleCursor(request, callback) {
function resolver(resolve, reject) {
// Open DB //
function handleCursor(request, callback, resolve, reject) {
request.onerror = function (error) {
if (request.transaction) {
request.transaction.abort();
......@@ -12554,9 +12882,6 @@ return new Parser;
}
};
}
// XXX Canceller???
return new RSVP.Promise(resolver);
}
IndexedDBStorage.prototype.buildQuery = function (options) {
var result_list = [];
......@@ -12577,40 +12902,50 @@ return new Parser;
}
return openIndexedDB(this)
.push(function (db) {
return new RSVP.Promise(function (resolve, reject) {
var tx = openTransaction(db, ["metadata"], "readonly");
if (options.include_docs === true) {
return handleCursor(tx.objectStore("metadata").index("_id")
.openCursor(), pushIncludedMetadata);
handleCursor(tx.objectStore("metadata").index("_id").openCursor(),
pushIncludedMetadata, resolve, reject);
} else {
handleCursor(tx.objectStore("metadata").index("_id")
.openKeyCursor(), pushMetadata, resolve, reject);
}
return handleCursor(tx.objectStore("metadata").index("_id")
.openKeyCursor(), pushMetadata);
});
})
.push(function () {
return result_list;
});
};
function handleGet(request) {
function resolver(resolve, reject) {
function handleGet(store, id, resolve, reject) {
var request = store.get(id);
request.onerror = reject;
request.onsuccess = function () {
if (request.result) {
resolve(request.result);
} else {
reject(new jIO.util.jIOError(
"IndexedDB: cannot find object '" + id + "' in the '" +
store.name + "' store",
404
));
}
// XXX How to get ID
reject(new jIO.util.jIOError("Cannot find document", 404));
};
}
return new RSVP.Promise(resolver);
}
IndexedDBStorage.prototype.get = function (id) {
return openIndexedDB(this)
.push(function (db) {
var transaction = openTransaction(db, ["metadata"],
"readonly");
return handleGet(transaction.objectStore("metadata").get(id));
return new RSVP.Promise(function (resolve, reject) {
var transaction = openTransaction(db, ["metadata"], "readonly");
handleGet(
transaction.objectStore("metadata"),
id,
resolve,
reject
);
});
})
.push(function (result) {
return result.doc;
......@@ -12626,37 +12961,52 @@ return new Parser;
return openIndexedDB(this)
.push(function (db) {
return new RSVP.Promise(function (resolve, reject) {
var transaction = openTransaction(db, ["metadata", "attachment"],
"readonly");
return RSVP.all([
handleGet(transaction.objectStore("metadata").get(id)),
handleCursor(transaction.objectStore("attachment").index("_id")
.openCursor(IDBKeyRange.only(id)), addEntry)
]);
function getAttachments() {
handleCursor(
transaction.objectStore("attachment").index("_id")
.openCursor(IDBKeyRange.only(id)),
addEntry,
resolve,
reject
);
}
handleGet(
transaction.objectStore("metadata"),
id,
getAttachments,
reject
);
});
})
.push(function () {
return attachment_dict;
});
};
function handleRequest(request) {
function resolver(resolve, reject) {
function handleRequest(request, resolve, reject) {
request.onerror = reject;
request.onsuccess = function () {
resolve(request.result);
};
}
return new RSVP.Promise(resolver);
}
IndexedDBStorage.prototype.put = function (id, metadata) {
return openIndexedDB(this)
.push(function (db) {
return new RSVP.Promise(function (resolve, reject) {
var transaction = openTransaction(db, ["metadata"], "readwrite");
return handleRequest(transaction.objectStore("metadata").put({
handleRequest(
transaction.objectStore("metadata").put({
"_id": id,
"doc": metadata
}));
}),
resolve,
reject
);
});
});
};
......@@ -12665,19 +13015,38 @@ return new Parser;
}
IndexedDBStorage.prototype.remove = function (id) {
var resolved_amount = 0;
return openIndexedDB(this)
.push(function (db) {
return new RSVP.Promise(function (resolve, reject) {
function resolver() {
if (resolved_amount < 2) {
resolved_amount += 1;
} else {
resolve();
}
}
var transaction = openTransaction(db, ["metadata", "attachment",
"blob"], "readwrite");
return RSVP.all([
handleRequest(transaction
.objectStore("metadata")["delete"](id)),
handleRequest(
transaction.objectStore("metadata")["delete"](id),
resolver,
reject
);
// XXX Why not possible to delete with KeyCursor?
handleCursor(transaction.objectStore("attachment").index("_id")
.openCursor(IDBKeyRange.only(id)), deleteEntry),
.openCursor(IDBKeyRange.only(id)),
deleteEntry,
resolver,
reject
);
handleCursor(transaction.objectStore("blob").index("_id")
.openCursor(IDBKeyRange.only(id)), deleteEntry)
]);
.openCursor(IDBKeyRange.only(id)),
deleteEntry,
resolver,
reject
);
});
});
};
......@@ -12691,48 +13060,67 @@ return new Parser;
}
return openIndexedDB(this)
.push(function (db) {
transaction = openTransaction(db, ["attachment", "blob"], "readonly");
// XXX Should raise if key is not good
return handleGet(transaction.objectStore("attachment")
.get(buildKeyPath([id, name])));
})
.push(function (attachment) {
return new RSVP.Promise(function (resolve, reject) {
transaction = openTransaction(
db,
["attachment", "blob"],
"readonly"
);
function getBlob(attachment) {
var total_length = attachment.info.length,
i,
promise_list = [],
result_list = [],
store = transaction.objectStore("blob"),
start_index,
end_index;
type = attachment.info.content_type;
start = options.start || 0;
end = options.end || total_length;
if (end > total_length) {
end = total_length;
}
if (start < 0 || end < 0) {
throw new jIO.util.jIOError("_start and _end must be positive",
400);
throw new jIO.util.jIOError(
"_start and _end must be positive",
400
);
}
if (start > end) {
throw new jIO.util.jIOError("_start is greater than _end",
400);
}
start_index = Math.floor(start / UNITE);
end_index = Math.floor(end / UNITE);
end_index = Math.floor(end / UNITE) - 1;
if (end % UNITE === 0) {
end_index -= 1;
}
for (i = start_index; i <= end_index; i += 1) {
promise_list.push(
handleGet(store.get(buildKeyPath([id,
name, i])))
function resolver(result) {
if (result.blob !== undefined) {
result_list.push(result);
}
resolve(result_list);
}
function getPart(i) {
return function (result) {
if (result) {
result_list.push(result);
}
i += 1;
handleGet(store,
buildKeyPath([id, name, i]),
(i <= end_index) ? getPart(i) : resolver,
reject
);
};
}
return RSVP.all(promise_list);
getPart(start_index - 1)();
}
// XXX Should raise if key is not good
handleGet(transaction.objectStore("attachment"),
buildKeyPath([id, name]),
getBlob,
reject
);
});
})
.push(function (result_list) {
var array_buffer_list = [],
......@@ -12753,19 +13141,24 @@ return new Parser;
});
};
function removeAttachment(transaction, id, name) {
return RSVP.all([
function removeAttachment(transaction, id, name, resolve, reject) {
// XXX How to get the right attachment
handleRequest(transaction.objectStore("attachment")["delete"](
function deleteContent() {
handleCursor(
transaction.objectStore("blob").index("_id_attachment")
.openCursor(IDBKeyRange.only([id, name])),
deleteEntry,
resolve,
reject
);
}
handleRequest(
transaction.objectStore("attachment")["delete"](
buildKeyPath([id, name])
)),
handleCursor(transaction.objectStore("blob").index("_id_attachment")
.openCursor(IDBKeyRange.only(
[id, name]
)),
deleteEntry
)
]);
),
deleteContent,
reject
);
}
IndexedDBStorage.prototype.putAttachment = function (id, name, blob) {
......@@ -12793,12 +13186,29 @@ return new Parser;
// Remove previous attachment
transaction = openTransaction(db, ["attachment", "blob"], "readwrite");
return removeAttachment(transaction, id, name);
})
.push(function () {
var promise_list = [
handleRequest(transaction.objectStore("attachment").put({
return new RSVP.Promise(function (resolve, reject) {
function write() {
var len = blob_part.length - 1,
attachment_store = transaction.objectStore("attachment"),
blob_store = transaction.objectStore("blob");
function putBlobPart(i) {
return function () {
i += 1;
handleRequest(
blob_store.put({
"_key_path": buildKeyPath([id, name, i]),
"_id" : id,
"_attachment" : name,
"_part" : i,
"blob": blob_part[i]
}),
(i < len) ? putBlobPart(i) : resolve,
reject
);
};
}
handleRequest(
attachment_store.put({
"_key_path": buildKeyPath([id, name]),
"_id": id,
"_attachment": name,
......@@ -12806,25 +13216,13 @@ return new Parser;
"content_type": blob.type,
"length": blob.size
}
}))
],
len = blob_part.length,
blob_store = transaction.objectStore("blob"),
i;
for (i = 0; i < len; i += 1) {
promise_list.push(
handleRequest(blob_store.put({
"_key_path": buildKeyPath([id, name,
i]),
"_id" : id,
"_attachment" : name,
"_part" : i,
"blob": blob_part[i]
}))
}),
putBlobPart(-1),
reject
);
}
// Store all new data
return RSVP.all(promise_list);
removeAttachment(transaction, id, name, write, reject);
});
});
};
......@@ -12833,7 +13231,9 @@ return new Parser;
.push(function (db) {
var transaction = openTransaction(db, ["attachment", "blob"],
"readwrite");
return removeAttachment(transaction, id, name);
return new RSVP.Promise(function (resolve, reject) {
removeAttachment(transaction, id, name, resolve, reject);
});
});
};
......@@ -12851,24 +13251,29 @@ return new Parser;
(function (jIO, RSVP, DOMException, Blob, crypto, Uint8Array, ArrayBuffer) {
"use strict";
/*
The cryptography system used by this storage is AES-GCM.
Here is an example of how to generate a key to the json format:
// you the cryptography system used by this storage is AES-GCM.
// here is an example of how to generate a key to the json format.
// var key,
// jsonKey;
// crypto.subtle.generateKey({name: "AES-GCM",length: 256},
// (true), ["encrypt", "decrypt"])
// .then(function(res){key = res;});
//
// window.crypto.subtle.exportKey("jwk", key)
// .then(function(res){jsonKey = val})
//
//var storage = jIO.createJIO({type: "crypt", key: jsonKey,
// sub_storage: {...}});
return new RSVP.Queue()
.push(function () {
return crypto.subtle.generateKey({name: "AES-GCM", length: 256},
true, ["encrypt", "decrypt"]);
})
.push(function (key) {
return crypto.subtle.exportKey("jwk", key);
})
.push(function (json_key) {
var jio = jIO.createJIO({
type: "crypt",
key: json_key,
sub_storage: {storage_definition}
});
});
// find more informations about this cryptography system on
// https://github.com/diafygi/webcrypto-examples#aes-gcm
Find more informations about this cryptography system on
https://github.com/diafygi/webcrypto-examples#aes-gcm
*/
/**
* The JIO Cryptography Storage extension
......@@ -12946,12 +13351,12 @@ return new Parser;
})
.push(function (dataURL) {
//string->arraybuffer
var strLen = dataURL.currentTarget.result.length,
var strLen = dataURL.target.result.length,
buf = new ArrayBuffer(strLen),
bufView = new Uint8Array(buf),
i;
dataURL = dataURL.currentTarget.result;
dataURL = dataURL.target.result;
for (i = 0; i < strLen; i += 1) {
bufView[i] = dataURL.charCodeAt(i);
}
......@@ -12988,7 +13393,7 @@ return new Parser;
.push(function (coded) {
var initializaton_vector;
coded = coded.currentTarget.result;
coded = coded.target.result;
initializaton_vector = new Uint8Array(coded.slice(0, 12));
return new RSVP.Queue()
.push(function () {
......@@ -13207,7 +13612,7 @@ return new Parser;
return jIO.util.readBlobAsDataURL(blob);
})
.push(function (strBlob) {
argument_list[index + 2].push(strBlob.currentTarget.result);
argument_list[index + 2].push(strBlob.target.result);
return;
});
}
......@@ -13391,3 +13796,117 @@ return new Parser;
jIO.addStorage('websql', WebSQLStorage);
}(jIO, RSVP, Blob, openDatabase));
;/*jslint nomen: true */
/*global RSVP, UriTemplate*/
(function (jIO, RSVP, UriTemplate) {
"use strict";
var GET_POST_URL = "https://graph.facebook.com/v2.9/{+post_id}" +
"?fields={+fields}&access_token={+access_token}",
get_post_template = UriTemplate.parse(GET_POST_URL),
GET_FEED_URL = "https://graph.facebook.com/v2.9/{+user_id}/feed" +
"?fields={+fields}&limit={+limit}&since={+since}&access_token=" +
"{+access_token}",
get_feed_template = UriTemplate.parse(GET_FEED_URL);
function FBStorage(spec) {
if (typeof spec.access_token !== 'string' || !spec.access_token) {
throw new TypeError("Access Token must be a string " +
"which contains more than one character.");
}
if (typeof spec.user_id !== 'string' || !spec.user_id) {
throw new TypeError("User ID must be a string " +
"which contains more than one character.");
}
this._access_token = spec.access_token;
this._user_id = spec.user_id;
this._default_field_list = spec.default_field_list || [];
this._default_limit = spec.default_limit || 500;
}
FBStorage.prototype.get = function (id) {
var that = this;
return new RSVP.Queue()
.push(function () {
return jIO.util.ajax({
type: "GET",
url: get_post_template.expand({post_id: id,
fields: that._default_field_list, access_token: that._access_token})
});
})
.push(function (result) {
return JSON.parse(result.target.responseText);
});
};
function paginateResult(url, result, select_list) {
return new RSVP.Queue()
.push(function () {
return jIO.util.ajax({
type: "GET",
url: url
});
})
.push(function (response) {
return JSON.parse(response.target.responseText);
},
function (err) {
throw new jIO.util.jIOError("Getting feed failed " + err.toString(),
err.target.status);
})
.push(function (response) {
if (response.data.length === 0) {
return result;
}
var i, j, obj = {};
for (i = 0; i < response.data.length; i += 1) {
obj.id = response.data[i].id;
obj.value = {};
for (j = 0; j < select_list.length; j += 1) {
obj.value[select_list[j]] = response.data[i][select_list[j]];
}
result.push(obj);
obj = {};
}
return paginateResult(response.paging.next, result, select_list);
});
}
FBStorage.prototype.buildQuery = function (query) {
var that = this, fields = [], limit = this._default_limit,
template_argument = {
user_id: this._user_id,
limit: limit,
access_token: this._access_token
};
if (query.include_docs) {
fields = fields.concat(that._default_field_list);
}
if (query.select_list) {
fields = fields.concat(query.select_list);
}
if (query.limit) {
limit = query.limit[1];
}
template_argument.fields = fields;
template_argument.limit = limit;
return paginateResult(get_feed_template.expand(template_argument), [],
fields)
.push(function (result) {
if (!query.limit) {
return result;
}
return result.slice(query.limit[0], query.limit[1]);
});
};
FBStorage.prototype.hasCapacity = function (name) {
var this_storage_capacity_list = ["list", "select", "include", "limit"];
if (this_storage_capacity_list.indexOf(name) !== -1) {
return true;
}
};
jIO.addStorage('facebook', FBStorage);
}(jIO, RSVP, UriTemplate));
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment