mirror of
https://github.com/Akif9748/akf-forum.git
synced 2024-12-22 23:59:08 +03:00
Caching for users, and rename is fixed
This commit is contained in:
parent
256b70c611
commit
b0a7ac7605
15 changed files with 157 additions and 169 deletions
16
APIDOCS.md
16
APIDOCS.md
|
@ -18,28 +18,28 @@ But in front end, the API will works with session.
|
|||
### Request types:
|
||||
- GET `/api/bans/` fetch all bans.
|
||||
- GET `/api/bans/:id` fetch a ban.
|
||||
- POST `/api/bans/:id?reason=flood` for ban an IP adress.
|
||||
- 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.
|
||||
- POST `/api/users/:id/undelete` for undelete user.
|
||||
- POST `/api/users/:id/admin` for give admin permissions for a user.
|
||||
- PATCH `/api/users/:id/` for edit user.
|
||||
|
||||
- GET `/api/threads/:id` for fetch thread.
|
||||
- GET `/api/threads/:id/messages/` for fetch messages in thread.
|
||||
- POST `/api/threads` for create thread.
|
||||
- DELETE `/api/threads/:id/` for delete thread.
|
||||
- POST `/api/threads/:id/undelete` for undelete thread.
|
||||
- PATCH `/api/threads/:id/` for edit thread.
|
||||
- POST `/api/threads/:id/undelete` for undelete thread.
|
||||
- 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.
|
||||
- POST `/api/messages` for create 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.
|
||||
- PATCH `/api/messages/:id/` for edit message.
|
||||
- POST `/api/messages` for create message.
|
||||
|
||||
### Example request:
|
||||
GET ```/api/messages/0```
|
||||
|
@ -67,7 +67,7 @@ GET ```/api/messages/0```
|
|||
"__v": 0,
|
||||
"react": {
|
||||
"like": [0],
|
||||
"dislike":[]
|
||||
"dislike": []
|
||||
},
|
||||
"authorID": "0"
|
||||
}
|
||||
|
|
69
README.md
69
README.md
|
@ -29,74 +29,41 @@ Akf-forum has got an API for AJAX, other clients etc. And, you can learn about A
|
|||
|
||||
## Roadmap
|
||||
### TO-DO:
|
||||
- If thread deleted, not show its messages in API.
|
||||
| To do | Is done? | Priority |
|
||||
| ----- | -------- | -------- |
|
||||
| Profile Message | 🔴 | LOW |
|
||||
| from form to AJAX | 🟢 | HIGH |
|
||||
| auto-scroll | 🟡 | LOW |
|
||||
| Page support, support message limit correct | 🟢 | MEDIUM |
|
||||
| Multi-theme support, black theme | 🟡 | LOW |
|
||||
| Search | 🔴 | MEDIUM |
|
||||
| Footer | 🔴 | LOW |
|
||||
- If thread deleted, not show its messages in API. ?
|
||||
- Profile photos will store in database
|
||||
- replacer function global
|
||||
- author name of thread
|
||||
- page for threads - users []
|
||||
- API, ?fast=
|
||||
- page for threads - users
|
||||
- extra ratelimits
|
||||
- better edits
|
||||
- IP BAN CLI IN ADMIN PANEL
|
||||
|
||||
### Frontend
|
||||
#### User
|
||||
| To do | Is done? | Priority |
|
||||
| ----- | -------- | -------- |
|
||||
| Login via redirect query | 🟢 | HIGH |
|
||||
| Register | 🟢 | HIGH |
|
||||
| Logout | 🟢 | HIGH |
|
||||
| Admin | 🟢 | HIGH |
|
||||
| Message count | 🟢 | MEDIUM |
|
||||
| Delete user | 🟢 | HIGH |
|
||||
| Undelete | 🟢 | MEDIUM |
|
||||
| About me | 🟢 | LOW |
|
||||
| Edit user | 🟢 | HIGH |
|
||||
| IP ban | 🟢 | MEDIUM |
|
||||
| Profile Message | 🔴 | MEDIUM |
|
||||
|
||||
#### Messages
|
||||
| To do | Is done? | Priority |
|
||||
| ----- | -------- | -------- |
|
||||
| Ratelimit | 🟢 | HIGH |
|
||||
| Send | 🟢 | HIGH |
|
||||
| Delete | 🟢 | HIGH |
|
||||
| Regex for scripts | 🟢 | HIGH |
|
||||
| Undelete | 🟢 | MEDIUM |
|
||||
| React | 🟢 | MEDIUM |
|
||||
| Edit | 🟢 | MEDIUM |
|
||||
|
||||
#### Threads
|
||||
| To do | Is done? | Priority |
|
||||
| ----- | -------- | -------- |
|
||||
| Ratelimit | 🟢 | HIGH |
|
||||
| Create | 🟢 | HIGH |
|
||||
| Delete | 🟢 | HIGH |
|
||||
| Undelete | 🟢 | MEDIUM |
|
||||
| Edit | 🟢 | MEDIUM |
|
||||
- IP BAN fix
|
||||
- APIDOCS query
|
||||
- app.param for users in API
|
||||
- message counts for API
|
||||
- ZATEN SİLİNDİ BU KİŞİ & MESAJ
|
||||
|
||||
### API
|
||||
| To do | Is done?
|
||||
| ----- | --------
|
||||
| RATELIMITS | 🟢
|
||||
| Get message**s** | 🟢
|
||||
| Get a lots of message & thread & user | 🔴
|
||||
| Create message & thread & user | 🟢
|
||||
| Get message & thread & user | 🟢
|
||||
| Delete message & thread & user | 🟢
|
||||
| Undelete message & thread & user | 🟢
|
||||
| Edit message & thread & user | 🟢
|
||||
|
||||
### Other
|
||||
| To do | Is done? | Priority |
|
||||
| ----- | -------- | -------- |
|
||||
| from form to AJAX | 🟢 | HIGH |
|
||||
| auto-scroll | 🟢 | LOW |
|
||||
| Page support, support message limit correct | 🟢 | MEDIUM |
|
||||
| Multi-theme support, black theme | 🟡 | LOW |
|
||||
| Search | 🔴 | MEDIUM |
|
||||
| Footer | 🔴 | LOW |
|
||||
|
||||
## Major Version History
|
||||
- V4: Caching
|
||||
- V3: New Theme
|
||||
- V2: Backend fix, mongoose is fixed. Really big fix.
|
||||
- V1: Mongoose added.
|
||||
|
|
9
index.js
9
index.js
|
@ -1,18 +1,19 @@
|
|||
const { def_theme } = require("./config.json"),
|
||||
const { UserModel, BanModel } = require("./models"),
|
||||
{ def_theme } = require("./config.json"),
|
||||
ipBlock = require('express-ip-block'),
|
||||
session = require('express-session'),
|
||||
{ UserModel, BanModel } = require("./models"),
|
||||
bodyParser = require('body-parser'),
|
||||
port = process.env.PORT || 3000,
|
||||
mongoose = require("mongoose"),
|
||||
express = require('express'),
|
||||
fs = require("fs"),
|
||||
app = express();
|
||||
|
||||
app.ips = [];
|
||||
|
||||
require("dotenv").config();
|
||||
mongoose.connect(process.env.MONGO_DB_URL,
|
||||
async () => console.log("Connected to mongoDB with", app.ips = await BanModel.find({}).select("ip"), "banned IPs"));
|
||||
async () => console.log("Database is connected with", (app.ips = await BanModel.find({})).length, "banned IPs"));
|
||||
|
||||
app.set("view engine", "ejs");
|
||||
|
||||
|
@ -20,7 +21,7 @@ app.use(session({ secret: 'secret', resave: true, saveUninitialized: true }),
|
|||
bodyParser.urlencoded({ extended: true }),
|
||||
express.static("public"), express.json(), ipBlock(app.ips),
|
||||
async (req, res, next) => {
|
||||
req.user = await UserModel.get(req.session.userid);
|
||||
req.user = await UserModel.get(req.session.userID);
|
||||
res.reply = (page, options = {}, status = 200) => res.status(status)
|
||||
.render(page, { user: req.user, theme: req.user?.theme || def_theme, ...options });
|
||||
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
const mongoose = require("mongoose")
|
||||
const UserModel = require("./User");
|
||||
|
||||
const cache = require("./cache")
|
||||
const schema = new mongoose.Schema({
|
||||
id: { type: String, unique: true },
|
||||
|
||||
author: Object,
|
||||
threadID: String,
|
||||
author: UserModel.schema, // user-model
|
||||
|
||||
authorID: String,
|
||||
content: String,
|
||||
time: { type: Date, default: Date.now },
|
||||
deleted: { type: Boolean, default: false },
|
||||
|
@ -17,7 +15,7 @@ const schema = new mongoose.Schema({
|
|||
}
|
||||
})
|
||||
|
||||
schema.virtual('authorID').get(function () { return this.author?.id; });
|
||||
schema.methods.get_author = cache.getAuthor
|
||||
|
||||
schema.methods.takeId = async function () {
|
||||
this.id = String(await model.count() || 0);
|
||||
|
@ -30,7 +28,9 @@ schema.methods.getLink = function (id = this.id) {
|
|||
|
||||
const model = mongoose.model('message', schema);
|
||||
|
||||
model.get = id => model.findOne({ id });
|
||||
|
||||
module.exports = model;
|
||||
model.get = async id => {
|
||||
const message = await model.findOne({ id })
|
||||
return await message.get_author();
|
||||
};
|
||||
|
||||
module.exports = model;
|
|
@ -1,10 +1,11 @@
|
|||
const mongoose = require("mongoose");
|
||||
const UserModel = require("./User");
|
||||
const cache = require("./cache")
|
||||
const MessageModel = require("./Message");
|
||||
const schema = new mongoose.Schema({
|
||||
id: { type: String, unique: true },
|
||||
|
||||
author: UserModel.schema,
|
||||
authorID: String,
|
||||
author: Object,
|
||||
|
||||
title: String,
|
||||
time: { type: Date, default: Date.now },
|
||||
|
@ -16,18 +17,20 @@ const schema = new mongoose.Schema({
|
|||
|
||||
});
|
||||
|
||||
schema.virtual('authorID').get(function () { return this.author?.id; });
|
||||
|
||||
schema.methods.get_author = cache.getAuthor;
|
||||
|
||||
schema.methods.messageCount = async function (admin = false) {
|
||||
const query = { threadID: this.id };
|
||||
if (!admin) query.deleted = false;
|
||||
return await MessageModel.count(query) || 0;
|
||||
};
|
||||
|
||||
schema.methods.push = function (messageID) {
|
||||
this.messages.push(messageID);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
schema.methods.takeId = async function () {
|
||||
this.id = await model.count() || 0;
|
||||
return this;
|
||||
|
@ -39,6 +42,9 @@ schema.methods.getLink = function (id = this.id) {
|
|||
|
||||
const model = mongoose.model('thread', schema);
|
||||
|
||||
model.get = id => model.findOne({ id });
|
||||
model.get = async id => {
|
||||
const thread = await model.findOne({ id })
|
||||
return await thread.get_author();
|
||||
};
|
||||
|
||||
module.exports = model;
|
|
@ -14,7 +14,6 @@ const schema = new mongoose.Schema({
|
|||
|
||||
});
|
||||
|
||||
|
||||
schema.methods.takeId = async function () {
|
||||
this.id = String(await model.count() || 0);
|
||||
return this;
|
||||
|
|
14
models/cache.js
Normal file
14
models/cache.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
const UserModel = require("./User");
|
||||
const UserCache = [];
|
||||
|
||||
module.exports.getAuthor = async function () {
|
||||
console.log("User Cache Length:", UserCache.length);
|
||||
const id = this.authorID || this.author?.id;
|
||||
let user = UserCache.find(user => user?.id == id)
|
||||
if (!user) {
|
||||
user = await UserModel.findOne({ id })
|
||||
UserCache.push(user)
|
||||
}
|
||||
this.author = user;
|
||||
return this;
|
||||
}
|
|
@ -9,8 +9,7 @@ app.get("/", async (req, res) => {
|
|||
mem = process.memoryUsage().heapUsed / Math.pow(2, 20),
|
||||
users = await UserModel.count({deleted:false}),
|
||||
threads = await ThreadModel.count({deleted:false}),
|
||||
messages = await MessageModel.count({deleted:false}),
|
||||
user = req.user;
|
||||
messages = await MessageModel.count({deleted:false});
|
||||
|
||||
res.reply("index", { mem, users, threads, messages })
|
||||
|
||||
|
|
|
@ -5,43 +5,47 @@ const { Router } = require("express")
|
|||
|
||||
const app = Router();
|
||||
|
||||
app.param("id", async (req, res, next, id) => {
|
||||
req.message = await ThreadModel.get(id);
|
||||
|
||||
if (!req.message) return res.error(404, `We don't have any message with id ${id}.`);
|
||||
|
||||
if(req.message.deleted && !req.user?.admin)
|
||||
return res.error(404, `You do not have permissions to view this message with id ${id}.`)
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
|
||||
app.get("/:id", async (req, res) => {
|
||||
|
||||
const message = await MessageModel.get(req.params.id);
|
||||
|
||||
if (!message || (message.deleted && req.user && !req.user.admin)) return res.error(404, `We don't have any message with id ${req.params.id}.`);
|
||||
|
||||
res.complate(message.toObject({ virtuals: true }));
|
||||
|
||||
res.complate(message);
|
||||
|
||||
})
|
||||
app.patch("/:id/", async (req, res) => {
|
||||
|
||||
|
||||
const message = await MessageModel.get(req.params.id);
|
||||
const { message, user } = req;
|
||||
|
||||
if (!message || (message.deleted && req.user && !req.user.admin)) return res.error(404, `We don't have any message with id ${req.params.id}.`);
|
||||
|
||||
if (req.user.id !== message.authorID && !req.user.admin) return res.error(403, "You have not got permission for this.");
|
||||
if (user.id !== message.authorID && !user.admin) return res.error(403, "You have not got permission for this.");
|
||||
const { content = null } = req.body;
|
||||
if (!content) return res.error(400, "Missing message content in request body.");
|
||||
message.content = content;
|
||||
message.edited=true;
|
||||
message.edited = true;
|
||||
|
||||
await message.save();
|
||||
|
||||
res.complate(message.toObject({ virtuals: true }));
|
||||
res.complate(message);
|
||||
|
||||
})
|
||||
|
||||
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()
|
||||
!request.user.admin ? response.error(options.statusCode, "You are begin ratelimited") : next()
|
||||
}), async (req, res) => {
|
||||
|
||||
const { threadID = null, content = null } = req.body;
|
||||
const { threadID, content } = req.body;
|
||||
if (!content) return res.error(400, "Missing message content in request body.");
|
||||
|
||||
const thread = await ThreadModel.get(threadID);
|
||||
|
@ -52,13 +56,13 @@ app.post("/", rateLimit({
|
|||
await message.save();
|
||||
await thread.push(message.id).save();
|
||||
|
||||
res.complate(message.toObject({ virtuals: true }));
|
||||
res.complate(message);
|
||||
|
||||
})
|
||||
app.post("/:id/react/:type", async (req, res) => {
|
||||
|
||||
|
||||
const message = await MessageModel.get(req.params.id);
|
||||
if (!message) return error(res, 404, `We don't have any message with id ${req.params.id}.`);
|
||||
const { message } = req;
|
||||
|
||||
if (req.params.type == "like") {
|
||||
if (message.react.like.includes(req.user.id))
|
||||
|
@ -78,43 +82,41 @@ app.post("/:id/react/:type", async (req, res) => {
|
|||
message.react.like.pull(req.user.id);
|
||||
}
|
||||
|
||||
} else {
|
||||
} else
|
||||
return res.error(400, `We don't have any react type with name ${req.params.type}.`);
|
||||
}
|
||||
|
||||
await message.save();
|
||||
|
||||
res.complate(message.toObject({ virtuals: true }));
|
||||
res.complate(message);
|
||||
|
||||
});
|
||||
|
||||
app.delete("/:id/", async (req, res) => {
|
||||
const message = await MessageModel.get(req.params.id);
|
||||
if (!message || (message.deleted && req.user && !req.user.admin))
|
||||
return res.error(404, `We don't have any message with id ${req.params.id}.`);
|
||||
const user = req.user;
|
||||
|
||||
|
||||
const { message, user } = req;
|
||||
|
||||
if (user.id != message.authorID && !user.admin)
|
||||
return res.error(403, "You have not got permission for this.");
|
||||
|
||||
message.deleted = true;
|
||||
await message.save();
|
||||
|
||||
res.complate(message.toObject({ virtuals: true }));
|
||||
res.complate(message);
|
||||
|
||||
})
|
||||
|
||||
app.post("/:id/undelete", async (req, res) => {
|
||||
if (!req.user.admin) return res.error(403, "You have not got permission for this.");
|
||||
|
||||
|
||||
const message = await MessageModel.get(req.params.id);
|
||||
|
||||
if (!message) return res.error(404, `We don't have any message with id ${req.params.id}.`);
|
||||
const { message } = req;
|
||||
|
||||
if (!message.deleted) return res.error(404, "This message is not deleted, first, delete it.");
|
||||
|
||||
message.deleted = false;
|
||||
await message.save();
|
||||
|
||||
res.complate(message.toObject({ virtuals: true }));
|
||||
res.complate(message);
|
||||
|
||||
})
|
||||
|
||||
|
|
|
@ -2,22 +2,20 @@ const { MessageModel, ThreadModel } = require("../../../models");
|
|||
const { Router } = require("express")
|
||||
|
||||
const app = Router();
|
||||
app.param("id", async (req, res, next, id) => {
|
||||
req.thread = await ThreadModel.get(id);
|
||||
|
||||
app.get("/:id", async (req, res) => {
|
||||
|
||||
const { id } = req.params;
|
||||
|
||||
const thread = await ThreadModel.get(id);
|
||||
if (thread && (req.user?.admin || !thread.deleted))
|
||||
res.complate(thread.toObject({ virtuals: true }));
|
||||
else
|
||||
return res.error(404, `We don't have any thread with id ${id}.`);
|
||||
if (!req.thread) return res.error(404, `We don't have any thread with id ${id}.`);
|
||||
|
||||
if (req.thread.deleted && !req.user?.admin)
|
||||
return res.error(404, `You do not have permissions to view this thread with id ${id}.`)
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
app.get("/:id/messages/", async (req, res) => {
|
||||
app.get("/:id", async (req, res) => res.complate(req.thread));
|
||||
|
||||
app.get("/:id/messages/", async (req, res) => {
|
||||
|
||||
const { id } = req.params;
|
||||
const limit = Number(req.query.limit);
|
||||
|
@ -34,68 +32,62 @@ app.get("/:id/messages/", async (req, res) => {
|
|||
|
||||
if (!messages.length) return res.error(404, "We don't have any messages in this with your query thread.");
|
||||
|
||||
res.complate(messages.map(x => x.toObject({ virtuals: true })));
|
||||
res.complate(messages);
|
||||
|
||||
})
|
||||
|
||||
app.post("/", async (req, res) => {
|
||||
|
||||
const { title = null, content = null } = req.body;
|
||||
const { title, content } = req.body;
|
||||
|
||||
if (!content || !title) return res.error(400, "Missing content/title in request body.");
|
||||
|
||||
const user = req.user;
|
||||
const { user } = req;
|
||||
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.complate(thread.toObject({ virtuals: true }));
|
||||
res.complate(thread);
|
||||
|
||||
});
|
||||
app.patch("/:id/", async (req, res) => {
|
||||
|
||||
const thread = await ThreadModel.get(req.params.id);
|
||||
const { user, thread } = req;
|
||||
|
||||
if (!thread || (thread.deleted && req.user && !req.user.admin)) return res.error(404, `We don't have any message with id ${req.params.id}.`);
|
||||
|
||||
if (req.user.id !== thread.authorID && !req.user.admin) return res.error(403, "You have not got permission for this.");
|
||||
const { title = null } = req.body;
|
||||
if (user.id !== thread.authorID && !user.admin) return res.error(403, "You have not got permission for this.");
|
||||
const { title } = req.body;
|
||||
if (!title) return res.error(400, "Missing thread title in request body.");
|
||||
thread.title = title;
|
||||
await thread.save();
|
||||
|
||||
res.complate(thread.toObject({ virtuals: true }));
|
||||
res.complate(thread);
|
||||
|
||||
})
|
||||
app.delete("/:id/", async (req, res) => {
|
||||
const thread = await ThreadModel.get(req.params.id);
|
||||
if (!thread || thread.deleted) return res.error(404, `We don't have any thread with id ${req.params.id}.`);
|
||||
const user = req.user;
|
||||
|
||||
const { user, thread } = req;
|
||||
if (user.id != thread.authorID && !user.admin)
|
||||
return res.error(403, "You have not got permission for this.");
|
||||
|
||||
thread.deleted = true;
|
||||
await thread.save();
|
||||
|
||||
res.complate(thread.toObject({ virtuals: true }));
|
||||
res.complate(thread);
|
||||
|
||||
})
|
||||
app.post("/:id/undelete", async (req, res) => {
|
||||
if (!req.user.admin) return res.error(403, "You have not got permission for this.");
|
||||
|
||||
const thread = await ThreadModel.get(req.params.id);
|
||||
const { thread } = req;
|
||||
|
||||
if (!thread ) return res.error(404, `We don't have any thread with id ${req.params.id}.`);
|
||||
|
||||
if (!thread.deleted) return res.error(404, "This thread is not deleted, first, delete it.");
|
||||
|
||||
thread.deleted = false;
|
||||
thread.edited=true;
|
||||
thread.edited = true;
|
||||
|
||||
await thread.save();
|
||||
|
||||
res.complate(thread.toObject({ virtuals: true }));
|
||||
res.complate(thread);
|
||||
|
||||
})
|
||||
module.exports = app;
|
|
@ -1,28 +1,36 @@
|
|||
const { UserModel } = require("../../../models");
|
||||
const { UserModel, SecretModel } = require("../../../models");
|
||||
const { Router } = require("express")
|
||||
|
||||
const app = Router();
|
||||
|
||||
app.param("id", async (req, res, next, id) => {
|
||||
req.member = await UserModel.get(id);
|
||||
|
||||
if (!req.member) return res.error(404, `We don't have any user with id ${id}.`);
|
||||
|
||||
if (req.member.deleted && !req.user?.admin)
|
||||
return res.error(404, `You do not have permissions to view this user with id ${id}.`);
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
app.get("/:id", async (req, res) => {
|
||||
|
||||
const { id = null } = req.params;
|
||||
|
||||
const member = await UserModel.get(id);
|
||||
if (!member || (member.deleted && !req.user.admin)) return res.error(404, `We don't have any user with id ${id}.`);
|
||||
|
||||
if (req.member.not()) return;
|
||||
res.complate(member);
|
||||
|
||||
});
|
||||
|
||||
app.delete("/:id/", async (req, res) => {
|
||||
const user = req.user;
|
||||
const { user, member } = req;
|
||||
if (req.member.not()) return;
|
||||
|
||||
if (!user.admin)
|
||||
return res.error(403, "You have not got permission for this.");
|
||||
|
||||
const { id = null } = req.params;
|
||||
const member = await UserModel.get(id);
|
||||
|
||||
if (!member || member.deleted) return res.error(404, `We don't have any user with id ${id}.`);
|
||||
if (member.deleted) return res.error(404, `This user is with id ${id} already deleted.`);
|
||||
|
||||
member.deleted = true;
|
||||
await member.save();
|
||||
|
@ -32,7 +40,7 @@ app.delete("/:id/", async (req, res) => {
|
|||
app.post("/:id/undelete/", async (req, res) => {
|
||||
if (!req.user.admin) return res.error(403, "You have not got permission for this.");
|
||||
|
||||
const member = await UserModel.get(req.params.id);
|
||||
const { user, member } = req;
|
||||
|
||||
if (!member) return res.error(404, `We don't have any user with id ${req.params.id}.`);
|
||||
|
||||
|
@ -48,16 +56,17 @@ app.post("/:id/undelete/", async (req, res) => {
|
|||
|
||||
app.patch("/:id/", async (req, res) => {
|
||||
|
||||
const member = await UserModel.get(req.params.id);
|
||||
|
||||
if (!member || (member.deleted && !req.user.admin)) return res.error(404, `We don't have any message with id ${req.params.id}.`);
|
||||
const { user, member } = req;
|
||||
|
||||
if (req.user.id !== member.id && !req.user.admin) return res.error(403, "You have not got permission for this.");
|
||||
const { avatar, name, about } = req.body;
|
||||
if (!avatar && !name) return res.error(400, "Missing member informations in request body.");
|
||||
if (avatar && /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/g.test(avatar))
|
||||
member.avatar = avatar;
|
||||
if (name) member.name = name;
|
||||
if (name) {
|
||||
await SecretModel.findOneAndUpdate({ name: member.name }, { name });
|
||||
member.name = name;
|
||||
}
|
||||
|
||||
if (about) member.about = about;
|
||||
member.edited = true;
|
||||
|
|
|
@ -6,7 +6,7 @@ const bcrypt = require("bcrypt");
|
|||
app.get("/", (req, res) => res.reply("login", { redirect: req.query.redirect, user: null }));
|
||||
|
||||
app.post("/", async (req, res) => {
|
||||
req.session.userid = null;
|
||||
req.session.userID = null;
|
||||
|
||||
const { username = null, password = null } = req.body;
|
||||
|
||||
|
@ -18,7 +18,7 @@ app.post("/", async (req, res) => {
|
|||
const member = await UserModel.findOne({ name: username });
|
||||
if (!member || member.deleted) return res.error(403, 'Incorrect Username and/or Password!')
|
||||
|
||||
req.session.userid = user.id;
|
||||
req.session.userID = user.id;
|
||||
|
||||
res.redirect(req.query.redirect || '/');
|
||||
} else
|
||||
|
|
|
@ -7,7 +7,7 @@ const app = Router();
|
|||
app.get("/:id", async (req, res) => {
|
||||
const message = await MessageModel.get(req.params.id);
|
||||
|
||||
if (!message || (message.deleted && req.user && !req.user.admin)) return res.error( 404,
|
||||
if (!message || (message.deleted && !req.user?.admin)) return res.error( 404,
|
||||
`We don't have any message with id ${req.params.id}.`);
|
||||
res.redirect(`/threads/${message.threadID}?scroll=${message.id}`);
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ app.post("/", rateLimit({
|
|||
windowMs: 24 * 60 * 60_000, max: 10, standardHeaders: true, legacyHeaders: false,
|
||||
handler: (_r, response, _n, options) => response.error(options.statusCode, "You are begin ratelimited")
|
||||
}), async (req, res) => {
|
||||
req.session.userid = null;
|
||||
req.session.userID = null;
|
||||
|
||||
|
||||
let { username = null, password: body_pass = null, avatar, about } = req.body;
|
||||
|
@ -33,7 +33,7 @@ app.post("/", rateLimit({
|
|||
const salt = await bcrypt.genSalt(10);
|
||||
const password = await bcrypt.hash(body_pass, salt);
|
||||
await SecretModel.create({ username, password, id: user2.id })
|
||||
req.session.userid = user2.id;
|
||||
req.session.userID = user2.id;
|
||||
|
||||
res.redirect('/');
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@ const { ThreadModel, MessageModel } = require("../models")
|
|||
|
||||
app.get("/", async (req, res) => {
|
||||
|
||||
const threads = await ThreadModel.find(req.user?.admin ? {} : { deleted: false })//.limit(10);
|
||||
|
||||
let threads = await ThreadModel.find(req.user?.admin ? {} : { deleted: false })//.limit(10);
|
||||
threads = await Promise.all(threads.map(thread => thread.get_author()));
|
||||
return res.reply("threads", { threads });
|
||||
});
|
||||
|
||||
|
@ -18,7 +18,7 @@ app.get("/:id/", async (req, res) => {
|
|||
|
||||
const { user, params: { id } } = req
|
||||
|
||||
let page = Number(req.query.page || 0);
|
||||
const page = Number(req.query.page || 0);
|
||||
|
||||
const thread = await ThreadModel.get(id)
|
||||
thread.count = await thread.messageCount(user?.admin);
|
||||
|
@ -28,15 +28,14 @@ app.get("/:id/", async (req, res) => {
|
|||
const query = { threadID: id };
|
||||
if (!user || !user.admin) query.deleted = false;
|
||||
|
||||
const messages = await MessageModel.find(query).sort({ time: 1 }).limit(10).skip(page * 10)
|
||||
.then(messages => messages.map(message => {
|
||||
const messages = await Promise.all(await MessageModel.find(query).sort({ time: 1 }).limit(10).skip(page * 10)
|
||||
.then(messages => messages.map(async message => {
|
||||
message.content = message.content.replaceAll("&", "&")
|
||||
.replaceAll("<", "<").replaceAll(">", ">")
|
||||
.replaceAll("\"", """).replaceAll("'", "'")
|
||||
.replaceAll("\n", "<br>");
|
||||
return message.toObject({ virtuals: true });
|
||||
}))
|
||||
|
||||
return await message.get_author();
|
||||
})));
|
||||
res.reply("thread", { page, thread, messages, scroll: req.query.scroll || thread.messages[0].id });
|
||||
|
||||
thread.save();
|
||||
|
|
Loading…
Reference in a new issue