2018-01-24 07:31:54 +00:00
|
|
|
import store from '../../store';
|
|
|
|
import couchdbHelper from './helpers/couchdbHelper';
|
|
|
|
import providerRegistry from './providerRegistry';
|
2018-01-30 07:36:33 +00:00
|
|
|
import providerUtils from './providerUtils';
|
2018-01-24 07:31:54 +00:00
|
|
|
import utils from '../utils';
|
|
|
|
|
2018-02-01 22:39:14 +00:00
|
|
|
const getSyncData = (fileId) => {
|
|
|
|
const syncData = store.getters['data/syncDataByItemId'][`${fileId}/content`];
|
|
|
|
return syncData
|
|
|
|
? Promise.resolve(syncData)
|
|
|
|
: Promise.reject(); // No need for a proper error message.
|
|
|
|
};
|
|
|
|
|
2018-01-24 07:31:54 +00:00
|
|
|
export default providerRegistry.register({
|
|
|
|
id: 'couchdbWorkspace',
|
|
|
|
getToken() {
|
|
|
|
return store.getters['workspace/syncToken'];
|
|
|
|
},
|
|
|
|
initWorkspace() {
|
|
|
|
const dbUrl = (utils.queryParams.dbUrl || '').replace(/\/?$/, ''); // Remove trailing /
|
|
|
|
const workspaceIdParams = {
|
|
|
|
providerId: this.id,
|
|
|
|
dbUrl,
|
|
|
|
};
|
|
|
|
const workspaceId = utils.makeWorkspaceId(workspaceIdParams);
|
|
|
|
const getToken = () => store.getters['data/couchdbTokens'][workspaceId];
|
|
|
|
const getWorkspace = () => store.getters['data/sanitizedWorkspaces'][workspaceId];
|
|
|
|
|
|
|
|
if (!getToken()) {
|
|
|
|
// Create token
|
|
|
|
store.dispatch('data/setCouchdbToken', {
|
|
|
|
sub: workspaceId,
|
|
|
|
dbUrl,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
return Promise.resolve()
|
|
|
|
.then(() => getWorkspace() || couchdbHelper.getDb(getToken())
|
|
|
|
.then((db) => {
|
|
|
|
store.dispatch('data/patchWorkspaces', {
|
|
|
|
[workspaceId]: {
|
|
|
|
id: workspaceId,
|
|
|
|
name: db.db_name,
|
|
|
|
providerId: this.id,
|
|
|
|
dbUrl,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
return getWorkspace();
|
|
|
|
}, () => {
|
|
|
|
throw new Error(`${dbUrl} is not accessible. Make sure you have the right permissions.`);
|
|
|
|
}))
|
|
|
|
.then((workspace) => {
|
|
|
|
// Fix the URL hash
|
|
|
|
utils.setQueryParams(workspaceIdParams);
|
|
|
|
if (workspace.url !== location.href) {
|
|
|
|
store.dispatch('data/patchWorkspaces', {
|
|
|
|
[workspace.id]: {
|
|
|
|
...workspace,
|
|
|
|
url: location.href,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
|
|
|
return getWorkspace();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
getChanges() {
|
|
|
|
const syncToken = store.getters['workspace/syncToken'];
|
|
|
|
const lastSeq = store.getters['data/localSettings'].syncLastSeq;
|
2018-01-30 07:36:33 +00:00
|
|
|
return couchdbHelper.getChanges(syncToken, lastSeq)
|
2018-01-24 07:31:54 +00:00
|
|
|
.then((result) => {
|
|
|
|
const changes = result.changes.filter((change) => {
|
2018-01-30 07:36:33 +00:00
|
|
|
if (!change.deleted && change.doc) {
|
|
|
|
change.item = change.doc.item;
|
|
|
|
if (!change.item || !change.item.id || !change.item.type) {
|
2018-01-24 07:31:54 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// Build sync data
|
|
|
|
change.syncData = {
|
2018-01-30 07:36:33 +00:00
|
|
|
id: change.id,
|
2018-01-24 07:31:54 +00:00
|
|
|
itemId: change.item.id,
|
|
|
|
type: change.item.type,
|
|
|
|
hash: change.item.hash,
|
2018-01-30 07:36:33 +00:00
|
|
|
rev: change.doc._rev, // eslint-disable-line no-underscore-dangle
|
2018-01-24 07:31:54 +00:00
|
|
|
};
|
|
|
|
}
|
2018-01-30 07:36:33 +00:00
|
|
|
change.syncDataId = change.id;
|
2018-01-24 07:31:54 +00:00
|
|
|
return true;
|
|
|
|
});
|
2018-01-30 07:36:33 +00:00
|
|
|
changes.lastSeq = result.lastSeq;
|
2018-01-24 07:31:54 +00:00
|
|
|
return changes;
|
|
|
|
});
|
|
|
|
},
|
2018-01-30 07:36:33 +00:00
|
|
|
setAppliedChanges(changes) {
|
|
|
|
store.dispatch('data/patchLocalSettings', {
|
|
|
|
syncLastSeq: changes.lastSeq,
|
|
|
|
});
|
|
|
|
},
|
|
|
|
saveSimpleItem(item, syncData) {
|
|
|
|
const syncToken = store.getters['workspace/syncToken'];
|
|
|
|
return couchdbHelper.uploadDocument(
|
|
|
|
syncToken,
|
|
|
|
item,
|
|
|
|
undefined,
|
|
|
|
undefined,
|
|
|
|
syncData && syncData.id,
|
|
|
|
syncData && syncData.rev,
|
|
|
|
)
|
|
|
|
.then(res => ({
|
|
|
|
// Build sync data
|
|
|
|
id: res.id,
|
|
|
|
itemId: item.id,
|
|
|
|
type: item.type,
|
|
|
|
hash: item.hash,
|
|
|
|
rev: res.rev,
|
|
|
|
}));
|
|
|
|
},
|
|
|
|
removeItem(syncData) {
|
|
|
|
const syncToken = store.getters['workspace/syncToken'];
|
|
|
|
return couchdbHelper.removeDocument(syncToken, syncData.id, syncData.rev);
|
|
|
|
},
|
|
|
|
downloadContent(token, syncLocation) {
|
|
|
|
return this.downloadData(`${syncLocation.fileId}/content`);
|
|
|
|
},
|
|
|
|
downloadData(dataId) {
|
|
|
|
const syncData = store.getters['data/syncDataByItemId'][dataId];
|
|
|
|
if (!syncData) {
|
|
|
|
return Promise.resolve();
|
|
|
|
}
|
|
|
|
const syncToken = store.getters['workspace/syncToken'];
|
|
|
|
return couchdbHelper.retrieveDocumentWithAttachments(syncToken, syncData.id)
|
|
|
|
.then((body) => {
|
|
|
|
let item;
|
|
|
|
if (body.item.type === 'content') {
|
|
|
|
item = providerUtils.parseContent(body.attachments.data, body.item.id);
|
|
|
|
} else {
|
|
|
|
item = JSON.parse(body.attachments.data);
|
|
|
|
}
|
|
|
|
const rev = body._rev; // eslint-disable-line no-underscore-dangle
|
|
|
|
if (item.hash !== syncData.hash || rev !== syncData.rev) {
|
|
|
|
store.dispatch('data/patchSyncData', {
|
|
|
|
[syncData.id]: {
|
|
|
|
...syncData,
|
|
|
|
hash: item.hash,
|
|
|
|
rev,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
|
|
|
return item;
|
|
|
|
});
|
|
|
|
},
|
|
|
|
uploadContent(token, content, syncLocation) {
|
|
|
|
return this.uploadData(content, `${syncLocation.fileId}/content`)
|
|
|
|
.then(() => syncLocation);
|
|
|
|
},
|
|
|
|
uploadData(item, dataId) {
|
|
|
|
const syncData = store.getters['data/syncDataByItemId'][dataId];
|
|
|
|
if (syncData && syncData.hash === item.hash) {
|
|
|
|
return Promise.resolve();
|
|
|
|
}
|
|
|
|
let data;
|
|
|
|
let dataType;
|
|
|
|
if (item.type === 'content') {
|
|
|
|
data = providerUtils.serializeContent(item);
|
|
|
|
dataType = 'text/plain';
|
|
|
|
} else {
|
|
|
|
data = JSON.stringify(item);
|
|
|
|
dataType = 'application/json';
|
|
|
|
}
|
|
|
|
const syncToken = store.getters['workspace/syncToken'];
|
|
|
|
return couchdbHelper.uploadDocument(
|
|
|
|
syncToken,
|
|
|
|
{
|
|
|
|
id: item.id,
|
|
|
|
type: item.type,
|
|
|
|
hash: item.hash,
|
|
|
|
},
|
|
|
|
data,
|
|
|
|
dataType,
|
|
|
|
syncData && syncData.id,
|
|
|
|
syncData && syncData.rev,
|
|
|
|
)
|
|
|
|
.then(res => store.dispatch('data/patchSyncData', {
|
|
|
|
[res.id]: {
|
|
|
|
// Build sync data
|
|
|
|
id: res.id,
|
|
|
|
itemId: item.id,
|
|
|
|
type: item.type,
|
|
|
|
hash: item.hash,
|
|
|
|
rev: res.rev,
|
|
|
|
},
|
|
|
|
}));
|
|
|
|
},
|
|
|
|
listRevisions(token, fileId) {
|
2018-02-01 22:39:14 +00:00
|
|
|
return getSyncData(fileId)
|
|
|
|
.then(syncData => couchdbHelper.retrieveDocumentWithRevisions(token, syncData.id))
|
2018-01-30 07:36:33 +00:00
|
|
|
.then((body) => {
|
|
|
|
const revisions = [];
|
|
|
|
body._revs_info.forEach((revInfo) => { // eslint-disable-line no-underscore-dangle
|
|
|
|
if (revInfo.status === 'available') {
|
|
|
|
revisions.push({
|
|
|
|
id: revInfo.rev,
|
|
|
|
sub: null,
|
|
|
|
created: null,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return revisions;
|
|
|
|
});
|
|
|
|
},
|
|
|
|
loadRevision(token, fileId, revision) {
|
2018-02-01 22:39:14 +00:00
|
|
|
return getSyncData(fileId)
|
|
|
|
.then(syncData => couchdbHelper.retrieveDocument(token, syncData.id, revision.id))
|
2018-01-30 07:36:33 +00:00
|
|
|
.then((body) => {
|
|
|
|
revision.sub = body.sub;
|
2018-02-01 22:39:14 +00:00
|
|
|
revision.created = body.time || 1; // Has to be truthy to prevent from loading several times
|
2018-01-30 07:36:33 +00:00
|
|
|
});
|
|
|
|
},
|
|
|
|
getRevisionContent(token, fileId, revisionId) {
|
2018-02-01 22:39:14 +00:00
|
|
|
return getSyncData(fileId)
|
|
|
|
.then(syncData => couchdbHelper
|
|
|
|
.retrieveDocumentWithAttachments(token, syncData.id, revisionId))
|
2018-01-30 07:36:33 +00:00
|
|
|
.then(body => providerUtils.parseContent(body.attachments.data, body.item.id));
|
|
|
|
},
|
2018-01-24 07:31:54 +00:00
|
|
|
});
|