Commit 507c1ba5 authored by Caleb James DeLisle's avatar Caleb James DeLisle Committed by Tristan Cavelier

Added proof of concept document storage using XWiki as a backend.

parent 17015e67
/**
* JIO XWiki based storage. Type = 'xwiki'.
* Edits XWiki documents as html using html editor.
* Test this code using the following inputs:
* {"type":"xwiki","username":"Admin","password":"admin","xwikiurl":"http://127.0.0.1:8080/xwiki","space":"OfficeJS"}
*/
var newXWikiStorage = function(spec, my)
{
/** The input configuration. */
spec = spec || {};
/** The "public" object which will have methods called on it. */
var that = my.basicStorage(spec, my);
/** "private" fields. */
var priv = {
username: spec.username || '',
password: spec.password || '',
xwikiurl: spec.xwikiurl || '',
space: spec.space || ''
};
//--------------------- Private Functions ---------------------//
/** Escape a document ID by URL escaping all '/' characters. */
var escapeDocId = function(docId) {
return docId.replace(/.html$/, '').split('/').join('%2F');
};
/** Restore a document id from the escaped form. */
var restoreDocId = function(escapedDocId) {
return escapedDocId.split('%2F').join('/') + '.html';
};
/**
* Get the Anti-CSRF token and do something with it.
*
* @param docId the document id of a document which you have permission to edit.
* @param whatToDo a function which will be called with the form token as the parameter.
*/
var doWithFormToken = function(docId, whatToDo) {
var url = priv.xwikiurl + '/bin/edit/' + priv.space + '/' + escapeDocId(docId) +
'?editor=wiki&cachebuster=' + Date.now();
$.ajax({
url: url,
type: "GET",
async: true,
dataType: 'text',
headers: {'Authorization':'Basic ' + Base64.encode(
priv.username + ':' + priv.password )},
success: function (html) {
whatToDo($(html).find('input[name=form_token]').attr('value'));
}
});
};
/**
* Get the creation and modification dates for a page.
*
* @param docId the ID of the document.
* @param callWhenDone a callback which will be called when this function finishes.
*/
var getDates = function(docId, callWhenDone) {
// http://127.0.0.1:8080/xwiki/rest/wikis/xwiki/spaces/Main/pages/<pageName>
var map = {};
$.ajax ( {
url: priv.xwikiurl + '/rest/wikis/' + 'xwiki' +
'/spaces/' + priv.space +
'/pages/' + escapeDocId(docId) +
'?cachebuster=' + Date.now(),
type: "GET",
async: true,
dataType: 'xml',
headers: {'Authorization':'Basic ' + Base64.encode(
priv.username + ':' + priv.password )},
success: function (xmlData) {
$(xmlData).find('modified').each(function() {
map._last_modified = Date.parse($(this).text());
});
$(xmlData).find('created').each(function() {
map._creation_date = Date.parse($(this).text());
});
callWhenDone();
}
});
return map;
};
//--------------------- Public Functions ---------------------//
/** Get a serialized form of the module state. */
var super_serialized = that.serialized;
that.serialized = function() {
var o = super_serialized();
for(var key in priv) {
if (priv.hasOwnProperty(key)) {
o[key] = priv[key];
}
}
return o;
};
/** Check that the storage module is properly setup. */
that.validateState = function() {
for(var key in priv) {
if (priv.hasOwnProperty(key) && !priv[key]) {
return 'Must specify "' + key + '".';
}
}
return '';
};
/** Alias to put() */
that.post = function (command) {
that.put(command);
};
/**
* Saves a document as an XWikiDocument.
*
* @param command must contain document ID and document content.
*/
that.put = function (command) {
doWithFormToken(command.getDocId(), function(formToken) {
if (!formToken) {
throw Error("missing form token");
}
$.ajax({
url: priv.xwikiurl + '/bin/preview/' + priv.space +
'/' + escapeDocId(command.getDocId()),
type: "POST",
async: true,
dataType: 'text',
headers: {'Authorization':'Basic ' + Base64.encode(
priv.username + ':' + priv.password )},
data: {
parent: '',
title: '',
xredirect: '',
language: 'en',
RequiresHTMLConversion: 'content',
content_syntax: 'xwiki/2.1',
content: command.getDocContent(),
xeditaction: 'edit',
comment: 'Saved by OfficeJS',
action_saveandcontinue: 'Save & Continue',
syntaxId: 'xwiki/2.1',
xhidden: 0,
minorEdit: 0,
ajax: true,
form_token: formToken
},
success: function(html) {
that.success({
ok: true,
id: command.getDocId()
});
}
});
});
}; // end put
/**
* Loads a document from the XWiki storage.
*/
that.get = function (command) {
// /bin/view/Main/WebHomee?xpage=plain
/**
* Protocol specification:
* {
* "_id": "somePage",
* "content": "aoeu",
* "_creation_date": 1348154789478,
* "_last_modified": 1348154789478
* }
*/
var doc;
var pendingRequests = 2;
var finishedRequest = function() {
pendingRequests--;
if (pendingRequests < 1) {
that.success(doc);
}
};
doc = (function() {
var resultMap = getDates(command.getDocId(), finishedRequest);
$.ajax({
url: priv.xwikiurl + '/bin/get/' + priv.space +
'/' + escapeDocId(command.getDocId()) +
'?xpage=plain&cachebuster=' + Date.now(),
type: "GET",
async: true,
dataType: 'text',
headers: {'Authorization':'Basic ' + Base64.encode(
priv.username + ':' + priv.password )},
success: function (html) {
resultMap.content = html;
finishedRequest();
}
});
return resultMap;
})();
doc._id = command.getDocId();
}; // end get
/**
* Gets a document list from the xwiki storage.
* It will retreive an array containing files meta data owned by
* the user.
* @method allDocs
*/
that.allDocs = function (command) {
// http://127.0.0.1:8080/xwiki/rest/wikis/xwiki/spaces/Main/pages
$.ajax ( {
url: priv.xwikiurl + '/rest/wikis/' + 'xwiki'
+ '/spaces/' + priv.space
+ '/pages?cachebuster=' + Date.now(),
type: "GET",
async: true,
dataType: 'xml',
headers: {'Authorization':'Basic ' + Base64.encode(
priv.username + ':' + priv.password )},
success: function (xmlData) {
/** Protocol definition:
* {
* "total_rows":2,
* "rows":[{
* "id":"b",
* "key":"b",
* "value":{
* "content":"aoeu",
* "_creation_date":1348154789478,
* "_last_modified":1348154789478
* }
* },
* {
* "id":"oeau",
* "key":"oeau",
* "value"{
* "content":"oeu",
* "_creation_date":1348154834680,
* "_last_modified":1348154834680
* }
* }
* ]
* }
*/
var totalRows = 0
var data = [];
// The number of async calls which are waiting to return.
var outstandingCalls = 0;
$(xmlData).find('name').each(function() {
outstandingCalls++;
var id = restoreDocId($(this).text());
var entry = {
'id': id,
'key': id,
'value': getDates(id, function() {
outstandingCalls--;
if (outstandingCalls < 1) {
that.success(toSend);
}
})
};
data[totalRows++] = entry;
});
var toSend = {
'total_rows': totalRows,
'rows': data
};
/* TODO: Include the content if requested.
if (!command.getOption('metadata_only')) {
getContent();
} else {
that.success(toSend);
}
*/
},
error: function (type) {
if (type.status === 404) {
type.message = 'Cannot find "' + command.getDocId() +
'" informations.';
type.reason = 'missing';
that.error(type);
} else {
type.reason = 'Cannot get "' + command.getDocId() +
'" informations';
type.message = type.reason + '.';
that.retry(type);
}
}
} );
};
/**
* Removes a document from the XWiki storage.
*/
that.remove = function (command) {
// http://127.0.0.1:8080/xwiki/bin/delete/Main/WebHomee?confirm=1&form_token=r7x0oGBSk2EFm2fxVULfFA
doWithFormToken(command.getDocId(), function(formToken) {
$.ajax({
url: priv.xwikiurl + '/bin/delete/' + priv.space +
'/' + escapeDocId(command.getDocId()),
type: "POST",
async: true,
dataType: 'text',
headers: {'Authorization':'Basic ' + Base64.encode(
priv.username + ':' + priv.password )},
data: {
confirm: 1,
form_token: formToken
},
success: function(html) {
that.success({
ok: true,
id: command.getDocId()
});
}
});
});
}; // end remove
return that;
};
jio.addStorageType('xwiki', newXWikiStorage);
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