2018-07-28 14:33:42 -06:00
|
|
|
import { attempt, isError, take } from 'lodash';
|
2018-07-17 19:13:52 -04:00
|
|
|
import uuid from 'uuid/v4';
|
2019-03-15 10:19:57 -04:00
|
|
|
import { EditorialWorkflowError, Cursor, CURSOR_COMPATIBILITY_SYMBOL } from 'netlify-cms-lib-util';
|
2018-07-17 19:13:52 -04:00
|
|
|
import AuthenticationPage from './AuthenticationPage';
|
|
|
|
|
|
|
|
window.repoFiles = window.repoFiles || {};
|
|
|
|
window.repoFilesUnpublished = window.repoFilesUnpublished || [];
|
|
|
|
|
|
|
|
function getFile(path) {
|
|
|
|
const segments = path.split('/');
|
|
|
|
let obj = window.repoFiles;
|
|
|
|
while (obj && segments.length) {
|
|
|
|
obj = obj[segments.shift()];
|
|
|
|
}
|
|
|
|
return obj || {};
|
|
|
|
}
|
|
|
|
|
|
|
|
const pageSize = 10;
|
|
|
|
|
|
|
|
const getCursor = (collection, extension, entries, index) => {
|
|
|
|
const count = entries.length;
|
|
|
|
const pageCount = Math.floor(count / pageSize);
|
|
|
|
return Cursor.create({
|
|
|
|
actions: [
|
2018-08-07 14:46:54 -06:00
|
|
|
...(index < pageCount ? ['next', 'last'] : []),
|
|
|
|
...(index > 0 ? ['prev', 'first'] : []),
|
2018-07-17 19:13:52 -04:00
|
|
|
],
|
|
|
|
meta: { index, count, pageSize, pageCount },
|
|
|
|
data: { collection, extension, index, pageCount },
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
const getFolderEntries = (folder, extension) => {
|
|
|
|
return Object.keys(window.repoFiles[folder] || {})
|
2018-08-07 14:46:54 -06:00
|
|
|
.filter(path => path.endsWith(`.${extension}`))
|
2018-07-17 19:13:52 -04:00
|
|
|
.map(path => ({
|
2018-08-07 14:46:54 -06:00
|
|
|
file: { path: `${folder}/${path}` },
|
2018-07-17 19:13:52 -04:00
|
|
|
data: window.repoFiles[folder][path].content,
|
|
|
|
}))
|
|
|
|
.reverse();
|
|
|
|
};
|
|
|
|
|
|
|
|
export default class TestRepo {
|
2018-07-23 12:14:53 -04:00
|
|
|
constructor(config, options = {}) {
|
2018-07-17 19:13:52 -04:00
|
|
|
this.config = config;
|
|
|
|
this.assets = [];
|
2018-07-23 12:14:53 -04:00
|
|
|
this.options = options;
|
2018-07-17 19:13:52 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
authComponent() {
|
|
|
|
return AuthenticationPage;
|
|
|
|
}
|
|
|
|
|
|
|
|
restoreUser(user) {
|
|
|
|
return this.authenticate(user);
|
|
|
|
}
|
|
|
|
|
|
|
|
authenticate() {
|
|
|
|
return Promise.resolve();
|
|
|
|
}
|
|
|
|
|
|
|
|
logout() {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
getToken() {
|
|
|
|
return Promise.resolve('');
|
|
|
|
}
|
|
|
|
|
|
|
|
traverseCursor(cursor, action) {
|
|
|
|
const { collection, extension, index, pageCount } = cursor.data.toObject();
|
|
|
|
const newIndex = (() => {
|
2018-08-07 14:46:54 -06:00
|
|
|
if (action === 'next') {
|
|
|
|
return index + 1;
|
|
|
|
}
|
|
|
|
if (action === 'prev') {
|
|
|
|
return index - 1;
|
|
|
|
}
|
|
|
|
if (action === 'first') {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (action === 'last') {
|
|
|
|
return pageCount;
|
|
|
|
}
|
2018-07-17 19:13:52 -04:00
|
|
|
})();
|
|
|
|
// TODO: stop assuming cursors are for collections
|
|
|
|
const allEntries = getFolderEntries(collection.get('folder'), extension);
|
2018-08-07 14:46:54 -06:00
|
|
|
const entries = allEntries.slice(newIndex * pageSize, newIndex * pageSize + pageSize);
|
2018-07-17 19:13:52 -04:00
|
|
|
const newCursor = getCursor(collection, extension, allEntries, newIndex);
|
|
|
|
return Promise.resolve({ entries, cursor: newCursor });
|
|
|
|
}
|
|
|
|
|
|
|
|
entriesByFolder(collection, extension) {
|
|
|
|
const folder = collection.get('folder');
|
|
|
|
const entries = folder ? getFolderEntries(folder, extension) : [];
|
|
|
|
const cursor = getCursor(collection, extension, entries, 0);
|
|
|
|
const ret = take(entries, pageSize);
|
|
|
|
ret[CURSOR_COMPATIBILITY_SYMBOL] = cursor;
|
|
|
|
return Promise.resolve(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
entriesByFiles(collection) {
|
|
|
|
const files = collection.get('files').map(collectionFile => ({
|
|
|
|
path: collectionFile.get('file'),
|
|
|
|
label: collectionFile.get('label'),
|
|
|
|
}));
|
2018-08-07 14:46:54 -06:00
|
|
|
return Promise.all(
|
|
|
|
files.map(file => ({
|
|
|
|
file,
|
|
|
|
data: getFile(file.path).content,
|
|
|
|
})),
|
|
|
|
);
|
2018-07-17 19:13:52 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
getEntry(collection, slug, path) {
|
|
|
|
return Promise.resolve({
|
|
|
|
file: { path },
|
|
|
|
data: getFile(path).content,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
unpublishedEntries() {
|
|
|
|
return Promise.resolve(window.repoFilesUnpublished);
|
|
|
|
}
|
|
|
|
|
|
|
|
unpublishedEntry(collection, slug) {
|
2018-08-07 14:46:54 -06:00
|
|
|
const entry = window.repoFilesUnpublished.find(
|
|
|
|
e => e.metaData.collection === collection.get('name') && e.slug === slug,
|
|
|
|
);
|
2018-07-17 19:13:52 -04:00
|
|
|
if (!entry) {
|
2018-08-07 14:46:54 -06:00
|
|
|
return Promise.reject(
|
|
|
|
new EditorialWorkflowError('content is not under editorial workflow', true),
|
|
|
|
);
|
2018-07-17 19:13:52 -04:00
|
|
|
}
|
|
|
|
return Promise.resolve(entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
deleteUnpublishedEntry(collection, slug) {
|
|
|
|
const unpubStore = window.repoFilesUnpublished;
|
2018-08-07 14:46:54 -06:00
|
|
|
const existingEntryIndex = unpubStore.findIndex(
|
|
|
|
e => e.metaData.collection === collection && e.slug === slug,
|
|
|
|
);
|
2018-07-17 19:13:52 -04:00
|
|
|
unpubStore.splice(existingEntryIndex, 1);
|
|
|
|
return Promise.resolve();
|
|
|
|
}
|
|
|
|
|
2018-08-07 09:49:53 -06:00
|
|
|
persistEntry({ path, raw, slug }, mediaFiles, options = {}) {
|
2018-08-01 15:06:22 -04:00
|
|
|
if (options.useWorkflow) {
|
2018-07-17 19:13:52 -04:00
|
|
|
const unpubStore = window.repoFilesUnpublished;
|
|
|
|
const existingEntryIndex = unpubStore.findIndex(e => e.file.path === path);
|
|
|
|
if (existingEntryIndex >= 0) {
|
|
|
|
const unpubEntry = { ...unpubStore[existingEntryIndex], data: raw };
|
|
|
|
unpubEntry.title = options.parsedData && options.parsedData.title;
|
|
|
|
unpubEntry.description = options.parsedData && options.parsedData.description;
|
|
|
|
unpubStore.splice(existingEntryIndex, 1, unpubEntry);
|
|
|
|
} else {
|
|
|
|
const unpubEntry = {
|
|
|
|
data: raw,
|
|
|
|
file: {
|
|
|
|
path,
|
|
|
|
},
|
|
|
|
metaData: {
|
|
|
|
collection: options.collectionName,
|
2018-07-31 12:17:25 -04:00
|
|
|
status: this.options.initialWorkflowStatus,
|
2018-07-17 19:13:52 -04:00
|
|
|
title: options.parsedData && options.parsedData.title,
|
|
|
|
description: options.parsedData && options.parsedData.description,
|
|
|
|
},
|
|
|
|
slug,
|
|
|
|
};
|
|
|
|
unpubStore.push(unpubEntry);
|
|
|
|
}
|
|
|
|
return Promise.resolve();
|
|
|
|
}
|
|
|
|
|
|
|
|
const newEntry = options.newEntry || false;
|
|
|
|
const folder = path.substring(0, path.lastIndexOf('/'));
|
|
|
|
const fileName = path.substring(path.lastIndexOf('/') + 1);
|
|
|
|
window.repoFiles[folder] = window.repoFiles[folder] || {};
|
|
|
|
window.repoFiles[folder][fileName] = window.repoFiles[folder][fileName] || {};
|
|
|
|
if (newEntry) {
|
|
|
|
window.repoFiles[folder][fileName] = { content: raw };
|
|
|
|
} else {
|
|
|
|
window.repoFiles[folder][fileName].content = raw;
|
|
|
|
}
|
|
|
|
return Promise.resolve();
|
|
|
|
}
|
|
|
|
|
|
|
|
updateUnpublishedEntryStatus(collection, slug, newStatus) {
|
|
|
|
const unpubStore = window.repoFilesUnpublished;
|
2018-08-07 14:46:54 -06:00
|
|
|
const entryIndex = unpubStore.findIndex(
|
|
|
|
e => e.metaData.collection === collection && e.slug === slug,
|
|
|
|
);
|
2018-07-17 19:13:52 -04:00
|
|
|
unpubStore[entryIndex].metaData.status = newStatus;
|
|
|
|
return Promise.resolve();
|
|
|
|
}
|
|
|
|
|
|
|
|
publishUnpublishedEntry(collection, slug) {
|
|
|
|
const unpubStore = window.repoFilesUnpublished;
|
2018-08-07 14:46:54 -06:00
|
|
|
const unpubEntryIndex = unpubStore.findIndex(
|
|
|
|
e => e.metaData.collection === collection && e.slug === slug,
|
|
|
|
);
|
2018-07-17 19:13:52 -04:00
|
|
|
const unpubEntry = unpubStore[unpubEntryIndex];
|
|
|
|
const entry = { raw: unpubEntry.data, slug: unpubEntry.slug, path: unpubEntry.file.path };
|
|
|
|
unpubStore.splice(unpubEntryIndex, 1);
|
|
|
|
return this.persistEntry(entry);
|
|
|
|
}
|
|
|
|
getMedia() {
|
|
|
|
return Promise.resolve(this.assets);
|
|
|
|
}
|
|
|
|
|
|
|
|
persistMedia({ fileObj }) {
|
|
|
|
const { name, size } = fileObj;
|
|
|
|
const objectUrl = attempt(window.URL.createObjectURL, fileObj);
|
|
|
|
const url = isError(objectUrl) ? '' : objectUrl;
|
|
|
|
const normalizedAsset = { id: uuid(), name, size, path: url, url };
|
|
|
|
|
|
|
|
this.assets.push(normalizedAsset);
|
|
|
|
return Promise.resolve(normalizedAsset);
|
|
|
|
}
|
|
|
|
|
2018-08-07 09:53:31 -06:00
|
|
|
deleteFile(path) {
|
2018-07-17 19:13:52 -04:00
|
|
|
const assetIndex = this.assets.findIndex(asset => asset.path === path);
|
|
|
|
if (assetIndex > -1) {
|
|
|
|
this.assets.splice(assetIndex, 1);
|
2018-08-07 14:46:54 -06:00
|
|
|
} else {
|
2018-07-17 19:13:52 -04:00
|
|
|
const folder = path.substring(0, path.lastIndexOf('/'));
|
|
|
|
const fileName = path.substring(path.lastIndexOf('/') + 1);
|
|
|
|
delete window.repoFiles[folder][fileName];
|
|
|
|
}
|
|
|
|
|
|
|
|
return Promise.resolve();
|
|
|
|
}
|
|
|
|
}
|