forked from kaverti/website
133 lines
4.1 KiB
JavaScript
133 lines
4.1 KiB
JavaScript
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')
|
||
var emoji = require('markdown-it-emoji');
|
||
var twemoji = require('twemoji')
|
||
md.use(emoji);
|
||
md.renderer.rules.emoji = function(token, idx) {
|
||
return twemoji.parse(token[idx].content);
|
||
};
|
||
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
|
||
}
|
||
})
|
||
Post.associate = function (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 })
|
||
}
|
||
Post.includeOptions = function () {
|
||
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'] }]
|
||
}
|
||
]
|
||
}
|
||
Post.getReplyingToPost = function (id, thread, replyingToPost) {
|
||
let { Thread, User } = sequelize.models
|
||
return replyingToPost
|
||
}
|
||
Post.prototype.setReplyingTo = function (post) {
|
||
return post.getUser().then(user => {
|
||
return this.update({ replyingToUsername: user.username, replyId: post.id })
|
||
})
|
||
}
|
||
Post.getReplyingTo = function () {
|
||
return Post.findByPrimary(this.replyId)
|
||
}
|
||
return Post
|
||
}
|