cubash-archive/models/post.js

147 lines
4.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

var md = require('../kaverti_modules/markdown-it')({
html: false, // Enable HTML tags in source
xhtmlOut: false, // Use '/' to close single tags (<br />).
// This is only for full CommonMark compatibility.
breaks: true, // Convert '\n' in paragraphs into <br>
langPrefix: 'language-', // CSS language prefix for fenced blocks. Can be
// useful for external highlighters.
linkify: true, // Autoconvert URL-like text to links
image: false,
// Enable some language-neutral replacement + quotes beautification
typographer: true,
// Double + single quotes replacement pairs, when typographer enabled,
// and smartquotes on. Could be either a String or an Array.
//
// For example, you can use '«»„“' for Russian, '„“‚‘' for German,
// and ['«\xA0', '\xA0»', '\xA0', '\xA0'] for French (including nbsp).
quotes: '“”‘’',
// Highlighter function. Should return escaped HTML,
// or '' if the source string is not changed and should be escaped externally.
// If result starts with <pre... internal wrapper is skipped.
highlight: function (/*str, lang*/) { return ''; }
});
md.disable('image')
let createDOMPurify = require('dompurify');
let { JSDOM } = require('jsdom');
var marked = require('marked')
let window = new JSDOM('').window;
let DOMPurify = createDOMPurify(window);
var escaped_str = require('querystring')
const Errors = require('../lib/errors')
const renderer = new marked.Renderer();
renderer.image = function (text) {
return text;
};
renderer.link = function (href, title, text) {
if (!href.match(/[a-z]+:\/\/.+/i)) {
href = 'http://' + href;
}
return `
<a href='/out/?uri=${href}' ${title ? "title='" + title + "'" : ""} target='_blank' rel='noopener'>
${text}
</a>
`;
}
module.exports = (sequelize, DataTypes) => {
let Post = sequelize.define('Post', {
content: {
type: DataTypes.TEXT,
set (val) {
if(!val) {
throw Errors.sequelizeValidation(sequelize, {
error: 'content must be a string',
path: 'content'
})
}
let rawHTML = md.render(val);
let cleanHTML = DOMPurify.sanitize(rawHTML);
let plainText = (new JSDOM(cleanHTML)).window.document.body.textContent;
if (!plainText.trim().length) {
throw Errors.sequelizeValidation(sequelize, {
error: 'Post content must not be empty',
path: 'content'
})
}
this.setDataValue('content', cleanHTML)
this.setDataValue('plainText', plainText)
},
allowNull: false
},
plainText: {
type: DataTypes.TEXT,
},
postNumber: DataTypes.INTEGER,
replyingToUsername: DataTypes.STRING,
removed: {
type: DataTypes.BOOLEAN,
defaultValue: false
}
}, {
instanceMethods: {
getReplyingTo () {
return Post.findByPrimary(this.replyId)
},
setReplyingTo (post) {
return post.getUser().then(user => {
return this.update({ replyingToUsername: user.username, replyId: post.id })
})
}
},
classMethods: {
associate (models) {
Post.belongsTo(models.User)
Post.belongsTo(models.Thread)
Post.hasMany(models.Post, { as: 'Replies', foreignKey: 'replyId' })
Post.belongsToMany(models.User, { as: 'Likes', through: 'user_post' })
Post.hasMany(models.Report, { foreignKeyConstraint: true, onDelete: 'CASCADE', hooks: true })
},
includeOptions () {
let models = sequelize.models
return [
{ model: models.User, attributes: ['username', 'createdAt', 'id', 'color', 'picture'] },
{ model: models.User, as: 'Likes', attributes: ['username', 'createdAt', 'id', 'color', 'picture'] },
{ model: models.Thread, include: [models.Category]} ,
{
model: models.Post, as: 'Replies', include:
[{ model: models.User, attributes: ['username', 'id', 'color', 'picture'] }]
}
]
},
async getReplyingToPost (id, thread) {
let { Thread, User } = sequelize.models
let replyingToPost = await Post.findById(
id,
{ include: [Thread, { model: User, attributes: ['username'] }] }
)
if(!replyingToPost) {
throw Errors.invalidParameter('replyingToId', 'post does not exist')
} else if(replyingToPost.Thread.id !== thread.id) {
throw Errors.invalidParameter('replyingToId', 'replies must be in same thread')
} else if (replyingToPost.removed) {
throw Errors.postRemoved
} else {
return replyingToPost
}
}
}
})
return Post
}