cleaned up auth in api calls, added page delete, moved edit page methods to Book data class

This commit is contained in:
Ro 2020-02-29 21:01:34 -08:00
parent 0f6ce7c3d8
commit 7b6af21c77
10 changed files with 261 additions and 130 deletions

3
.gitignore vendored
View file

@ -15,4 +15,5 @@ brain/models/_backup/
/_maintenance/
*.DS_Store
/forfipamo
site-settings.json
site-settings.json
.nova/

View file

@ -31,117 +31,89 @@ var post_upload = multer({
storage: storage
}).array('post_image');
/***
Retrieve Pages
*/
/**
* Retrives list of Pages
* @public
*/
router.get('/', (req, res) => {
book.getPage().then(result => {
res.json(result);
});
});
/***
Update Page
*/
/**
* Add/Update Page
*/
router.post('/write/:task?', feature_upload, (req, res) => {
if (req.session.user) {
//Get enctrypted hashed token from header request
let hash = req.headers['x-access-token'];
//Checks if token is a proper hash, if not reject
if (!isTokenValid(req.session.token, hash)) {
res.json({
type: DataEvent.API_REQUEST_LAME,
message: 'Invalid Token. Auth Blocked'
});
} else {
//console.log('TOKEN IS GOOD');
var member = req.session.user;
jwt.verify(req.session.token, member.key, function(err, decoded) {
if (err) {
console('NOPE', err);
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;
feature = '/' + path.substring(7, path.length);
} else {
var url = body.feature_image;
url != null || url != undefined || url != ''
? (feature = url.substring(21, url.length))
: (feature = '');
}
console.log('YUP', decoded);
body.feature = feature;
body.deleted = false;
book.editPage(body, body.page_uuid, task, req.session.user)
.then(result => {
if (result.type === DataEvent.PAGE_CREATE) {
fs.readJSON('site/settings.json').then(settings => {
settings.library_stats.current_index = ++settings.library_stats
.current_index;
settings.library_stats.total_pages = ++settings.library_stats
.total_pages;
fs.writeJSON('site/settings.json', settings);
});
}
res.json(result);
})
.catch(err => {
res.json(err);
});
})
.catch(err => {
res.json(err);
});
}
}
var feature = '';
if (req.files.length > 0) {
var path = req.files[0].path;
feature = '/' + path.substring(7, path.length);
} else {
var url = req.body.feature_image;
url != null || url != undefined || url != ''
? (feature = url.substring(21, url.length))
: (feature = '');
}
var pageWrite =
'---\n' +
'id: ' +
req.body.page_id +
'\n' +
'uuid: ' +
req.body.page_uuid +
'\n' +
'title: ' +
req.body.title +
'\n' +
'feature: ' +
feature +
'\n' +
'layout: ' +
'page' +
'\n' +
'tags: ' +
req.body.tags +
'\n' +
'author: ' +
req.session.user.handle +
'\n' +
'created: ' +
moment(req.body.created).format() +
'\n' +
'updated: ' +
moment(Date.now()).format() +
'\n' +
'menu: ' +
req.body.pinToMenu +
'\n' +
'featured: ' +
req.body.featureStatus +
'\n' +
'published: ' +
req.body.publishedStatus +
'\n' +
'slug: ' +
req.body.slug +
'\n' +
'---\n\n' +
req.body.content;
fs.writeFile('content/pages/' + req.body.slug + '.md', pageWrite, err => {
// throws an error, you could also catch it here
if (err) res.json({ type: DataEvent.PAGE_ERROR, message: err });
// success case, the file was saved
if (req.params.task === 'new') {
// if new file, update settings index and page count
fs.readJSON('site/settings.json').then(settings => {
settings.library_stats.current_index = ++settings.library_stats.current_index;
settings.library_stats.total_pages = ++settings.library_stats.total_pages;
fs.writeJSON('site/settings.json', settings);
});
res.json({
type: DataEvent.PAGE_ADDED,
message: 'New Page Created',
id: req.body.page_uuid
});
} else {
res.json({ type: DataEvent.PAGE_UPDATED, message: 'Page saved, boss' });
}
});
});
/**
* Soft deletes Page
*/
router.post('/delete', (req, res) => {
if (req.session.user) {
authCheck(req)
.then(() => {
book.editPage([], req.body.id, DataEvent.API_PAGE_DELETE, req.session.user)
.then(result => {
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;
@ -157,3 +129,39 @@ module.exports = router;
function isTokenValid(token, hashedToken) {
return bCrypt.compareSync(token, hashedToken);
}
function authCheck(req) {
return new Promise((resolve, reject) => {
let hash = req.headers['x-access-token'];
let response = [];
//Checks if token is a proper hash, if not reject
if (!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);
});
}
});
}

View file

@ -2,6 +2,8 @@ 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';
const moment = require('moment');
export default class Pages {
//--------------------------
@ -13,6 +15,10 @@ export default class Pages {
//--------------------------
start() {}
/**
* Retrieves single page or pages
* @parameter id: optional id if requesting a single Page
*/
getPage(id) {
return new Promise((resolve, reject) => {
fh.create()
@ -47,6 +53,116 @@ export default class Pages {
});
});
}
/**
* Edits single page based on id and task
* @parameter id: id of page being edited
* @parameter task: type of task being performed
*/
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, boss'
};
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(() => {
response = {
type: DataEvent.PAGE_DELETED,
message: 'Page deleted, sport'
};
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;
}
});
}
//--------------------------
// event handlers
//--------------------------

View file

@ -18,7 +18,7 @@ router.get('/list/:filter?/:page?', function(req, res) {
if (filter == '' || filter == null) filter = 'all';
if (req.session.user) {
book.getPage()
.then(function(pages) {
.then(pages => {
pages.sort((a, b) => parseFloat(b.metadata.id) - parseFloat(a.metadata.id));
let all = [];
let deleted = [];
@ -27,7 +27,10 @@ router.get('/list/:filter?/:page?', function(req, res) {
let featured = [];
for (let index = 0; index < pages.length; index++) {
let item = pages[index].metadata;
if (typeof item.deleted == 'undefined' || item.deleted == false) {
if (
typeof item.deleted === 'undefined' ||
(item.deleted === false && item.layout === 'page')
) {
all.push(pages[index].metadata);
if (item.published == true) published.push(pages[index].metadata);
if (item.menu == true) menu.push(pages[index].metadata);

View file

@ -14,7 +14,6 @@ router.get('/', function(req, res) {
.catch(() => {
//console.error(err)
});
loadThemes().then(themes => {
if (req.session.user) {
let memberInfo = [];

View file

@ -10,6 +10,7 @@
"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",
"prettier-watch": "npx onchange '**/*.js' -- npx prettier --write {{changed}}",
"watch-front": "stylus -w -m -o themes/$npm_package_theme/assets/css themes/$npm_package_theme/src/styles/base.styl & parcel watch themes/$npm_package_theme/src/com/Start.js --out-dir themes/$npm_package_theme/assets/js --out-file start.min.js --public-url /$npm_package_theme/assets/js",
"build-front-kit": "uglifyjs node_modules/scramble-text/dist/ScrambleText.min.js node_modules/animejs/anime.min.js node_modules/reframe.js/dist/reframe.min.js -c -o themes/$npm_package_theme/assets/js/toolkit.min.js",
"watch-back": "stylus -w -m -o public/assets/css src/styles/dash.styl & parcel watch src/com/Start.js --out-dir public/assets/scripts --out-file dash.min.js --public-url /assets/scripts",

View file

@ -19,11 +19,11 @@ export default class PostActions {
html = html.replace(/<\/?span[^>]*>/g, ''); //removes highightjs styling
html = html.replace(/<\/?br[^>]*>/g, '\n'); //convert back to encoded line break for storage
pageInfo.append(
'page_id',
'id',
document.getElementById('post-edit-index').getAttribute('data-index')
);
pageInfo.append(
'page_uuid',
'uuid',
document.getElementById('post-edit-index').getAttribute('data-uuid')
);
pageInfo.append('content', html);
@ -38,15 +38,15 @@ export default class PostActions {
);
pageInfo.append('tags', document.getElementById('post_tags').value);
pageInfo.append(
'pinToMenu',
'menu',
document.getElementById('option-menu-pin').getAttribute('data-active')
);
pageInfo.append(
'featureStatus',
'featured',
document.getElementById('option-feature').getAttribute('data-active')
);
pageInfo.append(
'publishedStatus',
'published',
document.getElementById('option-published').getAttribute('data-active')
);
if (image != null || image != undefined) {
@ -68,19 +68,6 @@ export default class PostActions {
}
deletePost(id, body) {
let self = this;
body.deleted = new Date().toString();
return new Promise(function(resolve, reject) {
self.dbUtils
.archivePost(id, body)
.then(response => {
//console.log(response);
resolve(response);
})
.catch(err => {
//console.log(err);
reject(err);
});
});
}
updateNav(add, id, post) {
api.request('/api/settings/nav', DataEvent.SETTINGS_LOADED)

View file

@ -1,5 +1,9 @@
//TOOLS
import ApiUtils, { REQUEST_TYPE_POST, CONTENT_TYPE_FORM } from '../utils/APIUtils';
import ApiUtils, {
REQUEST_TYPE_POST,
CONTENT_TYPE_FORM,
CONTENT_TYPE_JSON
} from '../utils/APIUtils';
import * as DataEvent from '../events/DataEvent';
import PageActions from '../actions/PageActions';
import * as EditorEvent from '../events/EditorEvent';
@ -17,9 +21,11 @@ export default class PostEditor {
this.urlPieces = document.URL.split('/');
this.post = [];
this.postID = null;
this.postUUID = null;
api.authStatus();
if (document.getElementById('post-edit-index').getAttribute('data-index')) {
this.postID = document.getElementById('post-edit-index').getAttribute('data-index');
this.postUUID = document.getElementById('post-edit-index').getAttribute('data-uuid');
}
if (document.getElementById('edit-post-text')) {
this.editor = new TextEditor(
@ -156,14 +162,21 @@ export default class PostEditor {
break;
case EditorEvent.EDITOR_DELETE:
if (confirm("AYE! You know you're deleting this post, right?")) {
new PageActions()
.deletePost(this.postID, this.post)
let id = { id: this.postUUID };
api.request(
'/api/v1/page/delete',
DataEvent.API_PAGE_DELETE,
REQUEST_TYPE_POST,
CONTENT_TYPE_JSON,
id
)
.then(() => {
setTimeout(() => {
window.location = '/@/dashboard/posts/';
}, 100);
console.log('DELETED');
window.location = '/@/dashboard/page/list/';
})
.catch(() => {});
.catch(err => {
notify.alert(err, false);
});
} else {
// Do nothing!
}

View file

@ -1,7 +1,7 @@
export const REQUEST_GOOD = 'requestGood';
export const REQUEST_LAME = 'requestLame';
export const API_REQUEST_GOOD = 'apiUseNotAuthorized';
export const API_REQUEST_LAME = 'apiUseAuthorized';
export const API_REQUEST_GOOD = 'apiUseAuthorized';
export const API_REQUEST_LAME = 'apiUseNotAuthorized';
export const IMG_REQUEST_GOOD = 'imgRequestGood';
export const IMG_REQUEST_LAME = 'imgRequestLame';
export const SETTINGS_LOADED = 'settingsLoaded';
@ -17,6 +17,8 @@ export const AVATAR_UPLOADED = 'avatarUploaded';
export const SITE_BACKGROUND_UPLOADED = 'siteBackgroundUploaded';
export const UPLOAD_PROGRESS = 'uploadProgress';
export const API_PAGE_WRITE = 'writingItDown';
export const API_PAGE_CREATE = 'writingNewEntry';
export const API_PAGE_DELETE = 'erasingPage';
export const API_SETTINGS_WRITE = 'savingSettings';
export const API_IMAGES_UPLOAD = 'uploadProfileImages';
class DataEvent {

View file

@ -55,7 +55,8 @@ export default class APIUtils {
if (
eventType === DataEvent.API_PAGE_WRITE ||
eventType === DataEvent.API_IMAGES_UPLOAD ||
eventType === DataEvent.API_SETTINGS_WRITE
eventType === DataEvent.API_SETTINGS_WRITE ||
eventType === DataEvent.API_PAGE_DELETE
)
request.setRequestHeader('x-access-token', self.token);
switch (contentType) {