import fh from 'filehound'; import fs from 'fs-extra'; import sanitize from 'sanitize-html'; import metadataParser from 'markdown-yaml-metadata-parser'; import _ from 'lodash'; import * as DataEvent from '../../src/com/events/DataEvent'; import Navigation from './Navigation'; import StringUtils from '../../src/com/utils/StringUtils'; const nav = new Navigation(); const moment = require('moment'); const pug = require('pug'); const md = require('markdown-it')('commonmark'); export default class Pages { //-------------------------- // constructor //-------------------------- constructor() {} //-------------------------- // methods //-------------------------- start() {} /** * Retrieves single page or pages * @parameter id: optional id if requesting a single Page */ getPage(id) { return new Promise((resolve, reject) => { fh.create() .paths('content/pages') .ext('md') .find() .then(files => { let pages = []; for (let index = 0; index < files.length; index++) { fs.readFile(files[index], { encoding: 'utf8' }, (err, file) => { pages.push(metadataParser(file)); }); } if (id === null || id === null || id === undefined) { setTimeout(() => { //TODO: Duct tape solution until something better created resolve(pages); }, 100); } else { setTimeout(() => { //TODO: Duct tape solution until something better created let page = _.find(pages, list => { return list.metadata.uuid === id; }); resolve(page); }, 100); } }) .catch(err => { reject(err); }); }); } /** * Edits single page based on id and task * @parameter body: object that contains all page information * @parameter id: identifier for page being edited * @parameter task: type of task being performed - listed in DataEvents Class * @parameter user: object containin user information */ editPage(body, id, task, user) { return new Promise((resolve, reject) => { let self = this; let response = []; switch (task) { case DataEvent.API_PAGE_CREATE: case DataEvent.API_PAGE_WRITE: var pageWrite = '---\n' + 'id: ' + body.id + '\n' + 'uuid: ' + body.uuid + '\n' + 'title: ' + body.title + '\n' + 'feature: ' + body.feature + '\n' + 'layout: ' + 'page' + '\n' + 'tags: ' + body.tags + '\n' + 'author: ' + user.handle + '\n' + 'created: ' + moment(body.created).format() + '\n' + 'updated: ' + moment(Date.now()).format() + '\n' + 'deleted: ' + body.deleted + '\n' + 'menu: ' + body.menu + '\n' + 'featured: ' + body.featured + '\n' + 'published: ' + body.published + '\n' + 'slug: ' + body.slug + '\n' + '---\n' + body.content; fs.writeFile('content/pages/' + body.slug + '.md', pageWrite, err => { // throws an error, you could also catch it here if (err) { response = { type: DataEvent.PAGE_ERROR, message: err }; reject(response); } // success case, the file was saved if (task === DataEvent.API_PAGE_CREATE) { // if new file, update settings index and page count response = { type: DataEvent.PAGE_ADDED, message: 'New Page Created', id: body.page_uuid }; } else { response = { type: DataEvent.PAGE_UPDATED, message: 'Page saved. Nice Work' }; resolve(response); } }); break; case DataEvent.API_PAGE_DELETE: this.getPage(id) .then(page => { let body = _.mapValues(page.metadata); body.content = page.content; body.deleted = moment(Date.now()).format(); self.editPage(body, body.uuid, DataEvent.API_PAGE_WRITE, user) .then(() => { let item = { title: body.title, id: body.id, slug: body.slug, uuid: body.uuid }; nav.editMenu(DataEvent.MENU_DELETE_ITEM, item); response = { type: DataEvent.PAGE_DELETED, message: 'Page deleted, sport', data: { uuid: body.uuid } }; resolve(response); }) .catch(err => { response = { type: DataEvent.PAGE_ERROR, message: err }; reject(response); }); }) .catch(err => { response = { type: DataEvent.PAGE_ERROR, message: err }; reject(response); }); break; } }); } /** * Renders all pages from markdown to html * @parameter theme: current theme being used as defined in settings */ publish(theme) { return new Promise((resolve, reject) => { this.getPage() .then(pages => { let response = []; for (let index = 0; index < pages.length; index++) { const page = pages[index]; if (page.metadata.layout === 'index') { let buffed = sanitize(page.content, { allowedTags: ['del', 'a', 'iframe', 'img'], allowedAttributes: { a: ['href', 'name', 'target'], img: ['src'], iframe: [ 'height', 'width', 'src', 'frameborder', 'allow', 'allowfullscreen' ] } }); buffed = new StringUtils().decodeHTML(buffed); let html = md.render(buffed, { html: true, xhtmlOut: true }); let file = pug.renderFile('content/themes/' + theme + '/index.pug', { title: page.metadata.title, default_bg: page.metadata.feature, content_index: html }); fs.writeFile('public/index.html', file, err => { // throws an error, you could also catch it here if (err) { response = { type: DataEvent.PAGES_NOT_RENDERED, message: err }; reject(response); } // success case, the file was saved response = { type: DataEvent.PAGES_RENDERED, message: 'All Pages Rendered. Sweet.' }; resolve(response); }); } } }) .catch(err => { reject(err); }); }); } //-------------------------- // event handlers //-------------------------- }