|
|
|
|
@ -1,37 +1,37 @@
|
|
|
|
|
import { Router } from 'express'
|
|
|
|
|
// import { Movie } from '../models/Post'
|
|
|
|
|
import { File } from '../lib/models/File'
|
|
|
|
|
import { Post } from '../lib/models/Post';
|
|
|
|
|
import jwt, { UserJwtRequest } from '../lib/middleware/jwt';
|
|
|
|
|
import { Router } from "express";
|
|
|
|
|
import { celebrate, Joi } from "celebrate";
|
|
|
|
|
import { File } from '@lib/models/File'
|
|
|
|
|
import { Post } from '@lib/models/Post';
|
|
|
|
|
import jwt, { UserJwtRequest } from '@lib/middleware/jwt';
|
|
|
|
|
import * as crypto from "crypto";
|
|
|
|
|
import { User } from '../lib/models/User';
|
|
|
|
|
import secretKey from '../lib/middleware/secret-key';
|
|
|
|
|
import markdown from '../lib/render-markdown';
|
|
|
|
|
import { User } from '@lib/models/User';
|
|
|
|
|
import secretKey from '@lib/middleware/secret-key';
|
|
|
|
|
import markdown from '@lib/render-markdown';
|
|
|
|
|
|
|
|
|
|
export const posts = Router()
|
|
|
|
|
export const posts = Router();
|
|
|
|
|
|
|
|
|
|
posts.post('/create', jwt, async (req, res, next) => {
|
|
|
|
|
try {
|
|
|
|
|
if (!req.body.files) {
|
|
|
|
|
throw new Error("Please provide files.")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!req.body.title) {
|
|
|
|
|
throw new Error("Please provide a title.")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!req.body.userId) {
|
|
|
|
|
throw new Error("No user id provided.")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!req.body.visibility) {
|
|
|
|
|
throw new Error("Please provide a visibility.")
|
|
|
|
|
const postVisibilitySchema = (value: string) => {
|
|
|
|
|
if (value === 'public' || value === 'private') {
|
|
|
|
|
return value;
|
|
|
|
|
} else {
|
|
|
|
|
throw new Error('Invalid post visibility');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (req.body.visibility === 'protected' && !req.body.password) {
|
|
|
|
|
throw new Error("Please provide a password.")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
posts.post(
|
|
|
|
|
"/create",
|
|
|
|
|
jwt,
|
|
|
|
|
celebrate({
|
|
|
|
|
body: {
|
|
|
|
|
title: Joi.string().required(),
|
|
|
|
|
files: Joi.any().required(),
|
|
|
|
|
visibility: Joi.string().custom(postVisibilitySchema, 'valid visibility').required(),
|
|
|
|
|
userId: Joi.string().required(),
|
|
|
|
|
password: Joi.string().optional(),
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
async (req, res, next) => {
|
|
|
|
|
try {
|
|
|
|
|
let hashedPassword: string = ''
|
|
|
|
|
if (req.body.visibility === 'protected') {
|
|
|
|
|
hashedPassword = crypto.createHash('sha256').update(req.body.password).digest('hex');
|
|
|
|
|
@ -46,24 +46,7 @@ posts.post('/create', jwt, async (req, res, next) => {
|
|
|
|
|
await newPost.save()
|
|
|
|
|
await newPost.$add('users', req.body.userId);
|
|
|
|
|
const newFiles = await Promise.all(req.body.files.map(async (file) => {
|
|
|
|
|
const renderAsMarkdown = ['markdown', 'md', 'mdown', 'mkdn', 'mkd', 'mdwn', 'mdtxt', 'mdtext', 'text', '']
|
|
|
|
|
const fileType = () => {
|
|
|
|
|
const pathParts = file.title.split(".")
|
|
|
|
|
const language = pathParts.length > 1 ? pathParts[pathParts.length - 1] : ""
|
|
|
|
|
return language
|
|
|
|
|
}
|
|
|
|
|
const type = fileType()
|
|
|
|
|
let contentToRender: string = (file.content || '');
|
|
|
|
|
|
|
|
|
|
if (!renderAsMarkdown.includes(type)) {
|
|
|
|
|
contentToRender =
|
|
|
|
|
`~~~${type}
|
|
|
|
|
${file.content}
|
|
|
|
|
~~~`
|
|
|
|
|
} else {
|
|
|
|
|
contentToRender = '\n' + file.content;
|
|
|
|
|
}
|
|
|
|
|
const html = markdown(contentToRender)
|
|
|
|
|
const html = getHtmlFromFile(file);
|
|
|
|
|
const newFile = new File({
|
|
|
|
|
title: file.title,
|
|
|
|
|
content: file.content,
|
|
|
|
|
@ -86,13 +69,15 @@ ${file.content}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
next(e);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
posts.get("/", secretKey, async (req, res, next) => {
|
|
|
|
|
try {
|
|
|
|
|
const posts = await Post.findAll({
|
|
|
|
|
attributes: ["id", "title", "visibility", "createdAt"],
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
res.json(posts);
|
|
|
|
|
} catch (e) {
|
|
|
|
|
next(e);
|
|
|
|
|
@ -128,30 +113,48 @@ posts.get("/mine", jwt, secretKey, async (req: UserJwtRequest, res, next) => {
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
posts.get("/:id", async (req, res, next) => {
|
|
|
|
|
posts.get(
|
|
|
|
|
"/:id",
|
|
|
|
|
celebrate({
|
|
|
|
|
params: {
|
|
|
|
|
id: Joi.string().required(),
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
async (req: UserJwtRequest, res, next) => {
|
|
|
|
|
try {
|
|
|
|
|
const post = await Post.findOne({
|
|
|
|
|
where: {
|
|
|
|
|
id: req.params.id
|
|
|
|
|
id: req.params.id,
|
|
|
|
|
},
|
|
|
|
|
include: [
|
|
|
|
|
{
|
|
|
|
|
model: File,
|
|
|
|
|
as: "files",
|
|
|
|
|
attributes: ["id", "title", "content", "sha", "createdAt", "updatedAt"],
|
|
|
|
|
attributes: [
|
|
|
|
|
"id",
|
|
|
|
|
"title",
|
|
|
|
|
"content",
|
|
|
|
|
"sha",
|
|
|
|
|
"createdAt",
|
|
|
|
|
"updatedAt",
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
model: User,
|
|
|
|
|
as: "users",
|
|
|
|
|
attributes: ["id", "username"],
|
|
|
|
|
},
|
|
|
|
|
]
|
|
|
|
|
})
|
|
|
|
|
],
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!post) {
|
|
|
|
|
throw new Error("Post not found.")
|
|
|
|
|
return res.status(404).json({ error: "Post not found" })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if public or unlisted, cache
|
|
|
|
|
if (post.visibility === 'public' || post.visibility === 'unlisted') {
|
|
|
|
|
res.set('Cache-Control', 'public, max-age=4800')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (post.visibility === 'public' || post?.visibility === 'unlisted') {
|
|
|
|
|
secretKey(req, res, () => {
|
|
|
|
|
@ -179,4 +182,28 @@ posts.get("/:id", async (req, res, next) => {
|
|
|
|
|
catch (e) {
|
|
|
|
|
next(e);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
function getHtmlFromFile(file: any) {
|
|
|
|
|
const renderAsMarkdown = ['markdown', 'md', 'mdown', 'mkdn', 'mkd', 'mdwn', 'mdtxt', 'mdtext', 'text', ''];
|
|
|
|
|
const fileType = () => {
|
|
|
|
|
const pathParts = file.title.split(".");
|
|
|
|
|
const language = pathParts.length > 1 ? pathParts[pathParts.length - 1] : "";
|
|
|
|
|
return language;
|
|
|
|
|
};
|
|
|
|
|
const type = fileType();
|
|
|
|
|
let contentToRender: string = (file.content || '');
|
|
|
|
|
|
|
|
|
|
if (!renderAsMarkdown.includes(type)) {
|
|
|
|
|
contentToRender =
|
|
|
|
|
`~~~${type}
|
|
|
|
|
${file.content}
|
|
|
|
|
~~~`;
|
|
|
|
|
} else {
|
|
|
|
|
contentToRender = '\n' + file.content;
|
|
|
|
|
}
|
|
|
|
|
const html = markdown(contentToRender);
|
|
|
|
|
return html;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|