From 495bd71f3678f7b4930db6207fdafdff2432512c Mon Sep 17 00:00:00 2001 From: hippoz Date: Sat, 2 Oct 2021 22:50:12 +0300 Subject: [PATCH] feat: add message storage and fetching api --- brainlet/api/v1/content.js | 42 ++++++++++++++++++++++++++------ brainlet/api/v2/gateway/index.js | 15 ++++++++++-- brainlet/config.js | 4 +-- brainlet/models/Message.js | 12 +++++++++ 4 files changed, 61 insertions(+), 12 deletions(-) create mode 100644 brainlet/models/Message.js diff --git a/brainlet/api/v1/content.js b/brainlet/api/v1/content.js index 1a01e4a..a73dcc4 100755 --- a/brainlet/api/v1/content.js +++ b/brainlet/api/v1/content.js @@ -1,6 +1,7 @@ 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"); @@ -38,7 +39,7 @@ app.post("/channel/create", [ res.status(200).json({ error: false, - message: "SUCCESS_CATEGORY_CREATED", + message: "SUCCESS_CHANNEL_CREATED", channel: channel.getPublicObject() }); }, undefined, config.roleMap.USER)); @@ -76,7 +77,7 @@ app.post("/post/create", [ if (r.n < 1) { res.status(404).json({ error: true, - message: "ERROR_CATEGORY_NOT_FOUND" + message: "ERROR_CHANNEL_NOT_FOUND" }); return; } @@ -90,6 +91,33 @@ app.post("/post/create", [ }); }, undefined, config.roleMap.USER)); +app.get("/channel/:channel/messages", [ + 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; + } + + 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) => { @@ -99,23 +127,21 @@ app.get("/channel/:channel/info", [ return; } - const channelId = req.params.channel; - const channel = await Channel.findById(channelId).populate("posts.creator", User.getPulicFields()); + const channel = await Channel.findById(req.params.channel).populate("posts.creator", User.getPulicFields()); - // TODO: Implement subscribing to a channel and stuff const users = await User.find().sort({ _id: -1 }).limit(50).select(User.getPulicFields()); if (!channel) { res.status(404).json({ error: true, - message: "ERROR_CATEGORY_NOT_FOUND" + message: "ERROR_CHANNEL_NOT_FOUND" }); return; } res.status(200).json({ error: false, - message: "SUCCESS_CATEGORY_DATA_FETCHED", + message: "SUCCESS_CHANNEL_DATA_FETCHED", channel: channel.getPublicObject(), userInfo: { userListLimit: 50, @@ -135,7 +161,7 @@ app.get("/channel/list", authenticateEndpoint(async (req, res) => { res.status(200).json({ error: false, - message: "SUCCESS_CATEGORY_LIST_FETCHED", + message: "SUCCESS_CHANNEL_LIST_FETCHED", channels }); }, undefined, config.roleMap.USER)); diff --git a/brainlet/api/v2/gateway/index.js b/brainlet/api/v2/gateway/index.js index 6cb25fa..ca3f40a 100644 --- a/brainlet/api/v2/gateway/index.js +++ b/brainlet/api/v2/gateway/index.js @@ -5,6 +5,7 @@ const { policies, gatewayPingInterval, gatewayPingCheckInterval, clientFacingPin const { experiments } = require("../../../experiments"); const User = require("../../../models/User"); const Channel = require("../../../models/Channel"); +const Message = require("../../../models/Message"); const { parseMessage, packet } = require("./messageparser"); const { checkToken } = require("../../../common/auth/authfunctions"); @@ -20,10 +21,11 @@ const wsCloseCodes = { }; const attributes = { - PRESENCE_UPDATES: "PRESENCE_UPDATES" + PRESENCE_UPDATES: "PRESENCE_UPDATES", + SAVE_MESSAGES: "SAVE_MESSAGES" }; -const supportedAttributes = [attributes.PRESENCE_UPDATES]; +const supportedAttributes = [attributes.PRESENCE_UPDATES, attributes.SAVE_MESSAGES]; class GatewaySession { constructor() { @@ -243,6 +245,15 @@ class GatewayHandler { _id: uuid.v4() }); }); + + if (session.hasAttribute(attributes.SAVE_MESSAGES)) { + await Message.create({ + author: session.user._id, + channel: data.channel._id, + content: messageContent, + createdAt: new Date().getTime() + }); + } } } diff --git a/brainlet/config.js b/brainlet/config.js index 656dc88..d689a76 100755 --- a/brainlet/config.js +++ b/brainlet/config.js @@ -10,7 +10,6 @@ module.exports = { // "https://example.com" "http://localhost:3005", // Allow the server itself (provided it's listening on 3005) - //"http://localhost:3000" // Optionally allow the react app development server (which listens on 3000 by default) ], policies: { // Currently, policies apply to all users - no matter the role. @@ -19,7 +18,7 @@ module.exports = { allowAccountCreation: true, allowLogin: true, allowGatewayConnection: true, - perUserMaxGatewayConnections: 4, + perUserMaxGatewayConnections: 4 }, /* --- Adding a special code requirement for account creation @@ -36,6 +35,7 @@ module.exports = { gatewayPingInterval: 15000, gatewayPingCheckInterval: 4500, clientFacingPingInterval: 14750, + unsafeStoreMessages: false, bcryptRounds: 10, roleMap: { "BANNED": 0, diff --git a/brainlet/models/Message.js b/brainlet/models/Message.js new file mode 100644 index 0000000..e60a9f9 --- /dev/null +++ b/brainlet/models/Message.js @@ -0,0 +1,12 @@ +const mongoose = require("mongoose"); + +const messageSchema = new mongoose.Schema({ + author: {type: mongoose.Schema.Types.ObjectId, ref: "User"}, + channel: {type: mongoose.Schema.Types.ObjectId, ref: "Channel"}, + content: String, + createdAt: Number +}); + +const Message = mongoose.model("Message", messageSchema); + +module.exports = Message; \ No newline at end of file