<commit_before>import TestRepoBackend from './test-repo/implementation';
import GitHubBackend from './github/implementation';
import NetlifyGitBackend from './netlify-git/implementation';
import { resolveFormat } from '../formats/formats';
import { selectListMethod, selectEntrySlug, selectEntryPath, selectAllowNewEntries } from '../reducers/collections';
import { createEntry } from '../valueObjects/Entry';

class LocalStorageAuthStore {
  storageKey = 'nf-cms-user';

  retrieve() {
    const data = window.localStorage.getItem(this.storageKey);
    return data && JSON.parse(data);
  }

  store(userData) {
    window.localStorage.setItem(this.storageKey, JSON.stringify(userData));
  }

  logout() {
    window.localStorage.removeItem(this.storageKey);
  }
}

const slugFormatter = (template = '{{slug}}', entryData) => {
  const date = new Date();
  const identifier = entryData.get('title', entryData.get('path'));
  return template.replace(/\{\{([^\}]+)\}\}/g, (_, field) => {
    switch (field) {
      case 'year':
        return date.getFullYear();
      case 'month':
        return (`0${ date.getMonth() + 1 }`).slice(-2);
      case 'day':
        return (`0${ date.getDate() }`).slice(-2);
      case 'slug':
        return identifier.trim().toLowerCase().replace(/[^a-z0-9\.\-_]+/gi, '-');
      default:
        return entryData.get(field);
    }
  });
};

class Backend {
  constructor(implementation, authStore = null) {
    this.implementation = implementation;
    this.authStore = authStore;
    if (this.implementation === null) {
      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) {
      this.implementation.setUser(stored);
      return stored;
    }
    return null;
  }

  authComponent() {
    return this.implementation.authComponent();
  }

  authenticate(credentials) {
    return this.implementation.authenticate(credentials).then((user) => {
      if (this.authStore) { this.authStore.store(user); }
      return user;
    });
  }

  logout() {
    if (this.authStore) {
      this.authStore.logout();
    } else {
      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(
          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)),
        }
      ));
  }

  getEntry(collection, slug) {
    return this.implementation.getEntry(collection, slug, selectEntryPath(collection, slug))
      .then(loadedEntry => this.entryWithFormat(collection, slug)(createEntry(
        collection.get('name'),
        slug,
        loadedEntry.file.path,
        { raw: loadedEntry.data, label: loadedEntry.file.label }
      ))
    );
  }

  newEntry(collection) {
    return createEntry(collection.get('name'));
  }

  entryWithFormat(collectionOrEntity) {
    return (entry) => {
      const format = resolveFormat(collectionOrEntity, entry);
      if (entry && entry.raw) {
        return Object.assign(entry, { data: format && format.fromFile(entry.raw) });
      }
      return format.fromFile(entry);
    };
  }

  unpublishedEntries(page, perPage) {
    return this.implementation.unpublishedEntries(page, perPage)
    .then(loadedEntries => loadedEntries.filter(entry => entry !== null))
    .then(entries => (
      entries.map((loadedEntry) => {
        const entry = createEntry('draft', loadedEntry.slug, loadedEntry.file.path, { raw: loadedEntry.data });
        entry.metaData = loadedEntry.metaData;
        return entry;
      })
    ))
    .then(entries => ({
      pagination: 0,
      entries: entries.map(this.entryWithFormat('editorialWorkflow')),
    }));
  }

  unpublishedEntry(collection, slug) {
    return this.implementation.unpublishedEntry(collection, slug)
    .then((loadedEntry) => {
      const entry = createEntry('draft', loadedEntry.slug, loadedEntry.file.path, { raw: loadedEntry.data });
      entry.metaData = loadedEntry.metaData;
      return entry;
    })
    .then(this.entryWithFormat(collection, slug));
  }

  persistEntry(config, collection, entryDraft, MediaFiles, options) {
    const newEntry = entryDraft.getIn(['entry', 'newRecord']) || false;

    const parsedData = {
      title: entryDraft.getIn(['entry', 'data', 'title'], 'No Title'),
      description: entryDraft.getIn(['entry', 'data', 'description'], 'No Description!'),
    };

    const entryData = entryDraft.getIn(['entry', 'data']).toJS();
    let entryObj;
    if (newEntry) {
      if (!selectAllowNewEntries(collection)) {
        throw (new Error('Not allowed to create new entries in this collection'));
      }
      const slug = slugFormatter(collection.get('slug'), entryDraft.getIn(['entry', 'data']));
      const path = selectEntryPath(collection, slug);
      entryObj = {
        path,
        slug,
        raw: this.entryToRaw(collection, Object.assign({ path }, entryData)),
      };
    } else {
      const path = entryDraft.getIn(['entry', 'path']);
      entryObj = {
        path,
        slug: entryDraft.getIn(['entry', 'slug']),
        raw: this.entryToRaw(collection, Object.assign({ path }, entryData)),
      };
    }

    const commitMessage = `${ (newEntry ? 'Created ' : 'Updated ') +
          collection.get('label') } “${
          entryDraft.getIn(['entry', 'data', 'title']) }”`;

    const mode = config.get('publish_mode');

    const collectionName = collection.get('name');

    return this.implementation.persistEntry(entryObj, MediaFiles, {
      newEntry, parsedData, commitMessage, collectionName, mode, ...options,
    });
  }

  persistUnpublishedEntry(config, collection, entryDraft, MediaFiles) {
    return this.persistEntry(config, collection, entryDraft, MediaFiles, { unpublished: true });<commit_msg>Fix: Path was being incorrectly injected on entry for persistence. Closes #176<commit_after>import TestRepoBackend from './test-repo/implementation';
import GitHubBackend from './github/implementation';
import NetlifyGitBackend from './netlify-git/implementation';
import { resolveFormat } from '../formats/formats';
import { selectListMethod, selectEntrySlug, selectEntryPath, selectAllowNewEntries } from '../reducers/collections';
import { createEntry } from '../valueObjects/Entry';

class LocalStorageAuthStore {
  storageKey = 'nf-cms-user';

  retrieve() {
    const data = window.localStorage.getItem(this.storageKey);
    return data && JSON.parse(data);
  }

  store(userData) {
    window.localStorage.setItem(this.storageKey, JSON.stringify(userData));
  }

  logout() {
    window.localStorage.removeItem(this.storageKey);
  }
}

const slugFormatter = (template = '{{slug}}', entryData) => {
  const date = new Date();
  const identifier = entryData.get('title', entryData.get('path'));
  return template.replace(/\{\{([^\}]+)\}\}/g, (_, field) => {
    switch (field) {
      case 'year':
        return date.getFullYear();
      case 'month':
        return (`0${ date.getMonth() + 1 }`).slice(-2);
      case 'day':
        return (`0${ date.getDate() }`).slice(-2);
      case 'slug':
        return identifier.trim().toLowerCase().replace(/[^a-z0-9\.\-_]+/gi, '-');
      default:
        return entryData.get(field);
    }
  });
};

class Backend {
  constructor(implementation, authStore = null) {
    this.implementation = implementation;
    this.authStore = authStore;
    if (this.implementation === null) {
      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) {
      this.implementation.setUser(stored);
      return stored;
    }
    return null;
  }

  authComponent() {
    return this.implementation.authComponent();
  }

  authenticate(credentials) {
    return this.implementation.authenticate(credentials).then((user) => {
      if (this.authStore) { this.authStore.store(user); }
      return user;
    });
  }

  logout() {
    if (this.authStore) {
      this.authStore.logout();
    } else {
      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(
          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)),
        }
      ));
  }

  getEntry(collection, slug) {
    return this.implementation.getEntry(collection, slug, selectEntryPath(collection, slug))
      .then(loadedEntry => this.entryWithFormat(collection, slug)(createEntry(
        collection.get('name'),
        slug,
        loadedEntry.file.path,
        { raw: loadedEntry.data, label: loadedEntry.file.label }
      ))
    );
  }

  newEntry(collection) {
    return createEntry(collection.get('name'));
  }

  entryWithFormat(collectionOrEntity) {
    return (entry) => {
      const format = resolveFormat(collectionOrEntity, entry);
      if (entry && entry.raw) {
        return Object.assign(entry, { data: format && format.fromFile(entry.raw) });
      }
      return format.fromFile(entry);
    };
  }

  unpublishedEntries(page, perPage) {
    return this.implementation.unpublishedEntries(page, perPage)
    .then(loadedEntries => loadedEntries.filter(entry => entry !== null))
    .then(entries => (
      entries.map((loadedEntry) => {
        const entry = createEntry('draft', loadedEntry.slug, loadedEntry.file.path, { raw: loadedEntry.data });
        entry.metaData = loadedEntry.metaData;
        return entry;
      })
    ))
    .then(entries => ({
      pagination: 0,
      entries: entries.map(this.entryWithFormat('editorialWorkflow')),
    }));
  }

  unpublishedEntry(collection, slug) {
    return this.implementation.unpublishedEntry(collection, slug)
    .then((loadedEntry) => {
      const entry = createEntry('draft', loadedEntry.slug, loadedEntry.file.path, { raw: loadedEntry.data });
      entry.metaData = loadedEntry.metaData;
      return entry;
    })
    .then(this.entryWithFormat(collection, slug));
  }

  persistEntry(config, collection, entryDraft, MediaFiles, options) {
    const newEntry = entryDraft.getIn(['entry', 'newRecord']) || false;

    const parsedData = {
      title: entryDraft.getIn(['entry', 'data', 'title'], 'No Title'),
      description: entryDraft.getIn(['entry', 'data', 'description'], 'No Description!'),
    };

    const entryData = entryDraft.getIn(['entry', 'data']).toJS();
    let entryObj;
    if (newEntry) {
      if (!selectAllowNewEntries(collection)) {
        throw (new Error('Not allowed to create new entries in this collection'));
      }
      const slug = slugFormatter(collection.get('slug'), entryDraft.getIn(['entry', 'data']));
      const path = selectEntryPath(collection, slug);
      entryObj = {
        path,
        slug,
        raw: this.entryToRaw(collection, entryData),
      };
    } else {
      const path = entryDraft.getIn(['entry', 'path']);
      entryObj = {
        path,
        slug: entryDraft.getIn(['entry', 'slug']),
        raw: this.entryToRaw(collection, entryData),
      };
    }

    const commitMessage = `${ (newEntry ? 'Created ' : 'Updated ') +
          collection.get('label') } “${
          entryDraft.getIn(['entry', 'data', 'title']) }”`;

    const mode = config.get('publish_mode');

    const collectionName = collection.get('name');

    return this.implementation.persistEntry(entryObj, MediaFiles, {
      newEntry, parsedData, commitMessage, collectionName, mode, ...options,
    });
  }

  persistUnpublishedEntry(config, collection, entryDraft, MediaFiles) {
    return this.persistEntry(config, collection, entryDraft, MediaFiles, { unpublished: true });
{'fraction_non_alphanumeric': 0.14838093722650966, 'fraction_numerical': 0.0015116556607526453, 'mean_word_length': 3.158121071782997, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 31, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2937637', 'n_tokens_mistral': 3751, 'n_tokens_neox': 3655, 'n_words': 725}