static-cms/src/backends/backend.js

240 lines
7.4 KiB
JavaScript
Raw Normal View History

2016-12-23 16:59:48 -02:00
import TestRepoBackend from "./test-repo/implementation";
import GitHubBackend from "./github/implementation";
import NetlifyGitBackend from "./netlify-git/implementation";
import NetlifyAuthBackend from "./netlify-auth/implementation";
import { resolveFormat } from "../formats/formats";
import { selectListMethod, selectEntrySlug, selectEntryPath, selectAllowNewEntries } from "../reducers/collections";
import { createEntry } from "../valueObjects/Entry";
2016-05-30 16:55:32 -07:00
class LocalStorageAuthStore {
2016-12-23 16:59:48 -02:00
storageKey = "nf-cms-user";
2016-05-30 16:55:32 -07:00
retrieve() {
const data = window.localStorage.getItem(this.storageKey);
return data && JSON.parse(data);
}
2016-05-30 16:55:32 -07:00
store(userData) {
window.localStorage.setItem(this.storageKey, JSON.stringify(userData));
}
logout() {
window.localStorage.removeItem(this.storageKey);
}
}
2016-12-23 16:59:48 -02:00
const slugFormatter = (template = "{{slug}}", entryData) => {
const date = new Date();
2016-12-23 16:59:48 -02:00
const identifier = entryData.get("title", entryData.get("path"));
2016-10-28 11:42:31 -02:00
return template.replace(/\{\{([^\}]+)\}\}/g, (_, field) => {
switch (field) {
2016-12-23 16:59:48 -02:00
case "year":
return date.getFullYear();
2016-12-23 16:59:48 -02:00
case "month":
return (`0${ date.getMonth() + 1 }`).slice(-2);
2016-12-23 16:59:48 -02:00
case "day":
return (`0${ date.getDate() }`).slice(-2);
2016-12-23 16:59:48 -02:00
case "slug":
return identifier.trim().toLowerCase().replace(/[^a-z0-9\.\-_]+/gi, "-");
default:
2016-12-23 16:59:48 -02:00
return entryData.get(field, "").trim().toLowerCase().replace(/[^a-z0-9\.\-_]+/gi, "-");
}
});
};
class Backend {
constructor(implementation, authStore = null) {
this.implementation = implementation;
this.authStore = authStore;
if (this.implementation === null) {
2016-12-23 16:59:48 -02:00
throw new Error("Cannot instantiate a Backend with no implementation");
}
}
currentUser() {
if (this.user) { return this.user; }
const stored = this.authStore && this.authStore.retrieve();
if (stored) {
2016-12-23 16:59:48 -02:00
return Promise.resolve(this.implementation.setUser(stored)).then(() => stored);
}
2016-12-23 16:59:48 -02:00
return Promise.resolve(null);
}
authComponent() {
return this.implementation.authComponent();
}
authenticate(credentials) {
2016-05-30 16:55:32 -07:00
return this.implementation.authenticate(credentials).then((user) => {
if (this.authStore) { this.authStore.store(user); }
return user;
});
}
logout() {
if (this.authStore) {
this.authStore.logout();
} else {
2016-12-23 16:59:48 -02:00
throw new Error("User isn't authenticated.");
}
}
listEntries(collection) {
const listMethod = this.implementation[selectListMethod(collection)];
return listMethod.call(this.implementation, collection)
.then(loadedEntries => (
loadedEntries.map(loadedEntry => createEntry(
2016-12-23 16:59:48 -02:00
collection.get("name"),
selectEntrySlug(collection, loadedEntry.file.path),
loadedEntry.file.path,
{ raw: loadedEntry.data, label: loadedEntry.file.label }
))
))
.then(entries => (
{
entries: entries.map(this.entryWithFormat(collection)),
}
));
}
2016-10-27 13:12:18 -02:00
getEntry(collection, slug) {
return this.implementation.getEntry(collection, slug, selectEntryPath(collection, slug))
2016-10-27 15:33:15 +02:00
.then(loadedEntry => this.entryWithFormat(collection, slug)(createEntry(
2016-12-23 16:59:48 -02:00
collection.get("name"),
slug,
loadedEntry.file.path,
{ raw: loadedEntry.data, label: loadedEntry.file.label }
2016-10-27 14:45:32 +02:00
))
);
}
2016-09-06 13:04:17 -03:00
entryWithFormat(collectionOrEntity) {
return (entry) => {
2016-09-06 13:04:17 -03:00
const format = resolveFormat(collectionOrEntity, entry);
if (entry && entry.raw) {
2016-10-27 14:45:32 +02:00
return Object.assign(entry, { data: format && format.fromFile(entry.raw) });
}
2016-10-27 14:45:32 +02:00
return format.fromFile(entry);
};
}
2016-09-06 13:04:17 -03:00
unpublishedEntries(page, perPage) {
return this.implementation.unpublishedEntries(page, perPage)
2016-10-28 11:42:31 -02:00
.then(loadedEntries => loadedEntries.filter(entry => entry !== null))
.then(entries => (
entries.map((loadedEntry) => {
2016-12-23 16:59:48 -02:00
const entry = createEntry("draft", loadedEntry.slug, loadedEntry.file.path, { raw: loadedEntry.data });
entry.metaData = loadedEntry.metaData;
return entry;
})
))
2016-10-28 11:42:31 -02:00
.then(entries => ({
pagination: 0,
2016-12-23 16:59:48 -02:00
entries: entries.map(this.entryWithFormat("editorialWorkflow")),
2016-10-28 11:42:31 -02:00
}));
2016-09-06 13:04:17 -03:00
}
unpublishedEntry(collection, slug) {
return this.implementation.unpublishedEntry(collection, slug)
2016-10-28 11:42:31 -02:00
.then((loadedEntry) => {
2016-12-23 16:59:48 -02:00
const entry = createEntry("draft", loadedEntry.slug, loadedEntry.file.path, { raw: loadedEntry.data });
2016-10-28 11:42:31 -02:00
entry.metaData = loadedEntry.metaData;
return entry;
})
.then(this.entryWithFormat(collection, slug));
}
persistEntry(config, collection, entryDraft, MediaFiles, options) {
2016-12-23 16:59:48 -02:00
const newEntry = entryDraft.getIn(["entry", "newRecord"]) || false;
const parsedData = {
2016-12-23 16:59:48 -02:00
title: entryDraft.getIn(["entry", "data", "title"], "No Title"),
description: entryDraft.getIn(["entry", "data", "description"], "No Description!"),
};
2016-12-23 16:59:48 -02:00
const entryData = entryDraft.getIn(["entry", "data"]).toJS();
let entryObj;
if (newEntry) {
if (!selectAllowNewEntries(collection)) {
2016-12-23 16:59:48 -02:00
throw (new Error("Not allowed to create new entries in this collection"));
}
2016-12-23 16:59:48 -02:00
const slug = slugFormatter(collection.get("slug"), entryDraft.getIn(["entry", "data"]));
const path = selectEntryPath(collection, slug);
entryObj = {
2016-10-28 04:51:37 +02:00
path,
slug,
raw: this.entryToRaw(collection, entryData),
};
} else {
2016-12-23 16:59:48 -02:00
const path = entryDraft.getIn(["entry", "path"]);
entryObj = {
2016-10-28 04:51:37 +02:00
path,
2016-12-23 16:59:48 -02:00
slug: entryDraft.getIn(["entry", "slug"]),
raw: this.entryToRaw(collection, entryData),
};
}
2016-07-19 17:11:22 -03:00
2016-12-23 16:59:48 -02:00
const commitMessage = `${ (newEntry ? "Created " : "Updated ") +
collection.get("label") } ${ entryObj.slug }`;
2016-07-19 17:11:22 -03:00
2016-12-23 16:59:48 -02:00
const mode = config.get("publish_mode");
2016-12-23 16:59:48 -02:00
const collectionName = collection.get("name");
return this.implementation.persistEntry(entryObj, MediaFiles, {
newEntry, parsedData, commitMessage, collectionName, mode, ...options,
});
}
2016-09-13 16:00:24 -03:00
persistUnpublishedEntry(config, collection, entryDraft, MediaFiles) {
return this.persistEntry(config, collection, entryDraft, MediaFiles, { unpublished: true });
}
updateUnpublishedEntryStatus(collection, slug, newStatus) {
return this.implementation.updateUnpublishedEntryStatus(collection, slug, newStatus);
}
2016-09-14 18:25:45 -03:00
publishUnpublishedEntry(collection, slug, status) {
return this.implementation.publishUnpublishedEntry(collection, slug, status);
}
entryToRaw(collection, entry) {
const format = resolveFormat(collection, entry);
return format && format.toFile(entry);
}
}
2016-05-30 16:55:32 -07:00
export function resolveBackend(config) {
2016-12-23 16:59:48 -02:00
const name = config.getIn(["backend", "name"]);
2016-05-30 16:55:32 -07:00
if (name == null) {
2016-12-23 16:59:48 -02:00
throw new Error("No backend defined in configuration");
2016-05-30 16:55:32 -07:00
}
const authStore = new LocalStorageAuthStore();
switch (name) {
2016-12-23 16:59:48 -02:00
case "test-repo":
2016-10-27 13:12:18 -02:00
return new Backend(new TestRepoBackend(config), authStore);
2016-12-23 16:59:48 -02:00
case "github":
2016-10-27 13:12:18 -02:00
return new Backend(new GitHubBackend(config), authStore);
2016-12-23 16:59:48 -02:00
case "netlify-git":
2016-10-27 13:12:18 -02:00
return new Backend(new NetlifyGitBackend(config), authStore);
2016-12-23 16:59:48 -02:00
case "netlify-auth":
return new Backend(new NetlifyAuthBackend(config), authStore);
2016-05-30 16:55:32 -07:00
default:
2016-10-27 14:45:32 +02:00
throw new Error(`Backend not found: ${ name }`);
2016-05-30 16:55:32 -07:00
}
}
export const currentBackend = (function () {
let backend = null;
return (config) => {
if (backend) { return backend; }
2016-12-23 16:59:48 -02:00
if (config.get("backend")) {
return backend = resolveBackend(config);
}
};
}());