Stackedit/src/services/providers/couchdbWorkspaceProvider.js
2018-02-01 22:39:14 +00:00

225 lines
6.9 KiB
JavaScript

import store from '../../store';
import couchdbHelper from './helpers/couchdbHelper';
import providerRegistry from './providerRegistry';
import providerUtils from './providerUtils';
import utils from '../utils';
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.
};
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;
return couchdbHelper.getChanges(syncToken, lastSeq)
.then((result) => {
const changes = result.changes.filter((change) => {
if (!change.deleted && change.doc) {
change.item = change.doc.item;
if (!change.item || !change.item.id || !change.item.type) {
return false;
}
// Build sync data
change.syncData = {
id: change.id,
itemId: change.item.id,
type: change.item.type,
hash: change.item.hash,
rev: change.doc._rev, // eslint-disable-line no-underscore-dangle
};
}
change.syncDataId = change.id;
return true;
});
changes.lastSeq = result.lastSeq;
return changes;
});
},
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) {
return getSyncData(fileId)
.then(syncData => couchdbHelper.retrieveDocumentWithRevisions(token, syncData.id))
.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) {
return getSyncData(fileId)
.then(syncData => couchdbHelper.retrieveDocument(token, syncData.id, revision.id))
.then((body) => {
revision.sub = body.sub;
revision.created = body.time || 1; // Has to be truthy to prevent from loading several times
});
},
getRevisionContent(token, fileId, revisionId) {
return getSyncData(fileId)
.then(syncData => couchdbHelper
.retrieveDocumentWithAttachments(token, syncData.id, revisionId))
.then(body => providerUtils.parseContent(body.attachments.data, body.item.id));
},
});