Commit 7037ef8d authored by Jarrod's avatar Jarrod 💬

Blog stuff. Mostly done!

parent 6211efc0
module.exports = {
friendlyName: `Create a blog post`,
description: ``,
inputs: {
slug: {
type: 'string',
required: true
},
title: {
type: 'string',
required: true
},
excerpt: {
type: 'string',
required: true
},
body: {
type: 'string',
required: true
},
published: {
type: 'boolean',
defaultsTo: false
},
category: {
type: 'number',
isInteger: true,
allowNull: true
},
featureImage: {
type: 'string',
allowNull: true
},
createdAt: {
type: 'ref',
}
},
exits: {
created: {
statusCode: 201,
description: 'Blog post was created'
}
},
fn: async function (inputs, exits) {
let post = await BlogPost.create(inputs).fetch()
// All done.
return exits.created({
post
})
}
}
module.exports = {
friendlyName: `Delete a blog image`,
description: ``,
inputs: {
post: {
type: 'number',
isInteger: true
},
filename: {
type: 'string',
required: true,
description: 'The name of the file to delete'
}
},
exits: {
badRequest: {
responseType: 'badRequest',
statusCode: 400
}
},
fn: async function (inputs) {
inputs.filename = inputs.filename.replace(/^article\//, '')
console.log('Removing ', inputs.filename)
await sails.rm(inputs.filename, sails.config.uploads.blog)
if (inputs.post) {
BlogPost
.update({ id: inputs.id })
.set({ featureImage: null })
.then(() => {})
}
// All done.
return {
message: 'ok'
}
}
}
module.exports = {
friendlyName: `Delete a blog post`,
description: ``,
inputs: {
id: {
type: 'number',
isInteger: true,
required: true
}
},
exits: { },
fn: async function (inputs) {
let post = await BlogPost.findOne({
id: inputs.id
})
if (!post) {
return this.res.badRequest('Post not found')
}
post = await BlogPost
.destroyOne({ id: inputs.id })
// Remove any images for this post
sails.rm(inputs.id + '/*', sails.config.uploads.blog, () => {})
// All done.
return {
post
}
}
}
module.exports = {
friendlyName: 'Admin Blog Index',
description: 'Get a list of all blog posts.',
inputs: {
// page: {
// type: 'number',
// isInteger: true,
// defaultsTo: 1,
// min: 1
// }
},
exits: {
},
fn: async function (inputs) {
const posts = await BlogPost
.find({ })
.select(['id', 'slug', 'title', 'published', 'excerpt', 'featureImage', 'createdAt'])
.sort('createdAt DESC')
.populate('category')
const categories = await BlogCategory
.find()
.sort('name ASC')
// All done.
return {
posts,
categories
}
}
}
module.exports = {
friendlyName: `Get Article as an administrator`,
description: `Get a blog post regardless of whether it's "published" or not`,
inputs: {
id: {
type: 'number',
isInteger: true,
required: true
}
},
exits: { },
fn: async function (inputs) {
const post = await BlogPost.findOne({
id: inputs.id
})
if (!post) {
return this.res.notFound('Post not found')
}
// All done.
return {
post
}
}
}
module.exports = {
friendlyName: `Update a blog post`,
description: ``,
inputs: {
id: {
type: 'number',
isInteger: true,
required: true
},
slug: {
type: 'string',
required: true
},
title: {
type: 'string',
required: true
},
excerpt: {
type: 'string',
required: true
},
body: {
type: 'string',
required: true
},
published: {
type: 'boolean',
defaultsTo: false
},
category: {
type: 'number',
isInteger: true,
allowNull: true
},
featureImage: {
type: 'string',
allowNull: true
},
createdAt: {
type: 'ref',
}
},
exits: { },
fn: async function (inputs) {
let post = await BlogPost.findOne({
id: inputs.id
})
if (!post) {
return this.res.badRequest('Post not found')
}
post = await BlogPost
.updateOne({ id: inputs.id })
.set(_.omit(inputs, ['id']))
// All done.
return {
post
}
}
}
module.exports = {
friendlyName: `Upload an image for a blog post`,
description: ``,
files: ['file'],
inputs: {
post: {
type: 'number',
isInteger: true,
required: true,
description: 'The ID of the post this image is attached to'
},
file: {
type: 'ref',
description: 'The file to upload',
required: true
}
},
exits: {
badRequest: {
responseType: 'badRequest',
statusCode: 400
}
},
fn: async function (inputs) {
const post = await BlogPost.findOne({ id: inputs.post })
if (!post) {
return this.res.badRequest('Invalid post ID')
}
const uploadConfig = _.merge(sails.config.uploads.blog || {}, {
saveAs: function (__file, cb) {
// Generate a filename like 'postId/RANDOMoriginalfile.jpg'
const pseudoRandomString = Math.random().toString(36).substring(7) + '-'
return cb(null, post.id + '/' + pseudoRandomString + __file.filename)
},
})
let file = await sails.uploadOne(inputs.file, uploadConfig)
.intercept('E_INVALID_FILE_TYPE', () => {
return { badRequest: 'Uploaded file type not allowed!' }
})
.intercept('E_EXCEEDS_UPLOAD_LIMIT', () => {
return { badRequest: 'Uploaded file is too large!' }
})
.intercept((err) => {
sails.log.error(`Unable to upload image for blog post`, err.stack)
return new Error('Unable to save uploaded file(s)')
})
let url = 'article/' + file.fd;
BlogPost.updateOne({ id: post.id })
.set({ featureImage: url })
.then(() => { })
// All done.
return {
url
}
}
}
module.exports = {
friendlyName: `Get all categories`,
description: ``,
inputs: { },
exits: { },
fn: async function (inputs) {
const categories = await BlogCategory.find({ })
// All done.
return {
categories
}
}
}
......@@ -14,10 +14,18 @@ module.exports = {
},
fn: async function (inputs) {
const post = await BlogPost.findOne({
published: true,
const { req } = this
const where = {
slug: inputs.slug
})
}
// Allow admins to 'preview' unpublished posts
// TODO: Replace with actual 'permissions' handling stuff
if (!req.me || !req.me.isAdmin) {
where.published = true
}
const post = await BlogPost.findOne(where)
.select(['id', 'slug', 'title', 'excerpt', 'body', 'featureImage', 'createdAt'])
.populate('category')
......@@ -27,7 +35,6 @@ module.exports = {
const recentPosts = await BlogPost.find({
published: true,
slug: inputs.slug,
id: { '!=': post.id }
})
.select(['id', 'slug', 'title', 'excerpt', 'featureImage', 'createdAt'])
......
......@@ -4,7 +4,8 @@
const Pluggable = require('@nahanil/ahoy/lib/pluggable')
module.exports = new Pluggable({
apiBase: 'blog',
key: 'blog',
apiBase: '',
dir: __dirname,
// Add permissions @ core ahoy level?
......@@ -14,15 +15,18 @@ module.exports = new Pluggable({
actions: {
// Public routes
'GET /': { action: 'index', cache: 10 },
'GET /category/:slug': { action: 'get-category', cache: 10 },
'GET /post/:slug': { action: 'get-post', cache: 10 },
'GET /blog': { action: 'index', cache: 10 },
'GET /blog/categories': { action: 'get-categories', cache: 10 },
'GET /blog/category/:slug': { action: 'get-category', cache: 10 },
'GET /blog/post/:slug': { action: 'get-post', cache: 10 },
// Admin routes
// 'GET /all': { action: 'get-all-posts', permission: 'blog' },
// 'POST /post': { action: 'create-post', permission: 'blog' },
// 'PUT /post/:id': { action: 'update-post', permission: 'blog' },
// 'DELETE /post/:id': { action: 'delete-post', permission: 'blog' },
// 'POST /image': { action: 'upload-image', permission: 'blog' },
'GET /admin/blog/list': { action: 'admin/get-all-posts', permission: 'blog' },
'GET /admin/blog/post/:id': { action: 'admin/get-post', permission: 'blog' },
'POST /admin/blog/post': { action: 'admin/create-post', permission: 'blog' },
'PUT /admin/blog/post/:id': { action: 'admin/update-post', permission: 'blog' },
'DELETE /admin/blog/post/:id': { action: 'admin/delete-post', permission: 'blog' },
'POST /admin/blog/image': { action: 'admin/upload-image', permission: 'blog' },
'DELETE /admin/blog/image': { action: 'admin/delete-image', permission: 'blog' },
}
})
......@@ -18,6 +18,7 @@ module.exports = {
slug: {
type: 'string',
required: true,
unique: true,
description: 'URL slug for this article'
},
......
......@@ -18,6 +18,7 @@ module.exports = {
slug: {
type: 'string',
required: true,
unique: true,
description: 'URL slug for this article'
},
......@@ -54,6 +55,9 @@ module.exports = {
},
},
beforeCreate: ensureCategory,
beforeUpdate: ensureCategory,
extend: {
user: {
articles: {
......@@ -63,3 +67,21 @@ module.exports = {
}
}
};
/*
* Ensures that all blog posts should always belong to a category
*/
async function ensureCategory (values, next) {
if (!values.category) {
let category = await BlogCategory.findOne({ where: { slug: 'uncategorized' } });
if (!category) {
category = await BlogCategory.create({
name: 'Uncategorized',
slug: 'uncategorized'
}).fetch();
}
values.category = category.id;
}
next()
}
\ No newline at end of file
......@@ -10,6 +10,9 @@
"isHook": true,
"hookName": "blog"
},
"peerDependencies": {
"sails-hook-uploads": "0.x"
},
"author": "",
"license": "MIT"
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment