From 09ac68ee704589ef7e5e645ac35bada7caa2c79e Mon Sep 17 00:00:00 2001
From: Akif9748 <akif9748@gmail.com>
Date: Fri, 9 Sep 2022 17:13:37 +0300
Subject: [PATCH] Added category to API

---
 APIDOCS.md                      | 39 ++++++++++++++++----------
 README.md                       |  4 +++
 models/Category.js              | 16 +++++++++++
 models/Thread.js                |  5 +++-
 models/index.js                 |  7 +++--
 routes/api/routes/bans.js       |  2 +-
 routes/api/routes/categories.js | 49 +++++++++++++++++++++++++++++++++
 routes/api/routes/messages.js   |  5 +---
 routes/api/routes/threads.js    |  1 -
 routes/api/routes/users.js      |  8 ++----
 10 files changed, 107 insertions(+), 29 deletions(-)
 create mode 100644 models/Category.js
 create mode 100644 routes/api/routes/categories.js

diff --git a/APIDOCS.md b/APIDOCS.md
index 7abba2a..9e122ea 100644
--- a/APIDOCS.md
+++ b/APIDOCS.md
@@ -16,19 +16,31 @@ But in front end, the API will works with session.
 ## How to request?
 
 ### Request types:
-- GET `/api/search/users?q=query` find users.
-- GET `/api/search/threads?q=query&authorID=not_required` find threads.
-- GET `/api/search/messages?q=query&authorID=not_required` find messages.
-
 - GET `/api/bans/` fetch all bans.
 - GET `/api/bans/:id` fetch a ban.
 - DELETE `/api/bans/:id` for unban an IP adress.
 - POST `/api/bans?reason=flood` for ban an IP adress.
 
-- GET `/api/users/:id` for fetch user.
-- DELETE `/api/users/:id/` for delete user.
-- PATCH `/api/users/:id/` for edit user.
-- PUT `/api/users/:id/` for add profile photo to user.
+
+- GET `/api/categories/` fetch all categories.
+- GET `/api/categories/:id` fetch a category
+- PATCH `/api/categories/:id` for update a category.
+- DELETE `/api/categories/:id` for delete a category.
+- POST `/api/categories` for create a category.
+
+
+- GET `/api/messages/:id` for fetch message.
+- DELETE `/api/messages/:id/` for delete message.
+- PATCH `/api/messages/:id/` for edit message.
+- POST `/api/messages/:id/undelete` for undelete message.
+- POST `/api/messages/:id/react/:type` for react to a message.
+- POST `/api/messages` for create message.
+
+
+- GET `/api/search/users?q=query` find users.
+- GET `/api/search/threads?q=query&authorID=not_required` find threads.
+- GET `/api/search/messages?q=query&authorID=not_required` find messages.
+
 
 - GET `/api/threads/:id` for fetch thread.
 - DELETE `/api/threads/:id/` for delete thread.
@@ -37,12 +49,11 @@ But in front end, the API will works with session.
 - GET `/api/threads/:id/messages?skip=0&limit=10` for fetch messages in thread.
 - POST `/api/threads` for create thread.
 
-- GET `/api/messages/:id` for fetch message.
-- DELETE `/api/messages/:id/` for delete message.
-- PATCH `/api/messages/:id/` for edit message.
-- POST `/api/messages/:id/undelete` for undelete message.
-- POST `/api/messages/:id/react/:type` for react to a message.
-- POST `/api/messages` for create message.
+
+- GET `/api/users/:id` for fetch user.
+- DELETE `/api/users/:id/` for delete user.
+- PATCH `/api/users/:id/` for edit user.
+- PUT `/api/users/:id/` for add profile photo to user.
 
 ### Example request:
 GET ```/api/messages/0```
diff --git a/README.md b/README.md
index 93b1ae2..f452051 100644
--- a/README.md
+++ b/README.md
@@ -41,6 +41,10 @@ Akf-forum has got an API for AJAX (fetch), other clients etc. And, you can learn
 | Better Auth | 🔴 | MEDIUM |
 - Fix footer, theme
 - Navbar manuel select
+- Version info to footer
+- upload other photos, model for it
+- black theme is broken
+
 ## Major Version History
 - V4: Caching
 - V3: New Theme
diff --git a/models/Category.js b/models/Category.js
new file mode 100644
index 0000000..c43f7f5
--- /dev/null
+++ b/models/Category.js
@@ -0,0 +1,16 @@
+const mongoose = require("mongoose")
+
+const schema = new mongoose.Schema({
+    name: { type: String, unique: true },
+    desp: String, position: Number,
+    id: { type: String, unique: true },
+    authorID: { type: String }
+
+});
+schema.methods.takeId = async function () {
+    this.id = String(await model.count() || 0);
+    return this;
+}
+const model = mongoose.model('category', schema);
+
+module.exports = model;
\ No newline at end of file
diff --git a/models/Thread.js b/models/Thread.js
index 08a9c43..7126c2c 100644
--- a/models/Thread.js
+++ b/models/Thread.js
@@ -4,6 +4,7 @@ const MessageModel = require("./Message");
 const schema = new mongoose.Schema({
     id: { type: String, unique: true },
 
+    categoryID: String,
     authorID: String,
     author: Object,
 
@@ -19,7 +20,9 @@ const schema = new mongoose.Schema({
 
 
 schema.methods.get_author = cache.getAuthor;
-
+schema.methods.get_category = () => async function () {
+    return await require("./Category").findOne({ id: this.categoryID }) || {id: this.categoryID, name: "Unknown"} ;
+}
 schema.methods.messageCount = async function (admin = false) {
     const query = { threadID: this.id }; 
     if (!admin) query.deleted = false;
diff --git a/models/index.js b/models/index.js
index 13e4237..1dcc225 100644
--- a/models/index.js
+++ b/models/index.js
@@ -1,7 +1,8 @@
-const UserModel = require("./User"),
+const CategoryModel = require("./Category"),
     MessageModel = require("./Message"),
     ThreadModel = require("./Thread"),
     SecretModel = require("./Secret"),
-    BanModel = require("./Ban");
+    UserModel = require("./User"),
+    BanModel = require("./Ban"); 
 
-module.exports = { UserModel, MessageModel, ThreadModel, SecretModel, BanModel };
\ No newline at end of file
+module.exports = { CategoryModel, MessageModel, ThreadModel, SecretModel, UserModel, BanModel };
\ No newline at end of file
diff --git a/routes/api/routes/bans.js b/routes/api/routes/bans.js
index a4d3a1c..f499c19 100644
--- a/routes/api/routes/bans.js
+++ b/routes/api/routes/bans.js
@@ -4,7 +4,7 @@ const { Router } = require("express")
 const app = Router();
 
 app.use((req, res, next) => {
-    if (!req.user || !req.user.admin) return res.error(403, "You have not got permission for this.");
+    if (!req.user.admin) return res.error(403, "You have not got permission for this.");
     next();
 });
 
diff --git a/routes/api/routes/categories.js b/routes/api/routes/categories.js
new file mode 100644
index 0000000..46a9a4d
--- /dev/null
+++ b/routes/api/routes/categories.js
@@ -0,0 +1,49 @@
+const { CategoryModel } = require("../../../models");
+const { Router } = require("express")
+
+const app = Router();
+
+app.use((req, res, next) => {
+    if (!req.user.admin) return res.error(403, "You have not got permission for this.");
+    next();
+});
+
+app.param("id", async (req, res, next, id) => {
+    req.category = await CategoryModel.findOne({ id });
+    if (!req.category) return res.error(404, `We don't have any category with id ${id}.`);
+    next();
+});
+
+app.get("/", async (req, res) => {
+    const categories = await CategoryModel.find({});
+    res.complate(categories);
+});
+
+app.get("/:id", async (req, res) => {
+    const {category} = req;
+    res.complate(category);
+});
+
+app.patch("/:id", async (req, res) => {
+    const {category} = req;
+    if (req.body.name) category.name = req.body.name;
+    if (req.body.desp) category.name = req.body.name;
+    res.complate(await category.save());
+});
+
+app.delete("/:id", async (req, res) => {
+    res.complate(await CategoryModel.deleteOne({ id: req.params.id }));
+});
+
+app.post("/", async (req, res) => {
+    const {name,desp} = req.body;
+    if (!name) return res.error(400, "You have to give a name for the category.");
+
+    if (await CategoryModel.exists({ name })) return res.error(400, "This category is already opened.");
+
+    res.complate(await CategoryModel.create({ name, desp, authorID: req.user.id }).then(c => c.takeId()));
+
+});
+
+
+module.exports = app;
\ No newline at end of file
diff --git a/routes/api/routes/messages.js b/routes/api/routes/messages.js
index 88dda90..ac13ccc 100644
--- a/routes/api/routes/messages.js
+++ b/routes/api/routes/messages.js
@@ -17,11 +17,8 @@ app.param("id", async (req, res, next, id) => {
 });
 
 
-app.get("/:id", async (req, res) => {
+app.get("/:id", async (req, res) => res.complate(req.message));
 
-    res.complate(message);
-
-})
 app.patch("/:id/", async (req, res) => {
 
 
diff --git a/routes/api/routes/threads.js b/routes/api/routes/threads.js
index 397a7ec..e3fed7a 100644
--- a/routes/api/routes/threads.js
+++ b/routes/api/routes/threads.js
@@ -73,7 +73,6 @@ app.delete("/:id/", async (req, res) => {
     if (thread.deleted) return res.error(403, "This thread is already deleted.");
     thread.deleted = true;
     await thread.save();
-    console.log(thread)
 
     await MessageModel.updateMany({ threadID: thread.id }, { deleted: true });
     res.complate(thread);
diff --git a/routes/api/routes/users.js b/routes/api/routes/users.js
index 4342f63..1da4624 100644
--- a/routes/api/routes/users.js
+++ b/routes/api/routes/users.js
@@ -43,9 +43,9 @@ app.post("/:id/undelete/", async (req, res) => {
     if (!member.deleted) return res.error(404, "This user is not deleted, first, delete it.");
 
     member.deleted = false;
-    await member.save();
+    ;
 
-    res.complate(member);
+    res.complate(await member.save());
 
 })
 
@@ -74,9 +74,7 @@ app.patch("/:id/", async (req, res) => {
     if (deleted === false) member.deleted = false;
     member.edited = true;
 
-    await member.save();
-
-    res.complate(member);
+    res.complate(await member.save());
 
 })
 const storage = multer.diskStorage({