const User = require("../../models/User"); const Channel = require("../../models/Channel"); const Post = require("../../models/Post"); const Message = require("../../models/Message"); const config = require("../../config"); const { authenticateEndpoint } = require("./../../common/auth/authfunctions"); const mongoose = require("mongoose"); const { body, param, validationResult } = require("express-validator"); const express = require("express"); const rateLimit = require("express-rate-limit"); const app = express.Router(); const createLimiter = rateLimit({ windowMs: 2 * 60 * 1000, max: 10, }); mongoose.connect(config.mongoUrl, {useNewUrlParser: true, useUnifiedTopology: true}); app.post("/channel/create", [ createLimiter, body("title").not().isEmpty().trim().isLength({ min: 3, max: 32 }).escape() ], authenticateEndpoint(async (req, res, user) => { if (!config.policies.allowChannelCreation) return res.status(403).json({ error: true, message: "ERROR_FORBIDDEN_BY_POLICY" }); const errors = validationResult(req); if (!errors.isEmpty()) { res.status(400).json({ error: true, message: "ERROR_REQUEST_INVALID_DATA", errors: errors.array() }); return; } const title = req.body.title; const channel = await Channel.create({ title: title, creator: user._id, posts: [] }); res.status(200).json({ error: false, message: "SUCCESS_CHANNEL_CREATED", channel: channel.getPublicObject() }); }, undefined, config.roleMap.USER)); app.post("/post/create", [ createLimiter, body("channel").not().isEmpty().trim().escape().isLength({ min: 24, max: 24 }), body("title").not().isEmpty().trim().isLength({ min: 3, max: 32 }).escape(), body("body").not().isEmpty().trim().isLength({ min: 3, max: 1000 }).escape(), ], authenticateEndpoint(async (req, res, user) => { if (!config.policies.allowPostCreation) return res.status(403).json({ error: true, message: "ERROR_FORBIDDEN_BY_POLICY" }); const errors = validationResult(req); if (!errors.isEmpty()) { res.status(400).json({ error: true, message: "ERROR_REQUEST_INVALID_DATA", errors: errors.array() }); return; } const channel = req.body.channel; const title = req.body.title; const content = req.body.body; const post = new Post(); post.title = title; post.body = content; post.creator = user._id; post.channel = channel; const r = await Channel.updateOne({ _id: channel }, { $push: { posts: post } }); if (r.n < 1) { res.status(404).json({ error: true, message: "ERROR_CHANNEL_NOT_FOUND" }); return; } res.status(200).json({ error: false, message: "SUCCESS_POST_CREATED", post: { _id: post._id } }); }, undefined, config.roleMap.USER)); app.get("/channel/:channel/messages", [ param("channel").not().isEmpty().trim().escape().isLength({ min: 24, max: 24 }) ], authenticateEndpoint(async (req, res) => { if (!config.policies.allowSavingMessages) { // TODO: hack res.status(200).json({ error: false, message: "SUCCESS_CHANNEL_MESSAGES_FETCHED", channelMessages: [] }); return; } const errors = validationResult(req); if (!errors.isEmpty()) { res.status(400).json({ error: true, message: "ERROR_REQUEST_INVALID_DATA", errors: errors.array() }); return; } let idSearch = {}; if (req.query.before) { idSearch = { _id: { $lt: req.query.before } }; } const messages = await Message.find({ channel: req.params.channel, ...idSearch }) .sort({ _id: -1 }) .limit(50) .select("-__v -channel") .populate("author", "_id username"); res.status(200).json({ error: false, message: "SUCCESS_CHANNEL_MESSAGES_FETCHED", channelMessages: messages }); }, undefined, config.roleMap.USER)); app.get("/channel/:channel/info", [ param("channel").not().isEmpty().trim().escape().isLength({ min: 24, max: 24 }) ], authenticateEndpoint(async (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) { res.status(400).json({ error: true, message: "ERROR_REQUEST_INVALID_DATA", errors: errors.array() }); return; } const channel = await Channel.findById(req.params.channel).populate("posts.creator", User.getPulicFields()); const users = await User.find().sort({ _id: -1 }).limit(50).select(User.getPulicFields()); if (!channel) { res.status(404).json({ error: true, message: "ERROR_CHANNEL_NOT_FOUND" }); return; } res.status(200).json({ error: false, message: "SUCCESS_CHANNEL_DATA_FETCHED", channel: channel.getPublicObject(), userInfo: { userListLimit: 50, users: users } }); }, undefined, config.roleMap.USER)); app.get("/channel/list", authenticateEndpoint(async (req, res) => { let count = parseInt(req.query.count); if (!Number.isInteger(count)) { count = 10; } // TODO: This is probably not efficient const channels = await Channel.find().lean().sort({ _id: -1 }).limit(count).select("-posts -__v").populate("creator", User.getPulicFields()); res.status(200).json({ error: false, message: "SUCCESS_CHANNEL_LIST_FETCHED", channels }); }, undefined, config.roleMap.USER)); module.exports = app;