You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
183 lines
4.5 KiB
183 lines
4.5 KiB
// post.js
|
|
// Copyright (C) 2021 Digital Telepresence, LLC
|
|
// License: Apache-2.0
|
|
|
|
'use strict';
|
|
|
|
const striptags = require('striptags');
|
|
const slug = require('slug');
|
|
|
|
const { SiteService } = require('../../lib/site-lib');
|
|
|
|
const mongoose = require('mongoose');
|
|
const ObjectId = mongoose.Types.ObjectId;
|
|
|
|
const Post = mongoose.model('Post');
|
|
|
|
class PostService extends SiteService {
|
|
|
|
constructor (dtp) {
|
|
super(dtp, module.exports);
|
|
|
|
this.populatePost = [
|
|
{
|
|
path: 'author',
|
|
select: '_id username username_lc displayName bio picture',
|
|
},
|
|
{
|
|
path: 'image',
|
|
},
|
|
];
|
|
}
|
|
|
|
async create (author, postDefinition) {
|
|
const NOW = new Date();
|
|
|
|
const post = new Post();
|
|
post.created = NOW;
|
|
post.author = author._id;
|
|
post.title = striptags(postDefinition.title.trim());
|
|
post.slug = this.createPostSlug(post._id, post.title);
|
|
post.summary = striptags(postDefinition.summary.trim());
|
|
post.content = postDefinition.content.trim();
|
|
post.status = postDefinition.status || 'draft';
|
|
post.flags = {
|
|
enableComments: postDefinition.enableComments === 'on',
|
|
isFeatured: postDefinition.isFeatured === 'on',
|
|
};
|
|
|
|
await post.save();
|
|
|
|
return post.toObject();
|
|
}
|
|
|
|
async update (post, postDefinition) {
|
|
const NOW = new Date();
|
|
const updateOp = {
|
|
$set: {
|
|
updated: NOW,
|
|
},
|
|
};
|
|
|
|
if (postDefinition.title) {
|
|
updateOp.$set.title = striptags(postDefinition.title.trim());
|
|
updateOp.$set.slug = this.createPostSlug(post._id, updateOp.$set.title);
|
|
}
|
|
if (postDefinition.slug) {
|
|
let postSlug = striptags(slug(postDefinition.slug.trim())).split('-');
|
|
while (ObjectId.isValid(postSlug[postSlug.length - 1])) {
|
|
postSlug.pop();
|
|
}
|
|
postSlug = postSlug.splice(0, 4);
|
|
postSlug.push(post._id.toString());
|
|
updateOp.$set.slug = `${postSlug.join('-')}`;
|
|
}
|
|
if (postDefinition.summary) {
|
|
updateOp.$set.summary = striptags(postDefinition.summary.trim());
|
|
}
|
|
if (postDefinition.content) {
|
|
updateOp.$set.content = postDefinition.content.trim();
|
|
}
|
|
if (postDefinition.status) {
|
|
updateOp.$set.status = striptags(postDefinition.status.trim());
|
|
}
|
|
|
|
updateOp.$set['flags.enableComments'] = postDefinition.enableComments === 'on';
|
|
updateOp.$set['flags.isFeatured'] = postDefinition.isFeatured === 'on';
|
|
|
|
await Post.updateOne(
|
|
{ _id: post._id },
|
|
updateOp,
|
|
{ upsert: true },
|
|
);
|
|
}
|
|
|
|
async updateImage (user, post, file) {
|
|
const { image: imageService } = this.dtp.services;
|
|
const images = [
|
|
{
|
|
width: 960,
|
|
height: 540,
|
|
format: 'jpeg',
|
|
formatParameters: {
|
|
quality: 80,
|
|
},
|
|
},
|
|
];
|
|
await imageService.processImageFile(user, file, images);
|
|
await Post.updateOne(
|
|
{ _id: post._id },
|
|
{
|
|
$set: {
|
|
image: images[0].image._id,
|
|
},
|
|
},
|
|
);
|
|
}
|
|
|
|
async getPosts (pagination, status = ['published']) {
|
|
if (!Array.isArray(status)) {
|
|
status = [status];
|
|
}
|
|
const posts = await Post
|
|
.find({ status: { $in: status }, 'flags.isFeatured': false })
|
|
.sort({ created: -1 })
|
|
.skip(pagination.skip)
|
|
.limit(pagination.cpp)
|
|
.lean();
|
|
return posts;
|
|
}
|
|
|
|
async getFeaturedPosts (maxCount = 3) {
|
|
const posts = await Post
|
|
.find({ status: 'published', 'flags.isFeatured': true })
|
|
.sort({ created: -1 })
|
|
.limit(maxCount)
|
|
.lean();
|
|
return posts;
|
|
}
|
|
|
|
async getAllPosts (pagination) {
|
|
const posts = await Post
|
|
.find()
|
|
.sort({ created: -1 })
|
|
.skip(pagination.skip)
|
|
.limit(pagination.cpp)
|
|
.lean();
|
|
return posts;
|
|
}
|
|
|
|
async getById (postId) {
|
|
const post = await Post
|
|
.findById(postId)
|
|
.select('+content')
|
|
.populate(this.populatePost)
|
|
.lean();
|
|
return post;
|
|
}
|
|
|
|
async getBySlug (postSlug) {
|
|
const slugParts = postSlug.split('-');
|
|
const postId = slugParts[slugParts.length - 1];
|
|
return this.getById(postId);
|
|
}
|
|
|
|
async deletePost (post) {
|
|
this.log.info('deleting post', { postId: post._id });
|
|
await Post.deleteOne({ _id: post._id });
|
|
}
|
|
|
|
createPostSlug (postId, postTitle) {
|
|
if ((typeof postTitle !== 'string') || (postTitle.length < 1)) {
|
|
throw new Error('Invalid input for making a post slug');
|
|
}
|
|
const postSlug = slug(postTitle.trim().toLowerCase()).split('-').slice(0, 4).join('-');
|
|
return `${postSlug}-${postId}`;
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
slug: 'post',
|
|
name: 'post',
|
|
create: (dtp) => { return new PostService(dtp); },
|
|
};
|