begin transition to php environment for rebuild

This commit is contained in:
Ro 2020-11-11 15:22:58 -08:00
parent 125256838c
commit 05ff48a51c
43 changed files with 5 additions and 16232 deletions

View file

@ -3,4 +3,5 @@ README.md
*.pug
*.sass
*.json
*.php

View file

@ -5,7 +5,6 @@
"insertPragma": false,
"jsxBracketSameLine": false,
"jsxSingleQuote": true,
"parser": "babel",
"proseWrap": "preserve",
"requirePragma": false,
"semi": true,

View file

@ -1,235 +0,0 @@
import * as DataEvent from '../../../src/com/events/DataEvent';
import mdparser from 'markdown-yaml-metadata-parser';
const uuidv4 = require('uuid/v4');
const express = require('express');
const router = express.Router();
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const fs = require('fs-extra');
const _ = require('lodash');
const crypto = require('crypto'); // for setting up new accounts
const secret_key = '58d5aeec3c604e2837aef70bc1606f35131ab8fea9731925558f5acfaa00da60';
const moment = require('moment');
/**
* Get Auth Status
*/
router.get('/', function (req, res) {
var token = req.headers['x-access-token'];
if (!token) return res.status(401).send({ auth: false, message: 'No token provided.' });
jwt.verify(token, 'super-secret-string', function (err, decoded) {
if (err)
return res.status(500).send({ auth: false, message: 'Failed to authenticate token.' });
res.status(200).send(decoded);
});
});
/**
* Get Auth Status
*/
router.get('/status', function (req, res) {
if (req.session.user) {
let session = req.session;
res.json({
type: DataEvent.API_REQUEST_GOOD,
message: 'Auth is Good',
token: session.hashToken
});
} else {
res.json({
type: DataEvent.API_REQUEST_LAME,
message: 'NOT AUTHORIZED'
});
}
});
/**
* Login Member and return token
*/
router.post('/login', function (req, res) {
fs.readJson('site/folks.json').then(folks => {
let found = _.find(folks, { handle: req.body.handle });
if (found) {
if (!isValidPassword(found, req.body.password)) {
res.json({
type: DataEvent.REQUEST_LAME,
message: 'CHECK YOUR PASSWORD'
});
}
let token = jwt.sign({ id: found.id }, found.key, {
expiresIn: 86400 // expires in 24 hours
});
let session = req.session;
session.user = found;
session.token = token;
session.hashToken = hashToken(token);
res.json({
type: DataEvent.REQUEST_GOOD,
message: 'Welcome Back',
token: session.hashToken
});
} else {
res.json({
type: DataEvent.REQUEST_LAME,
message: 'Need to see some id, champ.'
});
}
});
});
/**
* Initial Site Setup
*/
router.post('/init', function (req, res) {
let body = req.body;
let re = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
// check email
if (!re.test(body.new_member_email)) {
res.json({
type: DataEvent.API_INIT_LAME,
message: 'Need a valid email address'
});
}
//check handle is being passed
if (body.new_member_handle === null || body.new_member_handle === '') {
res.json({
type: DataEvent.API_INIT_LAME,
message: 'No handle. Kinda need that.'
});
}
// check password match
if (
body.new_member_pass !== body.new_member_pass2 ||
body.new_member_pass === '' ||
body.new_member_pass2 === ''
) {
res.json({
type: DataEvent.API_INIT_LAME,
message: 'Passwords do not match.'
});
}
if (body.new_member_title === null || body.new_member_title === '') {
res.json({
type: DataEvent.API_INIT_LAME,
message: 'No title. Gotta call it something.'
});
}
let key = crypto
.createHash('sha256')
.update(body.new_member_pass + secret_key)
.digest('hex');
// set up config files
fs.readJson('site/init/settings-template.json').then(fresh => {
fresh.global.title = body.new_member_title;
fs.writeJSON('site/settings.json', fresh);
});
fs.readJson('site/init/folks-template.json').then(folks => {
folks[0].id = 1;
folks[0].handle = body.new_member_handle;
folks[0].email = body.new_member_email;
folks[0].password = bcrypt.hashSync(body.new_member_pass, bcrypt.genSaltSync(10), null);
folks[0].key = key;
folks[0].role = 'hnic';
folks[0].created = moment(Date.now()).format();
folks[0].updated = moment(Date.now()).format();
fs.writeJSON('site/folks.json', folks);
});
fs.writeJson('site/tags.json', { tags: [] });
//set up index file as first page
fs.readFile('site/init/index-template.md', { encoding: 'utf8' }).then(file => {
let index = mdparser(file);
let data = index.metadata;
data.uuid = uuidv4();
data.path = moment().format('YYYY') + '/' + moment().format('MM');
data.author = body.new_member_handle;
data.created = moment(Date.now()).format();
data.updated = moment(Date.now()).format();
var init =
'---\n' +
'id: ' +
data.id +
'\n' +
'uuid: ' +
data.uuid +
'\n' +
'title: ' +
data.title +
'\n' +
'feature: ' +
data.feature +
'\n' +
'path: ' +
moment(Date.now()).format('YYYY') +
'/' +
moment(Date.now()).format('MM') +
'\n' +
'layout: ' +
'index' +
'\n' +
'tags: ' +
data.tags +
'\n' +
'author: ' +
body.new_member_handle +
'\n' +
'created: ' +
moment(Date.now()).format() +
'\n' +
'updated: ' +
moment(Date.now()).format() +
'\n' +
'deleted: ' +
'false' +
'\n' +
'menu: ' +
data.menu +
'\n' +
'featured: ' +
data.featured +
'\n' +
'published: ' +
data.published +
'\n' +
'slug: ' +
data.slug +
'\n' +
'---\n' +
index.content;
fs.ensureDir('content/pages/').then(() => {
fs.writeFile('content/pages/index.md', init)
.then(() => {
//console.log('index file created');
})
.catch(() => {
//console.log('ERROR', err);
});
});
});
res.json({
type: DataEvent.API_INIT_GOOD,
message: 'All Set Up'
});
});
//router.post('/logout', function(req, res) {});
module.exports = router;
function isValidPassword(user, password) {
return bcrypt.compareSync(password, user.password);
}
function hashToken(token) {
return bcrypt.hashSync(token, bcrypt.genSaltSync(10), null);
}

View file

@ -1,107 +0,0 @@
import * as DataEvent from '../../../src/com/events/DataEvent';
import Auth from '../../data/Auth';
import Utils from '../../data/Utils';
const express = require('express');
const router = express.Router();
const multer = require('multer');
const auth = new Auth();
const utils = new Utils();
var backup_upload = multer().array('backup_upload');
var backup_restore = multer().any();
/***
CREATE BACK UP
*/
router.post('/create', (req, res) => {
auth.authCheck(req)
.then(() => {
utils
.createBackup()
.then(() => {
res.json({
type: DataEvent.API_BACKUP_CREATE,
message: "You're backed up. Hi fives"
});
})
.catch(err => {
res.json({
type: err.type,
message: err.message
});
});
})
.catch(err => {
res.json({
type: err.type,
message: err.message
});
});
});
/***
RETRIEVE BACKUP
*/
router.get('/download', (req, res) => {
if (req.session.user) {
var filePath = 'content/backup.zip'; // Or format the path using the `id` rest param
var fileName = 'backup.zip'; // The default name the browser will use
res.download(filePath, fileName);
} else {
res.json({
type: DataEvent.REQUEST_LAME,
message: "You're not logged in, champ"
});
}
//Move to route?
});
/***
RESTORE BACKUP
*/
router.post('/restore', backup_upload, (req, res) => {
auth.authCheck(req)
.then(() => {
utils
.restoreBackup(req.files[0])
.then(() => {
res.json({
type: DataEvent.API_BACKUP_RESTORE,
message: 'Settings, files and pages restored. Nice work.'
});
})
.catch(err => {
res.json({
type: err.type,
message: 'Backup not restored. Uh oh.'
});
});
})
.catch(err => {
res.json({
type: err.type,
message: err.message
});
});
});
router.post('/init-restore', backup_restore, (req, res) => {
utils
.verifyBackup(req.files[0], req.body)
.then(response => {
res.json({
type: response.type,
message: response.message
});
})
.catch(err => {
res.json({
type: err.type,
message: err.message
});
});
});
module.exports = router;

View file

@ -1,83 +0,0 @@
import Settings, { SETTINGS_FILE } from '../../data/Settings';
import Auth from '../../data/Auth';
var express = require('express');
var router = express.Router();
var nodemailer = require('nodemailer');
var mg = require('nodemailer-mailgun-transport');
const pug = require('pug');
const settings = new Settings();
const auth = new Auth();
router.post('/', function (req, res) {
auth.authCheck(req)
.then(() => {
settings
.load(SETTINGS_FILE)
.then(settings => {
let transport = '';
var auth = '';
switch (settings.email.active) {
case 'option-smtp':
auth = {
host: settings.email.smtp.domain,
port: 587,
secure: false,
auth: {
type: 'login',
user: settings.email.smtp,
pass: settings.email.smtp.password
}
};
transport = nodemailer.createTransport(auth);
break;
case 'option-mg':
auth = {
auth: {
api_key: settings.email.mailgun.key,
domain: settings.email.mailgun.domain
}
};
transport = nodemailer.createTransport(mg(auth));
break;
}
let render = pug.compileFile('brain/views/email/base.pug');
let html = render({
title: settings.global.title,
header: 'a note from ' + settings.global.title,
content: req.body.content,
footer: 'powered by fipamo'
});
transport.sendMail(
{
from: 'control@playvico.us',
to: req.session.user.email, // An array if you have multiple recipients.
subject: 'Hey beautiful',
//You can use "html:" to send HTML email content. It's magic!
html: html
//You can use "text:" to send plain-text content. It's oldschool!
//text: 'Mailgun rocks, pow pow!'
},
function (err, info) {
if (err) {
res.json({
message: 'MAIL ERROR',
desc: err
});
} else {
//console.log(info);
res.json({
message: 'MAIL SENT',
desc: info
});
}
}
);
})
.catch(() => {
//console.error(err);
});
})
.catch(err => {
res.json(err);
});
});
module.exports = router;

View file

@ -1,268 +0,0 @@
import Book from '../../data/Book';
import Auth from '../../data/Auth';
import Settings, { SETTINGS_FILE } from '../../data/Settings';
import * as DataEvent from '../../../src/com/events/DataEvent';
import Render from '../../data/Render';
const express = require('express');
const router = express.Router();
const multer = require('multer');
const fs = require('fs-extra');
const moment = require('moment');
const book = new Book();
const auth = new Auth();
const settings = new Settings();
const render = new Render();
const _ = require('lodash');
const uploadPath =
'./public/assets/images/blog/' + moment().format('YYYY') + '/' + moment().format('MM');
var storage = multer.diskStorage({
destination: function (req, file, cb) {
fs.ensureDir(uploadPath, () => {
// dir has now been created, including the directory it is to be placed in
cb(null, uploadPath);
});
},
filename: function (req, file, cb) {
var splice = file.originalname.split(':');
cb(null, splice[0]);
}
});
var feature_upload = multer({
storage: storage
}).array('feature_image');
var post_upload = multer({
storage: storage
}).array('post_image');
/**
* Retrieves a page of a published entries
* @public
*/
router.get('/published/:pageNum?', (req, res) => {
//console.log('PAGE NUM', req.params.pageNum);
let pageNum = req.params.pageNum;
if (pageNum === null || pageNum === '' || !pageNum) pageNum = 1;
let pages = [];
book.getPage().then(result => {
result.sort((a, b) => parseFloat(b.metadata.id) - parseFloat(a.metadata.id));
let displayed = _.filter(result, page => {
return (
page.metadata.deleted === false &&
page.metadata.published === true &&
page.metadata.layout != 'index'
);
});
var pageLimit = 6;
var count = Math.ceil(displayed.length / pageLimit);
if (pageNum > count || isNaN(pageNum))
res.json({ type: DataEvent.REQUEST_LAME, message: "That page doesn't exist, champ." });
var rangeIndex = pageNum * pageLimit - pageLimit;
let meta = [];
for (let index = 0; index < pageLimit; index++) {
const page = displayed[index + rangeIndex];
try {
if (
page.metadata.id != null &&
page.metadata.deleted === false &&
page.metadata.published === true
) {
let entry = page.metadata;
entry.content = page.content;
//console.log('ENTRY', entry);
pages.push({
page: entry,
displayDate: moment(page.metadata.created).fromNow()
});
}
} catch (e) {
//console.log("NO POST", e)
}
}
meta.push({ currentPage: pageNum, totalPages: count });
let data = { pages: pages, meta: meta };
res.json({
type: DataEvent.REQUEST_GOOD,
message: 'This is Page ' + pageNum + ' of ' + count,
data: data
});
});
});
/**
* Retrieves single entry
* @public
*/
router.get('/single/:id', (req, res) => {
let id = req.params.id;
if (id === null || id === '')
res.json({ type: DataEvent.REQUEST_LAME, message: " Nah, this isn't here." });
book.getPage(id)
.then(page => {
let entry = page.metadata;
entry.content = page.content;
res.json({
type: DataEvent.REQUEST_GOOD,
message: 'Found it. Here you go.',
data: entry
});
})
.catch(err => {
res.json({
type: DataEvent.REQUEST_LAME,
message: "This doesn't seem to be here, homie.",
err: err.message
});
});
});
/**
* Add/Update Page
*/
router.post('/write/:task?', feature_upload, (req, res) => {
auth.authCheck(req)
.then(() => {
let body = _.mapValues(req.body);
let feature = '';
let task = '';
req.params.task === 'new'
? (task = DataEvent.API_PAGE_CREATE)
: (task = DataEvent.API_PAGE_WRITE);
if (req.files.length > 0) {
var path = req.files[0].path;
//console.log('NEW FEATURE URL', path);
feature = '/' + path.substring(7, path.length);
} else {
var url = body.feature_image;
//switch this to the new feature path edit
if (url != null || url != undefined || url != '') {
let chunks = url.split('/');
let strip = chunks[0] + '/' + chunks[1] + chunks[2];
feature = url.substr(strip.length + 1, url.length);
} else {
feature = '';
}
}
body.feature = feature;
body.deleted = false;
//if title changes, get rid of a pages with old title
if (body.current_title !== body.slug) {
let path =
moment(body.created).format('YYYY') + '/' + moment(body.created).format('MM');
//remove html page
fs.unlink('public/' + path + '/' + body.current_title + '.html')
.then()
.catch(() => {
//console.log('HTML ERROR', err);
});
//remove markdown
fs.unlink('content/pages/' + path + '/' + body.current_title + '.md')
.then()
.catch(() => {
//console.log('MD ERROR', err);
});
}
book.editPage(body, body.page_uuid, task, req.session.user)
.then(result => {
if (result.type === DataEvent.PAGE_ADDED) {
settings.updatePageIndex();
}
//load all page data and render if render on save flag is set in settings file
getBookData()
.then(result => {
if (result.settings.global.renderOnSave === 'true') {
render
.publishAll(
result.pages,
result.settings.global.theme,
req.session.user.handle
)
.then(response => {
res.json({
type: response.type,
message: response.message
});
})
.catch(err => {
res.json({
type: DataEvent.PAGES_NOT_RENDERED,
message: 'Uh oh. Pages not rendered, sport',
error: err
});
});
} else {
//console.log('DONT RENDER PAGES');
}
})
.catch(() => {
//console.log();
});
res.json(result);
})
.catch(err => {
res.json(err);
});
})
.catch(err => {
res.json(err);
});
});
/**
* Soft deletes Page
*/
router.post('/delete', (req, res) => {
auth.authCheck(req)
.then(() => {
book.editPage([], req.body.id, DataEvent.API_PAGE_DELETE, req.session.user)
.then(result => {
//remove item from menu in settings
res.json(result);
})
.catch(err => {
res.json(err);
});
})
.catch(err => {
res.json(err);
});
});
/**
* Uploads image from a Page content
*/
router.post('/add-post-image', post_upload, function (req, res) {
//console.log(req.body);
var image = req.files[0].path;
return res.json({
type: DataEvent.POST_IMAGE_ADDED,
message: 'Added Image',
url: '/' + image.substr(7, image.length)
});
});
module.exports = router;
function getBookData() {
return new Promise((resolve, reject) => {
let getSettings = settings.load(SETTINGS_FILE);
let getBook = book.getPage();
Promise.all([getSettings, getBook])
.then(result => {
const [settings, pages] = result;
let data = { settings: settings, pages: pages };
resolve(data);
})
.catch(err => {
reject(err);
});
});
}

View file

@ -1,250 +0,0 @@
import * as DataEvent from '../../../src/com/events/DataEvent';
import Auth from '../../data/Auth';
import Render from '../../data/Render';
import Settings, { SETTINGS_FILE, SETTINGS_FOLKS } from '../../data/Settings';
import Navigation from '../../data/Navigation';
import Book from '../../data/Book';
const express = require('express');
const router = express.Router();
const multer = require('multer');
const fs = require('fs-extra');
const moment = require('moment');
const _ = require('lodash');
const auth = new Auth();
const render = new Render();
const book = new Book();
const settings = new Settings();
const nav = new Navigation();
const uploadPath =
'./public/assets/images/user/' + moment().format('YYYY') + '/' + moment().format('MM');
var storage = multer.diskStorage({
destination: function (req, file, cb) {
fs.ensureDir(uploadPath, () => {
// dir has now been created, including the directory it is to be placed in
cb(null, uploadPath);
});
},
filename: function (req, file, cb) {
var splice = file.originalname.split(':');
cb(null, splice[0]);
}
});
var avatar_upload = multer({
storage: storage
}).array('avatar_upload');
var background_upload = multer({
storage: storage
}).array('background_upload');
//** SYNC POSTS */
router.post('/sync', (req, res) => {
auth.authCheck(req)
.then(() => {
settings
.sync(req, res)
.then(() => {
res.json({
type: DataEvent.SETTINGS_UPDATED,
message: 'Settings Saved'
});
})
.catch(err => {
res.json({
type: DataEvent.REQUEST_LAME,
error: err.message,
message: "Uh oh. Settings didn't take, sport"
});
});
})
.catch(err => {
res.json({
type: err.type,
message: err.message
});
});
});
router.post('/nav-sync', (req, res) => {
auth.authCheck(req)
.then(() => {
// find removed menu item page and set menu to false
book.getPage(req.body.remove).then(page => {
let body = page.metadata;
body.content = page.content;
body.menu = false;
book.editPage(body, body.uuid, DataEvent.API_PAGE_WRITE, req.session.user);
});
nav.sync(req.body)
.then(response => {
res.json({
type: response.type,
message: response.message
});
})
.catch(err => {
res.json({
type: DataEvent.REQUEST_LAME,
message: err
});
});
})
.catch(err => {
res.json({
type: err.type,
message: err.message
});
});
});
router.post('/publish-pages', (req, res) => {
auth.authCheck(req)
.then(() => {
getBookData()
.then(result => {
render
.publishAll(
result.pages,
result.settings.global.theme,
req.session.user.handle
)
.then(response => {
res.json({
type: response.type,
message: response.message
});
})
.catch(err => {
res.json({
type: DataEvent.PAGES_NOT_RENDERED,
message: 'Uh oh. Pages not rendered, sport',
error: err
});
});
})
.catch(err => {
res.json({
type: DataEvent.PAGES_NOT_RENDERED,
message: 'Uh oh. Pages not rendered, sport',
error: err
});
});
})
.catch(err => {
res.json({
type: err.type,
message: err.message
});
});
});
/***
UPLOAD AVATAR
*/
router.post('/add-avatar', avatar_upload, (req, res) => {
if (req.session.user) {
let user = req.session.user;
settings
.load(SETTINGS_FOLKS)
.then(folks => {
let found = _.find(folks, { handle: user.handle });
if (found) {
var index = found.id - 1;
var path = req.files[0].path;
var image = path.substr(7, path.length);
folks[index].avi = '/' + image;
fs.writeJson('site/folks.json', folks);
user.avi = '/' + image;
res.json({
type: DataEvent.AVATAR_UPLOADED,
message: 'Changed avi. You look great.',
url: '/' + image
});
}
})
.catch(() => {
res.json({
type: DataEvent.REQUEST_LAME,
message: 'Members Not found'
});
});
} else {
res.json({
type: DataEvent.REQUEST_LAME,
message: "You're not logged in, champ"
});
}
});
/***
UPLOAD FEATURE BACKGROUND
*/
router.post('/add-feature-background', background_upload, (req, res) => {
if (req.session.user) {
settings
.load(SETTINGS_FILE)
.then(settings => {
var path = req.files[0].path;
var image = path.substr(7, path.length);
settings.global.background = '/' + image;
fs.writeJson('site/settings.json', settings);
res.json({
type: DataEvent.SITE_BACKGROUND_UPLOADED,
message: 'Background Uploaded',
url: '/' + image
});
})
.catch(() => {
//console.log('ERROR', err);
});
} else {
res.json({
type: DataEvent.REQUEST_LAME,
message: "You're not logged in, champ"
});
}
});
router.post('/reindex', (req, res) => {
auth.authCheck(req)
.then(() => {
book.reindexPages(req)
.then(response => {
//reset settings index
settings.resetLibraryIndex(response.count + 1);
//return success to front end
res.json(response);
})
.catch(err => {
res.json({
type: err.type,
message: err.message
});
});
})
.catch(err => {
res.json({
type: err.type,
message: err.message
});
});
});
module.exports = router;
function getBookData() {
return new Promise((resolve, reject) => {
let getSettings = settings.load(SETTINGS_FILE);
let getBook = book.getPage();
Promise.all([getSettings, getBook])
.then(result => {
const [settings, pages] = result;
let data = { settings: settings, pages: pages };
resolve(data);
})
.catch(err => {
reject(err);
});
});
}

View file

@ -1,94 +0,0 @@
var express = require('express');
var path = require('path');
//var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');
var MemoryStore = require('memorystore')(session);
var flash = require('connect-flash');
var app = express();
// favicon stuff
//app.use(favicon(path.join(__dirname, 'favicons', 'favicon.ico')));
// view engine setup
app.set('views', path.join(__dirname, './views'));
app.set('view engine', 'pug');
app.use(logger('dev'));
app.use(bodyParser.json({ limit: '50mb' }));
app.use(
bodyParser.urlencoded({
extended: false,
limit: '50mb'
})
);
app.use(cookieParser());
app.use(express.static(path.join(__dirname, '../public'), { extensions: ['html'] }));
app.use(
session({
store: new MemoryStore({
checkPeriod: 86400000 // prune expired entries every 24h
}),
secret: '1KqZ18W8KskE1iSw',
saveUninitialized: false,
resave: false,
cookie: {
maxAge: 608800000
}
})
);
app.use(flash());
//sections
//var front = require('./routes/front/index')(session);
var dash = require('./routes/dash/index');
var page = require('./routes/dash/pages');
var settings = require('./routes/dash/settings');
var nav = require('./routes/dash/nav');
//api
var pages = require('./api/v1/pages');
var setting = require('./api/v1/settings');
var mailer = require('./api/v1/mailer');
var auth = require('./api/v1/auth');
var backup = require('./api/v1/backup');
// API PATHS
app.use('/api/v1/page', pages);
app.use('/api/v1/settings', setting);
app.use('/api/v1/auth', auth);
app.use('/api/v1/mailer', mailer);
app.use('/api/v1/backup', backup);
// PAGES
app.use('/@/dashboard', dash);
app.use('/@/dashboard/page', page);
app.use('/@/dashboard/settings', settings);
app.use('/@/dashboard/navigation', nav);
// catch 404 and forward to error handler
app.use(function (req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function (err, req, res) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function (err, req, res) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;

View file

@ -1,105 +0,0 @@
import * as DataEvent from '../../src/com/events/DataEvent';
const bCrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const _ = require('lodash');
export default class Auth {
//--------------------------
// constructor
//--------------------------
constructor() {}
//--------------------------
// methods
//--------------------------
start() {}
/**
* Makes sure access token is legit
* @parameter req
*/
authCheck(req) {
let self = this;
return new Promise((resolve, reject) => {
let hash = req.headers['x-access-token'];
let response = [];
//check to see if user is logged in
if (!req.session.user) {
response = {
status: false,
type: DataEvent.API_REQUEST_LAME,
message: "You're not logged in, champ."
};
reject(response);
}
//Checks if token is a proper hash, if not reject
if (!self.isTokenValid(req.session.token, hash)) {
response = {
status: false,
type: DataEvent.API_REQUEST_LAME,
message: 'No Token Present. Auth Blocked'
};
reject(response);
//res.json();
} else {
var member = req.session.user;
jwt.verify(req.session.token, member.key, function (err, decoded) {
if (err) {
response = {
status: false,
type: DataEvent.API_REQUEST_LAME,
message: 'Invalid Token. Auth Blocked'
};
reject(response);
}
response = {
status: true,
type: DataEvent.API_REQUEST_GOOD,
message: 'Token Verified',
token: decoded
};
resolve(response);
});
}
});
}
verifyCredentials(config, credentials) {
return new Promise((resolve, reject) => {
var found = _.find(config, { handle: credentials.handle });
var response;
if (found) {
if (!this.isValidPassword(found, credentials.pass)) {
response = {
type: DataEvent.REQUEST_LAME,
message: 'CHECK YOUR PASSWORD'
};
reject(response);
}
response = { type: DataEvent.REQUEST_GOOD, message: 'Backup Verified. Restoring' };
resolve(response);
} else {
response = { type: DataEvent.REQUEST_LAME, message: 'Handle not found, boss' };
reject(response);
}
});
}
isValidPassword(user, password) {
return bCrypt.compareSync(password, user.password);
}
/**
* Checks to make sure received token matches
* @parameter token: created token
* @parameter hashedToken: encrypted token
*/
isTokenValid(token, hashedToken) {
return bCrypt.compareSync(token, hashedToken);
}
//--------------------------
// event handlers
//--------------------------
}

View file

@ -1,273 +0,0 @@
import fh from 'filehound';
import fs from 'fs-extra';
import metadataParser from 'markdown-yaml-metadata-parser';
import _ from 'lodash';
import * as DataEvent from '../../src/com/events/DataEvent';
import Navigation from './Navigation';
import Utils from './Utils';
const moment = require('moment');
const nav = new Navigation();
const utils = new Utils();
/**
* Class for handling blog content pages
*/
export default class Book {
//--------------------------
// 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
utils.organizeTags(pages);
utils.organizeArchive(pages);
resolve(pages);
}, 100);
} else {
setTimeout(() => {
//TODO: Duct tape solution until something better created
//make check against menu to see if page should be marked as menu item
//if it doesn't exist in menu change, edit page to
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 /src/com/events
* @parameter user: object contain 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 layout = 'page';
var path = '';
fs.ensureDir(
'content/pages/' +
moment(body.created).format('YYYY') +
'/' +
moment(body.created).format('MM') +
'/'
).then(() => {
if (body.menu === 'true') {
body.path =
moment(body.created).format('YYYY') +
'/' +
moment(body.created).format('MM');
nav.editMenu(DataEvent.MENU_ADD_ITEM, body, user);
} else {
nav.editMenu(DataEvent.MENU_DELETE_ITEM, body, user);
}
if (body.layout !== 'page') layout = body.layout;
if (body.layout === null || body.layout === 'null') layout = 'page';
var pageWrite =
'---\n' +
'id: ' +
body.id +
'\n' +
'uuid: ' +
body.uuid +
'\n' +
'title: ' +
body.title +
'\n' +
'feature: ' +
body.feature +
'\n' +
'path: ' +
moment(body.created).format('YYYY') +
'/' +
moment(body.created).format('MM') +
'\n' +
'layout: ' +
layout +
'\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;
layout === 'index'
? (path = 'content/pages/index.md')
: (path =
'content/pages/' +
moment(body.created).format('YYYY') +
'/' +
moment(body.created).format('MM') +
'/' +
body.slug +
'.md');
fs.writeFile(path, 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.uuid
};
resolve(response);
} 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();
body.menu = false;
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;
}
});
}
reindexPages(req) {
var response = '';
var self = this;
return new Promise((resolve, reject) => {
self.getPage()
.then(pages => {
let sorted = [];
for (let i = 0; i < pages.length; i++) {
let body = pages[i].metadata;
body.content = pages[i].content;
sorted.push(body);
}
//resorts pages by date created
let byDate = _.sortBy(sorted, page => {
return page.created;
});
//reassigns id sequentially based on sorted pages
for (let index = 0; index < byDate.length; index++) {
byDate[index].id = index;
self.editPage(
byDate[index],
index,
DataEvent.API_PAGE_WRITE,
req.session.user
);
}
response = {
type: DataEvent.API_REINDEX_PAGES,
message: 'Pages re-sorted. Easy peasy.',
count: byDate.length
};
resolve(response);
})
.catch(err => {
response = { type: DataEvent.PAGE_ERROR, message: err };
reject(response);
});
});
}
//--------------------------
// event handlers
//--------------------------
}

View file

@ -1,75 +0,0 @@
import fs from 'fs-extra';
import _ from 'lodash';
import * as DataEvent from '../../src/com/events/DataEvent';
import Settings, { SETTINGS_FILE } from './Settings';
const settings = new Settings();
export default class Navigation {
//--------------------------
// constructor
//--------------------------
constructor() {}
//--------------------------
// methods
//--------------------------
sync(body) {
return new Promise((resolve, reject) => {
let response = [];
settings
.load(SETTINGS_FILE)
.then(settings => {
let payload = body;
settings.menu = payload.nav;
fs.writeJson('site/settings.json', settings)
.then(() => {
response = {
type: DataEvent.SETTINGS_UPDATED,
message: 'Menu order saved, champ'
};
resolve(response);
})
.catch(err => {
response = {
type: DataEvent.REQUEST_LAME,
message: err
};
reject(response);
});
})
.catch(err => {
response = {
type: DataEvent.REQUEST_LAME,
message: err
};
reject(response);
});
});
}
editMenu(task, item) {
settings.load(SETTINGS_FILE).then(settings => {
switch (task) {
case DataEvent.MENU_ADD_ITEM:
settings.menu.push({
title: item.title,
id: item.id,
slug: item.slug,
uuid: item.uuid,
path: item.path
});
break;
case DataEvent.MENU_DELETE_ITEM:
settings.menu = _.remove(settings.menu, m => {
return m.uuid != item.uuid;
});
break;
}
fs.writeJSON(SETTINGS_FILE, settings);
});
}
//--------------------------
// event handlers
//--------------------------
}

View file

@ -1,304 +0,0 @@
import * as DataEvent from '../../src/com/events/DataEvent';
import StringUtils from '../../src/com/utils/StringUtils';
import Settings, { SETTINGS_FILE, SETTINGS_TAG } from './Settings';
import fs from 'fs-extra';
import sanitize from 'sanitize-html';
import Utils from './Utils';
const pug = require('pug');
const md = require('markdown-it')('commonmark');
const _ = require('lodash');
const moment = require('moment');
const settings = new Settings();
export default class Render {
//--------------------------
// constructor
//--------------------------
constructor() {}
//--------------------------
// methods
//--------------------------
start() {}
/**
* Renders all pages from markdown to html
* @parameter pages: payload for site pages
* @parameter theme: current theme being used as defined in settings
*/
publishAll(pages, theme, author) {
return new Promise((resolve, reject) => {
settings
.load(SETTINGS_FILE)
.then(config => {
let response = [];
let count = _.filter(pages, page => {
return page.metadata.deleted === false && page.metadata.published === true;
}).length;
let rendered = 0;
let display_count = 0;
let recent = [];
let featured = _.filter(pages, page => {
return (
page.metadata.deleted === false &&
page.metadata.published === true &&
page.metadata.featured === true &&
page.metadata.layout !== 'index'
);
});
for (let index = 0; index < pages.length; index++) {
pages.sort((a, b) => parseFloat(b.metadata.id) - parseFloat(a.metadata.id));
const page = pages[index];
if (page.metadata.deleted === false && page.metadata.published === true) {
if (page.metadata.layout != 'index') {
if (recent.length < config.global.display_limit) {
recent.push({
title: page.metadata.title,
slug: page.metadata.slug,
feature: page.metadata.feature,
created: moment(page.metadata.created).fromNow(),
path: page.metadata.path
});
display_count = ++display_count;
}
}
let writeFile, template;
let path =
'public/' +
moment(page.metadata.created).format('YYYY') +
'/' +
moment(page.metadata.created).format('MM') +
'/';
if (page.metadata.layout === 'index') {
template = 'content/themes/' + theme + '/index.pug';
writeFile = 'public/index.html';
} else {
writeFile = path + page.metadata.slug + '.html';
template = 'content/themes/' + theme + '/page.pug';
}
let buffed = sanitize(page.content, {
allowedTags: ['del', 'a', 'iframe', 'img'],
allowedAttributes: {
a: ['href', 'name', 'target'],
img: ['src'],
iframe: [
'height',
'width',
'src',
'frameborder',
'allow',
'allowfullscreen'
]
}
});
let bag = page.metadata.tags.split(',');
let tags = [];
for (let index = 0; index < bag.length; index++) {
let tag = bag[index].trim();
tags.push({
label: bag[index],
slug: new StringUtils().cleanString(tag)
});
}
buffed = new StringUtils().decodeHTML(buffed);
let html = md.render(buffed, { html: true, xhtmlOut: true });
//add open graph meta variables
let file = pug.renderFile(template, {
title: page.metadata.title,
default_bg: page.metadata.feature,
image: page.metadata.feature,
keywords: page.metadata.tags,
content: html,
tags: tags,
menu: config.menu,
recent_posts: recent,
featured_posts: featured,
meta: {
who: author,
when: moment(page.metadata.created).fromNow(),
tags: tags
},
welcome_message: page.metadata.title
});
fs.ensureDir(path).then(() => {
fs.writeFile(writeFile, 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
});
});
rendered = ++rendered;
if (rendered === count) {
response = {
type: DataEvent.PAGES_RENDERED,
message: 'All Pages Rendered. Sweet.'
};
//move theme assets to public when pages are rendered
new Utils().moveAssets();
resolve(response);
}
} else {
if (count === 0) {
response = {
type: DataEvent.PAGES_RENDERED,
message: 'No page rendering needed'
};
resolve(response);
}
//check to see if deleted pages have been renderered and delete them
if (page.metadata.layout !== 'index') {
fs.unlink(
'public/' +
page.metadata.path +
'/' +
page.metadata.slug +
'.html'
)
.then()
.catch(() => {
//console.log('ERROR', err);
});
}
}
}
})
.catch(err => {
//console.log('ERROR', err);
reject(err);
});
});
}
/**
* Method to extract, group and render tags in page
* @parameter pages: payload for site pages
*/
publishTags(pages) {
let self = this;
return new Promise((resolve, reject) => {
self.loadRenderData()
.then(result => {
let tags = result.tags.tags;
let renderList = [];
for (let index = 0; index < tags.length; index++) {
let tag = tags[index];
//console.log('**TAG**', tag.tag_name);
var pageList = [];
for (let i = 0; i < pages.length; i++) {
let page = pages[i];
//TODO: filter for deleted and unpublished pages
if (
page.metadata.deleted === false &&
page.metadata.published === true
) {
if (_.includes(page.metadata.tags, tag.tag_name)) {
pageList.push({
title: page.metadata.title,
slug: page.metadata.slug,
path: page.metadata.path
});
}
}
}
renderList.push({ tag: tag.tag_name, tag_list: pageList, slug: tag.slug });
}
let response = [];
for (let index = 0; index < renderList.length; index++) {
let item = renderList[index];
let file = pug.renderFile(
'content/themes/' + result.settings.global.theme + '/tags.pug',
{
title: item.tag,
default_bg: result.settings.global.background,
content_tags: 'THESE ARE TAGS',
tag_list: item.tag_list,
menu: result.settings.menu
}
);
fs.ensureDir('public/tags', () => {
fs.writeFile('public/tags/' + item.slug + '.html', file, err => {
// throws an error, you could also catch it here
if (err) {
response = {
type: DataEvent.TAG_PAGES_NOT_RENDERED,
message: err
};
reject(response);
}
// success case, the file was saved
response = {
type: DataEvent.TAG_PAGES_RENDERED,
message: 'Tag Pages ready to go. Good job.'
};
resolve(response);
});
});
}
})
.catch(err => {
reject(err);
});
});
}
/**
* Method to build page that lists all active pages, organized by year and month
* @parameter pages: payload for site pages
*/
publishArchive(archive) {
settings
.load(SETTINGS_FILE)
.then(settings => {
let file = pug.renderFile(
'content/themes/' + settings.global.theme + '/archive.pug',
{
title: 'ARCHIVES',
default_bg: settings.global.background,
content_tags: 'COLD STORAGE',
archives: archive,
menu: settings.menu
}
);
fs.writeFile('public/archives.html', file, err => {
// throws an error, you could also catch it here
if (err) {
//console.log('ERROR', err);
//response = { type: DataEvent.TAG_PAGES_NOT_RENDERED, message: err };
}
// success case, the file was saved
});
})
.catch(() => {
//console.log(err);
});
}
loadRenderData() {
return new Promise((resolve, reject) => {
let getSettings = settings.load(SETTINGS_FILE);
let getTags = settings.load(SETTINGS_TAG);
Promise.all([getSettings, getTags])
.then(result => {
const [settings, tags] = result;
let data = { settings: settings, tags: tags };
resolve(data);
})
.catch(err => {
reject(err);
});
});
}
//--------------------------
// event handlers
//--------------------------
}

View file

@ -1,184 +0,0 @@
import * as DataEvent from '../../src/com/events/DataEvent';
import fs from 'fs-extra';
const _ = require('lodash');
export const SETTINGS_FILE = 'site/settings.json';
export const SETTINGS_FOLKS = 'site/folks.json';
export const SETTINGS_TAG = 'site/tags.json';
export default class Settings {
//--------------------------
// constructor
//--------------------------
constructor() {}
//--------------------------
// methods
//--------------------------
sync(req) {
let self = this;
return new Promise((resolve, reject) => {
self.loadConfigData()
.then(result => {
let payload = req.body;
//so payload matches loaded config
payload.global.display_limit = result.settings.global.display_limit;
payload.global.port = result.settings.global.port;
payload.global.last_backup = result.settings.global.last_backup;
let user = req.session.user;
let found = _.find(result.folks, { id: user.id });
let needToUpdate = false;
let response = [];
if (found) {
let index = found.id - 1;
if (
result.folks[index].handle != payload.member.handle ||
result.folks[index].email != payload.member.email
) {
user.handle = payload.member.handle;
user.email = payload.member.email;
result.folks[index].handle = payload.member.handle;
result.folks[index].email = payload.member.email;
fs.writeJson('site/folks.json', result.folks);
} else {
//no need to save
}
} else {
let response = {
type: DataEvent.REQUEST_LAME,
message: "You're not logged in, champ"
};
reject(response);
}
if (!_.isEqual(result.settings.global, payload.global)) {
let bg = payload.global.background;
let chunks = bg.split('/');
let strip = chunks[0] + '/' + chunks[1] + chunks[2];
payload.global.background = bg.substr(strip.length + 1, bg.length);
result.settings.global = payload.global;
needToUpdate = true;
} else {
//no need to save
}
if (!_.isEqual(result.settings.email, payload.email)) {
result.settings.email = payload.email;
needToUpdate = true;
} else {
//no need to save
}
if (needToUpdate) {
fs.writeJson('site/settings.json', result.settings)
.then(() => {
response = {
type: DataEvent.SETTINGS_UPDATED,
message: 'Settings Saved'
};
resolve(response);
})
.catch(() => {
//console.error(err);
});
} else {
//no need to update
}
})
.catch(err => {
reject(err);
});
});
}
saveTags(tags) {
let self = this;
return new Promise((resolve, reject) => {
self.load(SETTINGS_TAG)
.then(config => {
if (!_.isEqual(config.tags, tags)) {
config.tags = tags;
fs.writeJson('site/tags.json', config)
.then(() => {
let response = {
type: DataEvent.SETTINGS_UPDATED,
message: 'Settings Saved'
};
resolve(response);
})
.catch(err => {
reject(err);
});
} else {
let response = {
type: DataEvent.SETTINGS_NOT_UPDATED,
message: 'Settings Already Saved'
};
resolve(response);
}
})
.catch(err => {
reject(err);
});
});
}
updatePageIndex() {
fs.readJSON('site/settings.json').then(settings => {
settings.library_stats.current_index = ++settings.library_stats.current_index;
setTimeout(() => {
//TODO: Duct tape solution until something better created
fs.writeJSON('site/settings.json', settings)
.then(() => {
//console.log('ALL TO THE GOOD');
})
.catch(() => {
//.log('ERR', err);
});
}, 100);
});
}
resetLibraryIndex(index) {
fs.readJSON('site/settings.json').then(settings => {
settings.library_stats.current_index = index;
setTimeout(() => {
//TODO: Duct tape solution until something better created
fs.writeJSON('site/settings.json', settings)
.then(() => {
//console.log('ALL TO THE GOOD');
})
.catch(() => {
//.log('ERR', err);
});
}, 100);
});
}
load(fileToLoad) {
return new Promise((resolve, reject) => {
fs.readJSON(fileToLoad)
.then(file => {
resolve(file);
})
.catch(err => {
reject(err);
});
});
}
loadConfigData() {
return new Promise((resolve, reject) => {
let getSettings = this.load(SETTINGS_FILE);
let getFolks = this.load(SETTINGS_FOLKS);
Promise.all([getSettings, getFolks])
.then(result => {
const [settings, folks] = result;
let data = { settings: settings, folks: folks };
resolve(data);
})
.catch(err => {
reject(err);
});
});
}
//--------------------------
// event handlers
//--------------------------
}

View file

@ -1,243 +0,0 @@
import Settings, { SETTINGS_FILE } from './Settings';
import Render from './Render';
import StringUtils from '../../src/com/utils/StringUtils';
import _ from 'lodash';
import Auth from '../data/Auth';
const settings = new Settings();
const render = new Render();
const stringUtils = new StringUtils();
const moment = require('moment');
const fs = require('fs-extra');
const AdmZip = require('adm-zip');
const auth = new Auth();
export default class Utils {
constructor() {}
/**
* Retrieves single page or pages
* @parameter pages: payload of pages
*/
organizeTags(pages) {
let tags = [];
for (let index = 0; index < pages.length; index++) {
const page = pages[index];
let temp = [];
temp = page.metadata.tags.split(',');
for (let i = 0; i < temp.length; i++) {
let label = temp[i].trim();
if (!_.find(tags, { tag_name: label })) {
tags.push({
tag_name: label,
slug: stringUtils.cleanString(label),
count: 1
});
} else {
_.find(tags, { tag_name: label }).count++;
}
}
}
tags = _.orderBy(tags, ['tag_name'], ['asc']);
settings.saveTags(tags).then(() => {
render
.publishTags(pages)
.then(() => {
//console.log(response);
})
.catch(() => {
//console.log(err);
});
});
}
organizeArchive(pages) {
let years = [];
let archive = [];
for (let index = 0; index < pages.length; index++) {
let page = pages[index].metadata;
if (page.layout !== 'index') {
let year = moment(page.created).format('YYYY');
if (!_.find(years, { year: year })) {
years.push({ year: year, count: 1 });
} else {
_.find(years, { year: year }).count++;
}
}
}
years.sort((a, b) => parseFloat(b.year) - parseFloat(a.year));
for (let index = 0; index < years.length; index++) {
let item = years[index];
let sorted = [];
let filtered = _.filter(pages, page => {
return moment(page.metadata.created).format('YYYY') === item.year;
});
for (let index = 0; index < filtered.length; index++) {
let obj = filtered[index].metadata;
let month = moment(obj.created).format('MM');
if (!_.find(sorted, { month: month })) {
sorted.push({
month: month,
full_month: moment(obj.created).format('MMMM'),
count: 1,
pages: _.filter(pages, page => {
return (
moment(page.metadata.created).format('YYYY') === item.year &&
moment(page.metadata.created).format('MM') === month &&
page.metadata.deleted === false &&
page.metadata.published === true &&
page.metadata.layout !== 'index'
);
})
});
} else {
_.find(sorted, { month: month }).count++;
}
}
archive.push({ year: item.year, year_data: sorted });
}
render.publishArchive(archive);
}
moveAssets() {
settings
.load(SETTINGS_FILE)
.then(settings => {
//move css assets to public directory
fs.copy(
'content/themes/' + settings.global.theme + '/assets/css',
'public/assets/css',
function (err) {
if (err) {
//console.log('An error occured while copying the folder.', err);
//return console.error(err);
}
//console.log('Copy completed!');
}
);
//move js assets to public directory
fs.copy(
'content/themes/' + settings.global.theme + '/assets/scripts',
'public/assets/scripts',
function (err) {
if (err) {
//console.log('An error occured while copying the folder.', err);
//return console.error(err);
}
//console.log('Copy completed!');
}
);
//TODO: Add method to move new logo to public from theme upload
})
.catch(() => {
//console.log('ERROR', err);
});
}
createBackup() {
//let self = this;
var response;
return new Promise(resolve => {
var zip = new AdmZip();
zip.addLocalFolder('public/assets/images/blog', 'public/assets/images/blog');
zip.addLocalFolder('content/pages', 'content/pages/');
zip.addLocalFile('site/folks.json', 'settings/');
zip.addLocalFile('site/settings.json', 'settings/');
zip.addLocalFile('site/tags.json', 'settings/');
zip.writeZip('content/backup.zip');
fs.readJSON('site/settings.json').then(settings => {
settings.global.last_backup = moment(Date.now()).format();
fs.writeJSON('site/settings.json', settings);
});
response = {
type: '',
message: 'BACKUP CREATED'
};
resolve(response);
});
}
restoreBackup(file) {
var response;
return new Promise((resolve, reject) => {
var zip = new AdmZip(file.buffer);
try {
zip.extractEntryTo('settings/settings.json', 'site', false, true);
zip.extractEntryTo('settings/folks.json', 'site', false, true);
zip.extractEntryTo('settings/tags.json', 'site', false, true);
zip.getEntries().forEach(function (entry) {
var entryName = entry.entryName;
var list = entryName.split('/');
if (list[0] === 'public') {
if (list[6]) {
zip.extractEntryTo(
entryName,
'public/assets/images/blog/' + list[4] + '/' + list[5],
false,
true
);
}
}
if (list[0] === 'content') {
if (list[4]) {
zip.extractEntryTo(
entryName,
'content/pages/' + list[2] + '/' + list[3],
false,
true
);
}
zip.extractEntryTo('content/pages/index.md', 'content/pages', false, true);
}
});
resolve();
} catch (error) {
response = {
type: error,
message: 'ERROR READING BACKUP'
};
reject(response);
}
});
}
verifyBackup(file, body) {
var response;
var zip = new AdmZip(file.buffer);
var credentials = { handle: body.restore_member_handle, pass: body.restore_member_pass };
var self = this;
return new Promise((resolve, reject) => {
try {
let folks = JSON.parse(zip.readAsText('settings/folks.json'));
auth.verifyCredentials(folks, credentials)
.then(() => {
//resolve(r);
self.restoreBackup(file)
.then(() => {
response = {
type: '',
message: 'RESTORE COMPLETE'
};
resolve(response);
})
.catch(err => {
response = {
type: err,
message: 'ERROR RESTORING BACKUP'
};
});
})
.catch(err => {
reject(err);
});
} catch (error) {
response = {
type: 'error',
message: 'ERROR READING BACKUP FILE'
};
reject(response);
}
});
}
}

View file

@ -1,62 +0,0 @@
import Book from '../../data/Book';
import Settings, { SETTINGS_FILE } from '../../data/Settings';
const express = require('express');
const moment = require('moment');
const router = express.Router();
const book = new Book();
const settings = new Settings();
const indexLimit = 5;
//--------------------------
// Index
//--------------------------
router.get('/', function (req, res) {
settings
.load(SETTINGS_FILE)
.then(config => {
book.getPage().then(result => {
result.sort((a, b) => parseFloat(b.metadata.id) - parseFloat(a.metadata.id));
let indexPages = [];
let indexCount = 0;
result.forEach(page => {
if (
typeof page.metadata.deleted === 'undefined' ||
page.metadata.deleted === false
) {
if (indexCount === indexLimit) return;
indexPages.push({
page: page,
date: moment(page.metadata.created).fromNow()
});
++indexCount;
}
});
let pageData = [];
if (req.session.user) {
pageData = { title: config.global.title, status: true, pages: indexPages };
} else {
pageData = { title: config.global.title, status: false, pages: indexPages };
}
res.render('index', pageData);
});
})
.catch(err => {
if (err.code === 'ENOENT') {
let setupData = { title: 'Fipamo Set up' };
res.render('init', setupData);
} else {
res.render('error', { error: err });
}
});
});
//--------------------------
// Logout
//--------------------------
router.get('/logout', (req, res) => {
//req.logout();
req.session.destroy();
res.redirect('/@/dashboard');
});
module.exports = router;

View file

@ -1,79 +0,0 @@
import Book from '../../../brain/data/Book';
import Settings, { SETTINGS_FILE } from '../../data/Settings';
const express = require('express');
const router = express.Router();
const _ = require('lodash');
//const settings = require('../../../site/settings.json');
const book = new Book();
const settings = new Settings();
//--------------------------
// SETTINGS
//--------------------------
router.get('/', function (req, res) {
if (req.session.user) {
settings
.load(SETTINGS_FILE)
.then(settings => {
var nav = [];
book.getPage()
.then(pages => {
if (settings.menu.length === 0) {
for (let index = 0; index < pages.length; index++) {
let item = pages[index].metadata;
if (item.menu) {
nav.push({
id: item.id,
uuid: item.uuid,
title: item.title,
slug: item.slug,
path: item.path
});
}
}
} else {
let newpages = [];
nav = settings.menu;
for (let index = 0; index < pages.length; index++) {
let item = pages[index].metadata;
if (item.menu)
newpages.push({
id: item.id,
uuid: item.uuid,
title: item.title,
slug: item.slug,
path: item.path
});
}
for (let i = 0; i < newpages.length; i++) {
if (_.find(nav, { uuid: newpages[i].uuid })) {
//menu item already exists
} else {
nav.push({
id: newpages[i].id,
uuid: newpages[i].uuid,
title: newpages[i].title,
slug: newpages[i].slug,
path: newpages[i].path
});
}
}
}
res.render('navigation', {
menu: nav,
welcome: 'Edit Navigation',
status: true,
title: 'Dashboard | Navigation'
});
})
.catch(err => {
res.render('error', { error: err });
});
})
.catch(err => {
res.render('error', { error: err });
});
} else {
res.redirect('/@/dashboard');
}
});
module.exports = router;

View file

@ -1,172 +0,0 @@
import Book from '../../data/Book';
const express = require('express');
const router = express.Router();
const moment = require('moment');
const book = new Book();
const uuidv4 = require('uuid/v4');
const fs = require('fs-extra');
//--------------------------
// POSTS
//--------------------------
router.get('/list/:filter?/:page?', function (req, res) {
var pageNum = req.params.page;
var filter = req.params.filter;
if (pageNum == '' || pageNum == null) pageNum = 1;
if (filter == '' || filter == null) filter = 'all';
if (req.session.user) {
book.getPage()
.then(pages => {
pages.sort((a, b) => parseFloat(b.metadata.id) - parseFloat(a.metadata.id));
let all = [];
let deleted = [];
let published = [];
let menu = [];
let featured = [];
for (let index = 0; index < pages.length; index++) {
let item = pages[index].metadata;
if (typeof item.deleted === 'undefined' || item.deleted === false) {
all.push({
page: pages[index].metadata,
date: moment(pages[index].metadata.created).fromNow()
});
if (item.published == true)
published.push({
page: pages[index].metadata,
date: moment(pages[index].metadata.created).fromNow()
});
if (item.menu == true)
menu.push({
page: pages[index].metadata,
date: moment(pages[index].metadata.created).fromNow()
});
if (item.featured == true)
featured.push({
page: pages[index].metadata,
date: moment(pages[index].metadata.created).fromNow()
});
} else {
deleted.push({
page: pages[index].metadata,
date: moment(pages[index].metadata.created).fromNow()
});
}
}
var filtered;
switch (filter) {
case 'published':
filtered = published;
break;
case 'deleted':
filtered = deleted;
break;
default:
filtered = all;
break;
}
var count = Math.ceil(filtered.length / 6);
var pageItems = [];
var itemLimit = 6;
var rangeStart = pageNum * itemLimit - itemLimit;
for (var i = 0; i < itemLimit; i++) {
try {
if (filtered[i + rangeStart].page.id != null) {
pageItems.push({
page: filtered[i + rangeStart].page,
date: moment(filtered[i + rangeStart].page.created).fromNow()
});
}
} catch (e) {
//console.log("NO POST", e)
}
}
res.render('book-index', {
title: 'Dashbord | Book',
welcome: 'Your pages',
items: pageItems,
page_info: {
all: all.length,
deleted: deleted.length,
published: published.length,
pages: pages.length,
featured: featured.length
},
page_index: pageNum,
page_count: count,
postFilter: filter,
status: true
});
})
.then(() => {
//console.log(value);
})
.catch(err => {
res.render('error', { error: err });
});
} else {
res.redirect('/@/dashboard');
}
});
//--------------------------
// BLOG POST ADD DISPLAY
//--------------------------
router.get('/add/new', function (req, res) {
if (req.session.user) {
//need to grab a few copy of settings for the lastest index
fs.readJSON('site/settings.json')
.then(config => {
res.render('page-edit', {
id: config.library_stats.current_index,
uuid: uuidv4(),
title: 'Add New Page',
user_status: true,
welcome: 'Add New Page',
date: moment(Date.now()).format('YYYY MMM DD'),
page: [],
rawDate: moment(Date.now()).format(),
status: ['false', 'false', 'false'],
edit: false
});
})
.catch(err => {
res.render('error', { error: err });
});
} else {
res.redirect('/@/dashboard');
}
});
//--------------------------
// BLOG POST EDIT DISPLAY
//--------------------------
router.get('/edit/:id', function (req, res) {
var id = req.params.id;
if (req.session.user) {
book.getPage(id)
.then(page => {
res.render('page-edit', {
id: page.metadata.id,
uuid: page.metadata.uuid,
title: 'Edit Page',
welcome: 'Edit Page',
page: page.metadata,
date: moment(page.metadata.created).format('YYYY MMM DD HH:mm'),
layout: page.metadata.layout,
rawDate: page.metadata.created,
content: page.content,
feature: page.metadata.feature,
status: [
String(page.metadata.menu),
String(page.metadata.featured),
String(page.metadata.published)
],
edit: true
});
})
.catch(err => {
res.render('error', { error: err });
});
} else {
res.redirect('/@/dashboard');
}
});
module.exports = router;

View file

@ -1,94 +0,0 @@
import Settings, { SETTINGS_FILE } from '../../data/Settings';
const express = require('express');
const router = express.Router();
const FileHound = require('filehound');
const fs = require('fs-extra');
const settings = new Settings();
const moment = require('moment');
var config = [];
//--------------------------
// SETTINGS
//--------------------------
router.get('/', function (req, res) {
settings
.load(SETTINGS_FILE)
.then(obj => {
config = obj;
})
.catch(err => {
res.render('error', { error: err });
});
loadThemes()
.then(themes => {
if (req.session.user) {
let memberInfo = [];
let user = req.session.user;
memberInfo.push({
handle: user.handle,
email: user.email,
avi: user.avi
});
themes.sort(function (a, b) {
var textA = a.theme.name.toUpperCase();
var textB = b.theme.name.toUpperCase();
return textA < textB ? -1 : textA > textB ? 1 : 0;
});
res.render('settings', {
title: 'Dashboard | Settings',
welcome: 'Your Settings',
status: true,
themes: themes,
settings: config,
last_backup: moment(config.global.last_backup).fromNow(),
member: memberInfo[0]
});
} else {
res.redirect('/@/dashboard');
}
})
.catch(err => {
res.render('error', { error: err });
});
});
module.exports = router;
function loadThemes() {
return new Promise((resolve, reject) => {
settings
.load(SETTINGS_FILE)
.then(settings => {
FileHound.create()
.paths('content/themes')
.ext('json')
.find()
.then(files => {
let themes = [];
for (let index = 0; index < files.length; index++) {
fs.readJSON(files[index], (err, theme) => {
if (theme.name == settings.global.theme) {
themes.push({
theme: theme,
current: 'true'
});
} else {
themes.push({
theme: theme,
current: 'false'
});
}
});
}
setTimeout(() => {
resolve(themes);
}, 200);
})
.catch(err => {
reject(err);
});
})
.catch(err => {
reject(err);
});
});
}

View file

@ -1,57 +0,0 @@
extends frame
block main-content
#post-index
#post-index-wrapper
#post-index-menu
- if(postFilter=='all')
a.current-filter(href="/@/dashboard/page/list/all")= "All Pages ("+page_info.all+")"
- else
a(href="/@/dashboard/page/list/all")= "All Pages ("+page_info.all+")"
| .
- if(postFilter=='published')
a.current-filter(href="/@/dashboard/page/list/published")= "Published ("+page_info.published+")"
- else
a(href="/@/dashboard/page/list/published")= "Published ("+page_info.published+")"
| .
- if(postFilter=='deleted')
a.current-filter(href="/@/dashboard/page/list/deleted")= "Deleted ("+page_info.deleted+")"
- else
a(href="/@/dashboard/page/list/deleted")= "Deleted ("+page_info.deleted+")"
a.add-new-post(href="/@/dashboard/page/add/new") +
label Create New Post
#posts-list
- var index = 0;
- for ( index; index < items.length; index++)
a.page-link(href="/@/dashboard/page/edit/"+items[index].page.uuid id=items[index].uuid)
div.page-bg(style="background: #fc6399 url("+items[index].page.feature+") no-repeat center center / cover")
#meta
- var menu = String(items[index].page.menu)
- var published = String(items[index].page.published)
- var featured = String(items[index].page.featured)
span= items[index].date
label= items[index].page.title
br
#options
span.meta-options(data-active=menu) MENU ITEM
span.meta-options(data-active=published) PUBLISHED
span.meta-options(data-active=featured) FEATURED
- var next = parseInt(page_index, 10) + 1
- var prev = parseInt(page_index, 10) - 1
- if(next > page_count) next = 1
- if(prev <= 0) prev = page_count
- if(page_count > 1)
br
.paginate
a.page-btns(href="/@/dashboard/page/list/"+postFilter+"/"+prev)
svg(viewBox="0 0 20 20" class="icons")
use(xlink:href='/assets/images/global/sprite.svg#entypo-chevron-left')
span.count= "PAGE "+page_index+" OF "+page_count
a.page-btns(href="/@/dashboard/page/list/"+postFilter+"/"+next)
svg(viewBox="0 0 20 20" class="icons")
use(xlink:href='/assets/images/global/sprite.svg#entypo-chevron-right')

View file

@ -1,94 +0,0 @@
doctype strict
head
meta(http-equiv='Content-Type' content='text/html; charset=utf-8')
meta(name='viewport' content='width=device-width, initial-scale=1.0')
title #{title}
style(type='text/css').
/* reset */
#outlook a {
padding: 0;
}
/* Force Outlook to provide a "view in browser" menu link. */
.ExternalClass {
width: 100%;
}
/* Force Hotmail to display emails at full width */
.ExternalClass,
.ExternalClass p,
.ExternalClass span,
.ExternalClass font,
.ExternalClass td,
.ExternalClass div {
line-height: 100%;
}
/* Forces Hotmail to display normal line spacing. More on that: http://www.emailonacid.com/forum/viewthread/43/ */
p {
margin: 0;
padding: 0;
font-size: 0px;
line-height: 0px;
}
/* squash Exact Target injected paragraphs */
table td {
border-collapse: collapse;
}
/* Outlook 07, 10 padding issue fix */
table {
border-collapse: collapse;
mso-table-lspace: 0pt;
mso-table-rspace: 0pt;
}
/* remove spacing around Outlook 07, 10 tables */
/* bring inline */
img {
display: block;
outline: none;
text-decoration: none;
-ms-interpolation-mode: bicubic;
}
a img {
border: none;
}
a {
text-decoration: none;
color: #000001;
}
/* text link */
a.phone {
text-decoration: none;
color: #000001 !important;
pointer-events: auto;
cursor: default;
}
/* phone link, use as wrapper on phone numbers */
span {
font-size: 13px;
line-height: 17px;
font-family: monospace;
color: #000001;
}
//if gte mso 9
style.
/* Target Outlook 2007 and 2010 */
// body wrapper
table(cellpadding='0' cellspacing='0' border='0' style='margin:0; padding:0; width:100%; line-height: 100% !important;')
tr
td(valign='top')
// edge wrapper
table(cellpadding='0' cellspacing='0' border='0' align='center' width='600' style='background: #374857;')
tr
td(valign='top' style='vertical-align: top;')
// /////////////////////////////////////////////////////
table(cellpadding='0' cellspacing='0' border='0' align='center' style='width:100%')
tr
td(valign='top' style='vertical-align: top;text-align: center; padding: 10px')
span(style='font-family: Arial,Helvetica Neue,Helvetica,sans-serif; color:#f5ab35; font-size:20px; font-weight: bold;')
| #{header}
tr
td(valign='top' style='vertical-align: top; background: #161d23; padding:10px;')
span(style='font-family: Arial,Helvetica Neue,Helvetica,sans-serif; color:#cecece; font-size:16px;')
| #{content}
tr
td(valign='top' style='vertical-align: top; padding: 10px;')
span(style='font-family: Arial,Helvetica Neue,Helvetica,sans-serif; color:#b2cce5; font-size:12px;')
| #{footer}

View file

@ -1,8 +0,0 @@
extends frame
block main-content
#error-index
br
label#message Ok, so this is... awkward
br
label#error= error

View file

@ -1,42 +0,0 @@
doctype html
html(xmlns='http://www.w3.org/1999/xhtml', lang='en', xml:lang="en")
head
title= title
meta(content="text/html;charset=utf-8", http-equiv="Content-Type")
meta(meta content="utf-8", http-equiv="encoding")
meta(name='viewport', content='width=device-width, initial-scale=1.0')
meta(name="keywords" content="")
meta(name="description" content="")
meta(http-equiv="content-type", content="text/html; charset=utf-8")
//meta(property="og:image" content="https://thetwelfth.house/base-assets/images/current.png")
//meta(name="twitter:image" content="https://thetwelfth.house/base-assets/images/current.png")
link(rel='stylesheet', href="/assets/css/dash.css", type='text/css')
body
#notifications.notifications
#notifyMessage.notifyMessage
.notify-icon#notify-good
svg(viewBox="0 0 20 20" class="icons")
use#submit-update(xlink:href='/assets/images/global/sprite.svg#entypo-emoji-flirt')
.notify-icon#notify-lame
svg(viewBox="0 0 20 20" class="icons")
use#submit-update(xlink:href='/assets/images/global/sprite.svg#entypo-emoji-sad')
.notify-icon#notify-working
#notify-working-box
svg(viewBox="0 0 20 20" class="icons")
use#submit-update(xlink:href='/assets/images/global/sprite.svg#entypo-cog')
p#message-text This is a message
.main-container#main-content
section#dash-index-content
header#header
#wrapper
#left
a(href="/@/dashboard")
img#the-logo(src="/assets/images/global/the-logo.svg")
#right
-if(status)
include partials/dash-nav
block main-content
//script(src='/assets/scripts/dashkit.min.js' type="text/javascript")
script(src='/assets/scripts/dash.min.js' type="text/javascript")

View file

@ -1,9 +0,0 @@
extends frame
block main-content
#dash-index
#dash-index-wrapper
-if(!status)
include partials/login
-else
include partials/front

View file

@ -1,52 +0,0 @@
extends frame
block main-content
#dash-index
#dash-index-wrapper
.dash-init#dash-init
br
form#init-form
h1 What up.
p Just fill these in and it'll get you started.
label What's your handle?
br
input.large(type='text', name='new_member_handle' id='new_member_handle', placeholder="What\'s your handle?")
br
label Let's get that email
br
input.large(type='text', name='new_member_email' id='new_member_email', placeholder="Email Please")
br
label Let's get a password
br
input.large(type='password', name='new_member_pass' id='new_member_pass', placeholder="Password Please")
br
label And let's confirm that password
br
input.large(type='password', name='new_member_pass2' id='new_member_pass2', placeholder="Password Confirm")
br
label And finally, a title
br
input.large(type='text', name='new_member_title' id='new_member_title', placeholder="Site Title Please")
br
button#init-blog(data-action='blog-init' type='submit') SET IT UP
.option
button.init-option#init-switch-restore OR RESTORE FROM BACKUP
.dash-restore#dash-restore
form#init-restore
h1 Restore backup.
p Let's verify your backup
label What's your handle?
br
input.large(type='text', name='restore_member_handle' id='restore_member_handle', placeholder="What\'s your handle?")
br
label Let's get a password
br
input.large(type='password', name='restore_member_pass' id='restore_member_pass', placeholder="Password Please")
br
label Backup File
br
input(id="backup-upload" type="file" name="backup-upload")
br
button#blog-restore(data-action='blog-restore' type='submit') RESTORE
.option
button.init-option#init-switch-fresh OR INSTALL FRESH SITE

View file

@ -1,16 +0,0 @@
extends frame
block main-content
#nav-index
#nav-index-wrapper
#nav-pages
- var index = 0;
- for ( index; index < menu.length; index++)
.nav-item(id=menu[index].id, data-slug=menu[index].slug, data-uuid=menu[index].uuid, data-path=menu[index].path)
svg#item-arrows(viewBox="0 0 20 20" class="icons")
use(xlink:href='/assets/images/global/sprite.svg#entypo-select-arrows')
label
= menu[index].title
#nav-btns
button.nav-btn#edit-item(data-id=menu[index].uuid) EDIT
button.nav-btn#remove-item(data-id=menu[index].id, data-uuid=menu[index].uuid) REMOVE

View file

@ -1,57 +0,0 @@
extends frame
block main-content
#post-edit-index(data-index=id data-uuid=uuid data-layout=layout data-slug=page.slug)
#post-edit-index-wrapper
//h2 EDIT
=post_title
#post-feature
//label FEATURE IMAGE
if(post_feature == 'null')
#featured-image-drop
| DRAG AND DROP IMAGE OR
label(for="featured-image-upload") CLICK TO CHOOSE
else
#featured-new-image-btn
button#new-feature-upload
svg#new-feature-upload(viewBox="0 0 20 20" class="icons")
use(xlink:href='/assets/images/global/sprite.svg#entypo-image-inverted')
#featured-image-drop
img#featured-image(src=page.feature)
#post-header
#post-header-wrapper.columns
#post-title.column
label TITLE
textarea(id="post_title" type='text', name='post_title' class='post-edit', placeholder='title', required, autofocus)
=page.title
label CREATED
br
span(id="post-date" type="text" value=date data-raw=rawDate)= date
//#calendar-icon
svg(viewBox="0 0 20 20" class="icons")
use(xlink:href='/assets/images/global/sprite.svg#entypo-calendar')
//input(id="post-date" type="text" value=date data-raw=rawDate)
#post-meta.column
label TAGS
textarea(id='post_tags' type='text', name='post_tags' class='form-control', placeholder='tags [comma seperated]', autofocus)
=page.tags
// file inputs for image uploads
label OPTIONS
br
include partials/options
input(id="featured-image-upload" type="file" name="featured-image-upload")
input(id="post-image-upload" type="file" name="post-image-upload")
#edit-post
include partials/editor
#edit-post-wrapper
pre
code#edit-post-text(contenteditable="true") !{content}

View file

@ -1,7 +0,0 @@
#dash-menu
a#settings(href="/@/dashboard/settings") Settings
| .
a#navigation(href="/@/dashboard/navigation") Navigation
| .
a#navigation(href="/@/dashboard/logout") Log Out

View file

@ -1,37 +0,0 @@
#edit-control
button#edit-bold.content-editor-btn-text.editor-button(title="bold")
| B
button#edit-italic.content-editor-btn-text.editor-button(title="italics")
| I
button#edit-strikethrough.content-editor-btn-text.editor-button(title="strikethrough")
| S
button#edit-link.content-editor-btn-icon.editor-button(title="insert link")
svg#edit-link(viewBox="0 0 20 20" class="icons")
use#edit-link(xlink:href='/assets/images/global/sprite.svg#entypo-link')
button#edit-header1.content-editor-btn-text.editor-button(title="header 1")
| H1
button#edit-header2.content-editor-btn-text.editor-button(title="header 2")
| H2
button#edit-header3.content-editor-btn-text.editor-button(title="header 3")
| H3
button#edit-image.content-editor-btn-icon.editor-button(title='insert image')
svg#edit-image(viewBox="0 0 20 20" class="icons")
use#edit-image(xlink:href='/assets/images/global/sprite.svg#entypo-image')
if(edit)
button#edit-update.post-sumbit-btn.submit-start.editor-button(data-action='blog-update' data-id=page.id type='submit')
svg#submit-update(viewBox="0 0 20 20" class="icons")
use#submit-update(xlink:href='/assets/images/global/sprite.svg#entypo-save' data-action='blog-update' data-id=page.id)
svg#submit-good.icon-hide(viewBox="0 0 20 20" class="icons")
use(xlink:href='/assets/images/global/sprite.svg#entypo-thumbs-up')
svg#submit-error.icon-hide(viewBox="0 0 20 20" class="icons")
use(xlink:href='/assets/images/global/sprite.svg#entypo-thumbs-down')
button#edit-delete.content-editor-btn-icon.editor-button.submit-delete(for="post-delete" title='delete post')
svg#edit-delete(viewBox="0 0 20 20" class="icons")
use#edit-delete(xlink:href='/assets/images/global/sprite.svg#entypo-cross')
else
button#edit-save.post-sumbit-btn.submit-start.editor-button(data-action='blog-add' type='submit')
svg#submit-save(viewBox="0 0 20 20" class="icons")
use#submit-save(xlink:href='/assets/images/global/sprite.svg#entypo-plus' data-action='blog-add')

View file

@ -1,30 +0,0 @@
#dash-recent
#recent-list
.recent-header
h3 Recent
.index-menu
a(href='/@/dashboard/page/list') View Pages
| .
a(href='/@/dashboard/page/add/new') Create Page
br
- var index = 0;
- var cap = 5; // number of posts to display, get rid of this and put it in the config
if(pages.length == 0)
label this is empty
else
- for ( index; index < pages.length; index++)
a.post-link(href="/@/dashboard/page/edit/"+pages[index].page.metadata.uuid id=pages[index].page.metadata.uuid style="background:url("+pages[index].page.metadata.feature+") no-repeat center center / cover")
div
label= pages[index].page.metadata.title
#options
- var menu = String(pages[index].page.metadata.menu)
- var published = String(pages[index].page.metadata.published)
- var featured = String(pages[index].page.metadata.featured)
span.item-options(data-active=menu) MENU ITEM
span.item-options(data-active=published) PUBLISHED
span.item-options(data-active=featured) FEATURED
span= pages[index].date

View file

@ -1,7 +0,0 @@
#dash-login
.dash-form#dash-form
form(id="login" class='login', name="login" action="/@/dashboard/login" method="POST")
input(type='text', name='handle' class='form-control', placeholder='handle', required, autofocus)
input(type='password', name='password' class='form-control', placeholder='password', required)
button(id="login-btn", class='login-btn', type='submit') SUBMIT YOUR STUFF

View file

@ -1,25 +0,0 @@
-if(settings.email.active == "option-smtp")
#mail-smtp(data-enabled='true')
input(type='text', name='smtp-domain' id='smtp-domain', placeholder='domain', value=settings.email.smtp.domain autofocus)
input(type='text', name='smtp-email' id='smtp-email', placeholder='email', value=settings.email.smtp.email , autofocus)
input(type='text', name='smtp-pass' id='smtp-pass', placeholder='password', value=settings.email.smtp.password , autofocus)
#mail-mg(data-enabled='false')
input(type='text', name='mg-domain' id='mg-domain', placeholder='domain', value=settings.email.mailgun.domain autofocus)
input(type='text', name='mg-key' id='mg-key', placeholder='api key', value=settings.email.mailgun.key , autofocus)
-else if(settings.email.active == "option-mg")
#mail-smtp(data-enabled='false')
input(type='text', name='smtp-domain' id='smtp-domain', placeholder='domain', value=settings.email.smtp.domain autofocus)
input(type='text', name='smtp-email' id='smtp-email', placeholder='email', value=settings.email.smtp.email , autofocus)
input(type='text', name='smtp-pass' id='smtp-pass', placeholder='password', value=settings.email.smtp.password , autofocus)
#mail-mg(data-enabled='mg')
input(type='text', name='mg-domain' id='mg-domain', placeholder='domain', value=settings.email.mailgun.domain autofocus)
input(type='text', name='mg-key' id='mg-key', placeholder='api key', value=settings.email.mailgun.key , autofocus)
-else
#mail-smtp(data-enabled='false')
input(type='text', name='smtp-domain' id='smtp-domain', placeholder='domain', value=settings.email.smtp.domain autofocus)
input(type='text', name='smtp-email' id='smtp-email', placeholder='email', value=settings.email.smtp.email , autofocus)
input(type='text', name='smtp-pass' id='smtp-pass', placeholder='password', value=settings.email.smtp.password , autofocus)
#mail-mg(data-enabled='false')
input(type='text', name='mg-domain' id='mg-domain', placeholder='domain', value=settings.email.mailgun.domain autofocus)
input(type='text', name='mg-key' id='mg-key', placeholder='api key', value=settings.email.mailgun.key , autofocus)

View file

@ -1,13 +0,0 @@
#post-options
button#option-menu-pin.option-inactive.post-option-btn(data-active= status[0], title='Pin to Menu')
svg#option-page-icon(viewBox="0 0 20 20" class="icons")
use#option-page-icon(xlink:href='/assets/images/global/sprite.svg#entypo-pin')
button#option-feature.option-inactive.post-option-btn(data-active= status[1], title='Feature')
svg#option-feature-icon(viewBox="0 0 20 20" class="icons")
use#option-feature-icon(xlink:href='/assets/images/global/sprite.svg#entypo-star')
button#option-published.option-inactive.post-option-btn(data-active= status[2], title='Publish')
svg#option-published-icon(viewBox="0 0 20 20" class="icons")
use#option-published-icon(xlink:href='/assets/images/global/sprite.svg#entypo-globe')
//button#option-preview.option-inactive(data-active="false")
svg#option-preview-icon(viewBox="0 0 20 20" class="icons")
use#option-preview-icon(xlink:href='/assets/images/global/sprite.svg#entypo-eye')

View file

@ -1,94 +0,0 @@
extends frame
block main-content
#settings-actions
#buttons
button#save-toggle
svg#submit-update(viewBox="0 0 20 20" class="icons")
use#submit-update(xlink:href='/assets/images/global/sprite.svg#entypo-save')
//button#privacy-toggle(data-private=settings.global.private)
-if (settings.global.private == 'false')
| SITE IS PRIVATE
-else
| SITE IS PUBLIC
button#publish-pages
svg#submit-update(viewBox="0 0 20 20" class="icons")
use#submit-update(xlink:href='/assets/images/global/sprite.svg#entypo-publish')
button#render-toggle(data-render=settings.global.renderOnSave)
svg#submit-update(viewBox="0 0 20 20" class="icons")
use#submit-update(xlink:href='/assets/images/global/sprite.svg#entypo-ccw')
#site-background
label FEATURE SITE IMAGE
img#background(src=settings.global.background, alt="image for site background", for="background-upload")
input(id="background-upload" type="file" name="backgrond-upload")
#settings-index
#settings-index-wrapper
#member-settings.columns
#member-settings-1.column
label AVATAR
#member-avatar-drop
img#avatar(src=member.avi, for="avatar-upload")
input(id="avatar-upload" type="file" name="avatar-upload")
#member-settings-2.column
label INFO
#member-info
input(type='text', name='handle' id='settings-handle', placeholder='handle', value=member.handle, autofocus)
input(type='text', name='email' id='settings-email', placeholder='email', value=member.email, autofocus)
input(type='text', name='base-url' id='settings-url', placeholder='url', value=settings.global.base_url, autofocus)
input(type='text', name='base-title' id='settings-title', placeholder='site title', value=settings.global.title, autofocus)
textarea(id="settings-desc" type='text', name='settings_desc' class='settings-dec', placeholder='description stuff', autofocus)
=settings.global.descriptions
#member-utils.columns
#util-1.column
label BACKUP TOOLS
br
button#create-backup CREATE BACKUP
br
-if(settings.global.last_backup != null)
.backup-meta
| The last back up was created
a(href='/api/v1/backup/download')= last_backup
br
-else
br
span No back ups. Frowny face.
button#restore-backup(for='backup-upload') RESTORE BACKUP
input(id="backup-upload" type="file" name="backup-upload")
#util-2.column
label MAINTENANCE
br
button#reindex-pages REINDEX PAGES
#option-settings.columns
#theme-settings.column
label THEMES
br
- var index = 0;
- for ( index; index < themes.length; index++)
-if(themes[index].current == "true")
a.theme-select(href="#" id=themes[index].theme.name, data-enabled="true")
= themes[index].theme["display-name"]
//svg(viewBox="0 0 20 20" class="icons")
use(xlink:href='/dash/assets/images/sprite.svg#entypo-check')
-else
a.theme-select(href="#" id=themes[index].theme.name, data-enabled="false")
= themes[index].theme["display-name"]
#mail-settings.column
label E-MAIL
-if(settings.email.active == "option-none")
a.mail-option#option-none(href="#", data-enabled='true') NONE
-else
a.mail-option#option-none(href="#", data-enabled='false') NONE
-if(settings.email.active == "option-mg")
a.mail-option#option-mg(href="#", data-enabled='true') MAILGUN
-else
a.mail-option#option-mg(href="#", data-enabled='false') MAILGUN
-if(settings.email.active == "option-smtp")
a.mail-option#option-smtp(href="#", data-enabled='true') SMTP
-else
a.mail-option#option-smtp(href="#", data-enabled='false') SMTP
include partials/mailforms
button#send-mail TEST MAIL

1
config/folks.json Normal file
View file

@ -0,0 +1 @@
[{"id":1,"handle":"ItsRo","avi":"/assets/images/user/2020/09/download20200802144459.png","email":"are0h@protonmail.com","password":"$2b$10$77PMC2W6aZ3gJP7TOA7OpeqQaz..SrRSO74WEa7cn61ehHI55.zKq","key":"fe79df250470815bf32dcea70221384c89163cad3a827a9c3da25d87159ed55a","role":"hnic","created":"2020-09-01T22:46:47+02:00","updated":"2020-09-01T22:46:47+02:00","deleted":null}]

1
config/settings.json Normal file
View file

@ -0,0 +1 @@
{"global":{"base_url":"https://fipamo.blog","title":"It's Fipamo","descriptions":"Because it should be easy, boss.","background":"/assets/images/user/2020/09/default-bg.jpg","private":false,"renderOnSave":"false","theme":"fipamo-default","display_limit":5,"port":3314,"last_backup":"2020-09-15T22:14:42+02:00"},"library_stats":{"current_index":5},"email":{"active":"","smtp":{"domain":"","email":"","password":""},"mailgun":{"domain":"","key":""}},"menu":[]}

1
config/tags.json Normal file
View file

@ -0,0 +1 @@
{"tags":[{"tag_name":"development","slug":"development","count":1},{"tag_name":"docs","slug":"docs","count":3},{"tag_name":"first","slug":"first","count":1},{"tag_name":"set up","slug":"set-up","count":3},{"tag_name":"start","slug":"start","count":2},{"tag_name":"themes","slug":"themes","count":1},{"tag_name":"updates","slug":"updates","count":2},{"tag_name":"welcome","slug":"welcome","count":1},{"tag_name":"wiki","slug":"wiki","count":1}]}

1
index.php Normal file
View file

@ -0,0 +1 @@
Hi! We start here.

92
init.js
View file

@ -1,92 +0,0 @@
#!/usr/bin/env node
/**
* Module dependencies.
*/
var app = require('./brain/app');
var debug = require('debug')('fipamo:server');
var http = require('http');
/**
* Get port from environment and store in Express.
*/
try {
var configPort = require('./site/settings.json').global.port;
} catch (err) {
console.log('settings.json not found, assuming this is a first run...');
}
var port = normalizePort(configPort || process.env.PORT || 2314);
app.set('port', port);
/**
* Create HTTP server.
*/
var server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
/**
* Event listener for HTTP server "error" event.
*/
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
//var bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
//console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
//console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port;
console.log('Up and runnin on port: ' + addr.port);
debug('Listening on ' + bind);
}

12895
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,68 +0,0 @@
{
"name": "fipamo-development",
"version": "1.2.4",
"private": true,
"description": "The most chill blog framework ever.",
"repository": "https://code.playvicio.us/Are0h/Fipamo",
"scripts": {
"start": "pm2 --node-args='-r esm' start init.js",
"stop": "pm2 stop init.js",
"dev": "nodemon -r esm init.js --ignore node_modules/ -e js",
"debug": "nodemon inspect -r esm init.js --ignore node_modules/ -e js",
"watch": "sass --watch src/styles:public/assets/css & parcel watch src/com/Start.js --out-dir public/assets/scripts --out-file dash.min.js --public-url /assets/scripts"
},
"engines": {
"node": ">=10.16.0"
},
"dependencies": {
"adm-zip": "^0.4.16",
"bcrypt": "^5.0.0",
"bluebird": "^3.7.2",
"body-parser": "latest",
"caret-pos": "^1.2.2",
"connect-flash": "latest",
"cookie-parser": "~1.3.3",
"debug": "^4.1.1",
"esm": "^3.2.25",
"express": "^4.17.1",
"express-session": "^1.17.1",
"filehound": "^1.17.4",
"fs-extra": "^9.0.1",
"highlight.js": "^9.18.1",
"jsdom": "^12.2.0",
"jsonwebtoken": "^8.5.1",
"lodash": "^4.17.19",
"mailgun-js": "^0.18.0",
"markdown-it": "^8.4.1",
"markdown-yaml-metadata-parser": "^2.0.5",
"memorystore": "^1.6.2",
"moment": "^2.26.0",
"morgan": "^1.10.0",
"multer": "latest",
"nodemailer": "^6.4.8",
"nodemailer-mailgun-transport": "^1.4.0",
"pm2": "^4.4.0",
"pug": "^3.0.0",
"reframe.js": "^2.2.8",
"request": "^2.88.2",
"sanitize-html": "^1.26.0",
"serve-favicon": "latest",
"sortablejs": "^1.10.2",
"tiny-date-picker": "^3.2.8",
"uuid": "^3.4.0"
},
"devDependencies": {
"@babel/cli": "^7.10.1",
"@babel/core": "^7.10.2",
"@babel/preset-env": "^7.10.2",
"animejs": "^3.2.0",
"babel-preset-env": "^1.7.0",
"bulma": "^0.9.0",
"eslint": "^7.9.0",
"nodemon": "^2.0.4",
"parcel": "^1.12.4",
"prettier": "^2.0.5",
"sass": "^1.26.11",
"scramble-text": "0.0.8"
}
}