From dc29ed59069db78ebfb8f1c05cbe2fe486c383ce Mon Sep 17 00:00:00 2001
From: Akif9748 <akif9748@gmail.com>
Date: Wed, 10 Aug 2022 02:08:18 +0300
Subject: [PATCH] API is optimized, and better ratelimit

---
 README.md                    |  2 +-
 public/js/navbar.js          |  0
 routes/api/ApiResponse.js    |  7 -------
 routes/api/index.js          | 34 +++++++++++++++++--------------
 routes/api/routes/message.js | 39 +++++++++++++++++++-----------------
 routes/api/routes/threads.js | 32 ++++++++++++-----------------
 routes/api/routes/user.js    | 15 +++++---------
 routes/message.js            |  6 +++++-
 routes/threads.js            | 10 ++++++---
 9 files changed, 71 insertions(+), 74 deletions(-)
 delete mode 100644 public/js/navbar.js
 delete mode 100644 routes/api/ApiResponse.js

diff --git a/README.md b/README.md
index d9dcd27..795ea53 100644
--- a/README.md
+++ b/README.md
@@ -23,7 +23,7 @@ And, you can learn about API in `util/APIDOCS.md`.
 - `/errors/error` will change, better error page.
 - Redirect query.
 - Will fix API
-
+- message.js/12, so, admin perms,(req.user?.admin || !thread.deleted), and api in message
 ## Roadmap
 ### User
 | To do | Is done? | Priority |
diff --git a/public/js/navbar.js b/public/js/navbar.js
deleted file mode 100644
index e69de29..0000000
diff --git a/routes/api/ApiResponse.js b/routes/api/ApiResponse.js
deleted file mode 100644
index 39b9280..0000000
--- a/routes/api/ApiResponse.js
+++ /dev/null
@@ -1,7 +0,0 @@
-class ApiResponse {
-    constructor(status, result) {
-        this.status = status;
-        this.result = result;
-    }
-}
-module.exports = ApiResponse;
\ No newline at end of file
diff --git a/routes/api/index.js b/routes/api/index.js
index b25aa6a..0f1afdf 100644
--- a/routes/api/index.js
+++ b/routes/api/index.js
@@ -1,13 +1,10 @@
 const { Router } = require("express")
 const app = Router();
+const bcrypt = require("bcrypt");
 
-/**
- * @deprecated 
- * for less time
- */
 const { request, response } = require("express");
-const { SecretModel } = require("../../models")
-const ApiResponse = require("./ApiResponse")
+const { SecretModel, UserModel } = require("../../models")
+
 /**
  * AUTH TYPE:
  
@@ -34,30 +31,37 @@ const ApiResponse = require("./ApiResponse")
  * @param {request} req 
  * @param {response} res 
  */
-/*
+
 app.use(async (req, res, next) => {
-    const error = (status, error) =>
-        res.status(status).json(new ApiResponse(status, { error }))
+    res.error = (status, error) =>
+        res.status(status).json({ status, result: { error } })
+
+    res.complate = result => res.status(200).json({ status: 200, result });
 
     const { username = null, password = null } = req.headers;
 
     if (!username || !password)
-        return error(401, "Authorise headers are missing")
+        return res.error(401, "Authorise headers are missing")
 
     const user = await SecretModel.findOne({ username });
 
     if (!user)
-        return error(401, "We have not got any user has got this name")
+        return res.error(401, "We have not got any user has got this name")
+
+    const validPassword = await bcrypt.compare(password, user.password);
+
+    if (!validPassword)
+        return res.error(401, 'Incorrect Password!')
+    req.user = await UserModel.findOne({ name: req.headers.username });
 
-    if (user.password !== password)
-        return error(401, 'Incorrect Password!')
     next();
 });
 
+/* will add for loop */
 app.use("/messages", require("./routes/message"))
 app.use("/users", require("./routes/user"))
 app.use("/threads", require("./routes/threads"))
-*/
-app.all("*", (req, res) => res.status(400).json(new ApiResponse(400, { error: "Bad request" })));
+
+app.all("*", (req, res) => res.error(400, "Bad request"));
 
 module.exports = app;
\ No newline at end of file
diff --git a/routes/api/routes/message.js b/routes/api/routes/message.js
index 007e0d0..7608850 100644
--- a/routes/api/routes/message.js
+++ b/routes/api/routes/message.js
@@ -1,5 +1,5 @@
-const { User, Message, Thread } = require("../../../classes");
-const ApiResponse = require("../ApiResponse");
+const { UserModel, MessageModel, ThreadModel } = require("../../../models");
+const rateLimit = require('express-rate-limit')
 
 const { Router } = require("express")
 
@@ -7,34 +7,37 @@ const app = Router();
 
 app.get("/:id", async (req, res) => {
 
-    const error = (status, error) =>
-        res.status(status).json(new ApiResponse(status, { error }));
 
     const { id = null } = req.params;
-    if (!id) return error(400, "Missing id in query")
-    const message = await new Message().getById(id);
+    if (!id) return res.error(400, "Missing id in query")
+    const message = await MessageModel.get(id);
 
-    if (!message || message.deleted) return error(404, "We have not got any message declared as this id.");
+    if (!message || message.deleted) return res.error(404, "We have not got any message declared as this id.");
 
-    res.status(200).json(new ApiResponse(200, message));
+    res.complate(message);
 
 })
 
-app.post("/", async (req, res) => {
-    const error = (status, error) =>
-        res.status(status).json(new ApiResponse(status, { error }));
+app.post("/", rateLimit({
+    windowMs: 60_000, max: 1, standardHeaders: true, legacyHeaders: false,
+    handler: (request, response, next, options) =>
+        !request.user.admin ?
+            response.error(options.statusCode, "You are begin ratelimited")
+            : next()
+}), async (req, res) => {
+
     const { threadID = null, content = null } = req.body;
-    const thread = await new Thread().getById(threadID);
+    if (!content) return res.error(400, "Missing message content in request body.");
 
-    if (!content) return error(400, "Missing message content in request body.");
-    if (!thread) return error(404, "We have not got this thread.");
+    const thread = await ThreadModel.get(threadID);
 
+    if (!thread) return res.error(404, "We have not got this thread.");
 
-    const message = await new Message(content, await new User().getByName(req.headers.username), thread.id).takeId()
-    message.save();
-    thread.push(message.id).save();
+    const message = await new MessageModel({ content, author: req.user, threadID: thread.id }).takeId();
+    await message.save();
+    await thread.push(message.id).save();
 
-    res.status(200).json(new ApiResponse(200, message));
+    res.complate(message);
 
 })
 
diff --git a/routes/api/routes/threads.js b/routes/api/routes/threads.js
index efc66da..363e566 100644
--- a/routes/api/routes/threads.js
+++ b/routes/api/routes/threads.js
@@ -1,42 +1,36 @@
-const { Thread, User, Message } = require("../../../classes");
-const ApiResponse = require("../ApiResponse");
+const { UserModel, MessageModel, ThreadModel } = require("../../../models");
 const { Router } = require("express")
 
 const app = Router();
 
 app.get("/:id", async (req, res) => {
 
-    const error = (status, error) =>
-        res.status(status).json(new ApiResponse(status, { error }))
-
-
     const { id = null } = req.params;
-    if (!id) return error(400, "Missing id in query")
+    if (!id) return res.error(400, "Missing id in query")
 
-    const thread = await new Thread().getById(id);
-    if (!thread || thread.deleted) return error(404, "We have not got any thread declared as this id.");
+    const thread = await ThreadModel.get(id);
+    if (thread && (req.user?.admin || !thread.deleted))
+        res.complate( thread);
+    else
+        return res.error(404, "We have not got any thread declared as this id.");
 
-    res.status(200).json(new ApiResponse(200, thread));
 
 });
 
 
 app.post("/", async (req, res) => {
 
-    const error = (status, error) =>
-        res.status(status).json(new ApiResponse(status, { error }));
-
     const { title = null, content = null } = req.body;
 
-    if (!content || !title) return error(400, "Missing content/title in request body.");
+    if (!content || !title) return res.error(400, "Missing content/title in request body.");
 
-    const user = await new User().getByName(req.headers.username)
-    const thread = await new Thread(title, user).takeId()
-    const message = await new Message(content, user, thread.id).takeId()
-    thread.push(message.id).save();
+    const user = req.user;
+    const thread = await new ThreadModel({ title, author: user }).takeId()
+    const message = await new MessageModel({ content, author: user, threadID: thread.id }).takeId()
+    await thread.push(message.id).save();
     await message.save();
 
-    res.status(200).json(new ApiResponse(200, thread));
+    res.complate(thread);
 
 });
 
diff --git a/routes/api/routes/user.js b/routes/api/routes/user.js
index 4669a21..2e28bf8 100644
--- a/routes/api/routes/user.js
+++ b/routes/api/routes/user.js
@@ -1,21 +1,16 @@
-const { User } = require("../../../classes");
-const ApiResponse = require("../ApiResponse");
+const { UserModel, MessageModel, ThreadModel } = require("../../../models");
 const { Router } = require("express")
 
 const app = Router();
 
 app.get("/:id", async (req, res) => {
 
-    const error = (status, error) =>
-        res.status(status).json(new ApiResponse(status, { error }))
-
-
     const { id = null } = req.params;
-    if (!id) return error(400, "Missing id in query")
-    const member = await new User().getById(id);
-    if (!member || member.deleted) return error(404, "We have not got any user declared as this id.");
+    if (!id) return res.error(400, "Missing id in query")
+    const member = await UserModel.get(id);
+    if (!member || member.deleted) return res.error(404, "We have not got any user declared as this id.");
 
-    res.status(200).json(new ApiResponse(200, member));
+    res.complate(member);
 
 });
 
diff --git a/routes/message.js b/routes/message.js
index 9143156..4ebe937 100644
--- a/routes/message.js
+++ b/routes/message.js
@@ -17,7 +17,11 @@ app.get("/:id", async (req, res) => {
 app.use(require("../middlewares/login"));
 
 app.post("/", rateLimit({
-    windowMs: 60_000, max: 1, standardHeaders: true, legacyHeaders: false
+    windowMs: 60_000, max: 1, standardHeaders: true, legacyHeaders: false,
+    handler: (request, response, next, options) =>
+        !request.user.admin ?
+            error(response, options.statusCode, "You are begin ratelimited")
+            : next()
 }), async (req, res) => {
 
     const thread = await ThreadModel.get(req.body.threadID);
diff --git a/routes/threads.js b/routes/threads.js
index 694795f..41785fe 100644
--- a/routes/threads.js
+++ b/routes/threads.js
@@ -28,9 +28,9 @@ app.get("/:id", async (req, res) => {
     const { id } = req.params;
 
     const thread = await ThreadModel.get(id);
+    const user = req.user;
 
-    if (thread && !thread.deleted) {
-        const user = req.user;
+    if (thread && (user?.admin || !thread.deleted)) {
 
         const messages = await Promise.all(thread.messages.map(async id => {
             const message = await MessageModel.get(id)
@@ -49,7 +49,11 @@ app.use(require("../middlewares/login"));
 
 
 app.post("/", rateLimit({
-    windowMs: 10 * 60_000, max: 1, standardHeaders: true, legacyHeaders: false
+    windowMs: 10 * 60_000, max: 1, standardHeaders: true, legacyHeaders: false,
+    handler: (request, response, next, options) =>
+        !request.user.admin ?
+            error(response, options.statusCode, "You are begin ratelimited")
+            : next()
 }), async (req, res) => {
 
     const { title = null, content = null } = req.body;