Skip to content

Commit

Permalink
🆕 revision, content routes
Browse files Browse the repository at this point in the history
  • Loading branch information
scottnath committed Jul 8, 2016
1 parent 9e1ee25 commit 902551a
Show file tree
Hide file tree
Showing 4 changed files with 252 additions and 66 deletions.
12 changes: 11 additions & 1 deletion config/default.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,20 @@ module.exports = {
},
directory: path.join(__dirname, '../content-types'),
messages: {
content: {
title: 'Revisions for \'%id\'',
},
format: {
id: 'Content ID must be in UUID format',
revision: 'Revision must be a number',
},
missing: {
type: 'Content Type \'%type\' not found',
id: 'Content with ID \'%id\' in Content Type \'%type\' not found',
revision: 'Revision for ID \'%id\' in Content Type \'%type\' not found',
revision: 'Revision \'%revision\' for ID \'%id\' in Content Type \'%type\' not found',
},
revisions: {
title: 'Revision \'%revision\' for \'%id\'',
},
},
},
Expand Down
224 changes: 159 additions & 65 deletions lib/routes/content.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,52 @@ const content = require('punchcard-content-types');
const multipart = require('connect-multiparty');
const uuid = require('uuid');
const _ = require('lodash');
const isUUID = require('validator/lib/isUUID');

const utils = require('../utils');
const database = require('../database');

const multipartMiddleware = multipart();

const check = {
id: (req) => {
if (!isUUID(req.params.id)) {
_.set(req.session, '404', {
message: config.content.messages.format.id,
safe: `/${config.content.base}`,
});

return false;
}

return true;
},
revision: (req) => {
if (!Number.isInteger(parseInt(req.params.revision, 10))) {
_.set(req.session, '404', {
message: config.content.messages.format.revision.replace('%revision', req.params.revision),
safe: `/${config.content.base}`,
});

return false;
}

return true;
},
type: (req, type) => {
if (type === false) {
_.set(req.session, '404', {
message: config.content.messages.missing.type.replace('%type', req.params.type),
safe: `/${config.content.base}`,
});

return false;
}

return true;
},
};

/*
* Content Route Resolution
*
Expand Down Expand Up @@ -52,12 +92,8 @@ const routes = application => {
app.get(`/${config.content.base}/:type`, (req, res, next) => {
const type = utils.singleItem('id', req.params.type.toLowerCase(), types);

if (type === false) {
_.set(req.session, '404', {
message: config.content.messages.missing.type.replace('%type', req.params.type),
safe: `/${config.content.base}`,
});

// check type exists
if (!check.type(req, type)) {
return next();
}

Expand Down Expand Up @@ -96,12 +132,8 @@ const routes = application => {

values = utils.config(values);

if (type === false) {
_.set(req.session, '404', {
message: config.content.messages.missing.type.replace('%type', req.params.type),
safe: `/${config.content.base}`,
});

// check type exists
if (!check.type(req, type)) {
return next();
}

Expand All @@ -120,59 +152,137 @@ const routes = application => {
});

/*
* @name Individual Content Type Edit Page
* @name Individual Piece of Content
*
* @param {object} req - HTTP Request
* @param {object} res - HTTP Response
* @param {object} next - Express callback
*/
app.get(`/${config.content.base}/:type/:id/:revision/${config.content.actions.edit}`, (req, res, next) => {
app.get(`/${config.content.base}/:type/:id`, (req, res, next) => {
const type = utils.singleItem('id', req.params.type.toLowerCase(), types);
const errors = _.get(req.session, `form.content.add[${req.params.type.toLowerCase()}].errors`, {});
const idSess = _.get(req.session, `form.content.add[${req.params.type.toLowerCase()}].id`, {});
const revisionSess = _.get(req.session, `form.content.add[${req.params.type.toLowerCase()}].revision`, {});
let values = _.get(req.session, `form.content.add[${req.params.type.toLowerCase()}].content`, {});
const data = {};
let revisionSearch;

_.unset(req.session, 'form.content.add');
// check type exists
if (!check.type(req, type)) {
return next();
}

values = utils.config(values);
// id in url is not UUID
if (!check.id(req)) {
return next();
}

// no content type in url, so 404
if (type === false) {
_.set(req.session, '404', {
message: config.content.messages.missing.type.replace('%type', req.params.type),
safe: `/${config.content.base}`,
type.primary = type.attributes[0].inputs[Object.keys(type.attributes[0].inputs)[0]].name;

return database
.select('*')
.from(`content-type--${type.id}`)
.where('id', req.params.id)
.orderBy('revision', 'DESC').then(rows => {
if (rows.length < 1) {
_.set(req.session, '404', {
message: config.content.messages.missing.id.replace('%type', req.params.type).replace('%id', req.params.id),
safe: `/${config.content.base}/${req.params.type}`,
});

return next();
}

res.render('content/content', {
title: config.content.messages.content.title.replace('%id', req.params.id),
content: rows,
type,
config: config.content,
});

return true;
});
});

/*
* @name Specific revision of an Individual Piece of Content
*
* @param {object} req - HTTP Request
* @param {object} res - HTTP Response
* @param {object} next - Express callback
*/
app.get(`/${config.content.base}/:type/:id/:revision`, (req, res, next) => {
const type = utils.singleItem('id', req.params.type.toLowerCase(), types);

// check type exists
if (!check.type(req, type)) {
return next();
}

// id in url is not UUID
if (!check.id(req)) {
return next();
}

// revision in url is not a number
if (!check.revision(req)) {
return next();
}

// no id in url, so 404
if (!req.params.id) {
_.set(req.session, '404', {
message: config.content.messages.missing.id.replace('%type', req.params.type).replace('%id', req.params.id),
safe: `/${config.content.base}/${req.params.type}`,
type.primary = type.attributes[0].inputs[Object.keys(type.attributes[0].inputs)[0]].name;

return database
.select('*')
.from(`content-type--${type.id}`)
.where('revision', req.params.revision)
.orderBy('revision', 'DESC').then(rows => {
if (rows.length < 1) {
_.set(req.session, '404', {
message: config.content.messages.missing.revision.replace('%revision', req.params.revision).replace('%type', req.params.type).replace('%id', req.params.id),
safe: `/${config.content.base}/${req.params.type}`,
});

return next();
}

res.render('content/content', {
title: config.content.messages.revisions.title.replace('%revision', req.params.revision).replace('%id', req.params.id),
content: rows,
type,
config: config.content,
});

return true;
});
});

/*
* @name Individual Content Type Edit Page
*
* @param {object} req - HTTP Request
* @param {object} res - HTTP Response
* @param {object} next - Express callback
*/
app.get(`/${config.content.base}/:type/:id/:revision/${config.content.actions.edit}`, (req, res, next) => {
const type = utils.singleItem('id', req.params.type.toLowerCase(), types);
const errors = _.get(req.session, `form.content.add[${req.params.type.toLowerCase()}].errors`, {});
const idSess = _.get(req.session, `form.content.add[${req.params.type.toLowerCase()}].id`, {});
const revisionSess = _.get(req.session, `form.content.add[${req.params.type.toLowerCase()}].revision`, {});
let values = _.get(req.session, `form.content.add[${req.params.type.toLowerCase()}].content`, {});
const data = {};

// check type exists
if (!check.type(req, type)) {
return next();
}

// no revision in url, so create search to find latest revision
if (!req.params.revision || !Number.isInteger(req.params.revision)) {
revisionSearch = database(`content-type--${type.id}`)
.select('revision')
.where('id', req.params.id)
.orderBy('revision', 'DESC')
.limit(1);
// id in url is not UUID
if (!check.id(req)) {
return next();
}
else {
revisionSearch = database(`content-type--${type.id}`)
.select('revision')
.where('revision', req.params.revision);

// revision in url is not a number
if (!check.revision(req)) {
return next();
}

_.unset(req.session, 'form.content.add');

values = utils.config(values);

// something went wrong on save:
if (Object.keys(values).length > 0) {
Expand Down Expand Up @@ -201,25 +311,13 @@ const routes = application => {
// eslint mad if no return, then mad at this else if it is there
else { // eslint-disable-line no-else-return
// Search for the revision
return revisionSearch.then(rows => {
if (rows.length < 1) {
_.set(req.session, '404', {
message: config.content.messages.missing.revision.replace('%type', req.params.type).replace('%id', req.params.id),
safe: `/${config.content.base}/${req.params.type}`,
});

return next();
}
const revision = rows[0].revision;

return database(`content-type--${type.id}`).where({
id: req.params.id,
revision,
});
return database(`content-type--${type.id}`).where({
id: req.params.id,
revision: req.params.revision,
}).then(rows => {
if (rows.length < 1) {
_.set(req.session, '404', {
message: config.content.messages.missing.id.replace('%type', req.params.type).replace('%id', req.params.id).replace('%revision', req.params.revision),
message: config.content.messages.missing.revision.replace('%type', req.params.type).replace('%id', req.params.id).replace('%revision', req.params.revision),
safe: `/${config.content.base}/${req.params.type}`,
});

Expand Down Expand Up @@ -282,12 +380,8 @@ const routes = application => {
app.post(`/${config.content.base}/:type/${config.content.actions.save}`, multipartMiddleware, (req, res, next) => {
const type = utils.singleItem('id', req.params.type.toLowerCase(), types);

if (type === false) {
_.set(req.session, '404', {
message: config.content.messages.missing.type.replace('%type', req.params.type),
safe: `/${config.content.base}`,
});

// check type exists
if (!check.type(req, type)) {
return next();
}

Expand Down
41 changes: 41 additions & 0 deletions views/content/content.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{% extends "_donut.html" %}

{% block pageHead %}
{{ super() }}
{% endblock %}

{% block header %}
{{ super() }}
{% endblock %}

{% block main %}
<h1 class="base--h1">{{title}}</h1>

<h2 class="base--h2">Revisions</h2>

{% if content %}

<table class="table--style">
<tr class="table--tr">
<th class="table--th">revision</th>
<th class="table--th">{{config.base}}</th>
<th class="table--th">{{config.actions.edit}}</th>
<th class="table--th">date</th>
</tr>
{% for c in content %}
{% if c.value %}
<tr class="table--tr">
<td class="table--td">{{c.revision}}</td>
<td class="table--td">{{c.value[type.primary]}}</td>
<td class="table--td"><a href="/{{config.base}}/{{type.id}}/{{c.id}}/{{c.revision}}/{{config.actions.edit}}" class="table--a">{{config.actions.edit}}</a></td>
<td class="table--td">{{c.created}}</td>
</tr>
{% endif %}
{% endfor %}
</table>
{% endif %}
{% endblock %}

{% block footer %}
{{ super() }}
{% endblock %}
Loading

0 comments on commit 902551a

Please sign in to comment.