This commit is contained in:
Akif9748 2022-08-11 00:38:44 +03:00
parent 0d158c4fef
commit aa33c97db3
11 changed files with 108 additions and 68 deletions

View file

@ -20,15 +20,15 @@ And, you can learn about API in `util/APIDOCS.md`.
* [Camroku](https://github.com/Camroku) - Made stylesheets * [Camroku](https://github.com/Camroku) - Made stylesheets
## To do (Backend, bug fixes) ## To do (Backend, bug fixes)
- `/errors/error` will ~~change~~ deprecate, it will be in res.error . And we will use "alert" for errors with fetch api. - `/errors/error` will ~~change~~ deprecate, it will be in res.error . And we will use "alert" for errors with fetch api. this added for messages and reactions...
- message.js/12, so, admin perms,(req.user?.admin || !thread.deleted), and api in message. - message.js/12, so, admin perms,(req.user?.admin || !thread.deleted), and api in message.
- the forum will only use api path... - the forum will only use api path... this added for messages and reactions...
## Roadmap ## Roadmap
### User ### User
| To do | Is done? | Priority | | To do | Is done? | Priority |
| ----- | -------- | -------- | | ----- | -------- | -------- |
| Login | 🟢 | HIGH | | Login via redirect query | 🟢 | HIGH |
| Register | 🟢 | HIGH | | Register | 🟢 | HIGH |
| Logout | 🟢 | HIGH | | Logout | 🟢 | HIGH |
| Admin | 🟢 | HIGH | | Admin | 🟢 | HIGH |

View file

@ -22,4 +22,4 @@ for (const file of fs.readdirSync("./routes"))
app.all("*", (req, res) => error(res, 404, "We have not got this page.")); app.all("*", (req, res) => error(res, 404, "We have not got this page."));
app.listen(port, () => console.log("Akf-forum on port:", port)); app.listen(port, () => console.log("akf-forum on port:", port));

44
public/js/send.js Normal file
View file

@ -0,0 +1,44 @@
document.getElementById("send").addEventListener("submit", async e => {
e.preventDefault();
const form = e.target;
const data = new FormData(form);
fetch("/api/messages", {
method: 'POST',
body: JSON.stringify({ threadID: data.get("threadID"), content: data.get("content") }),
headers: {
"Content-Type": "application/json"
}
}).then(res => res.json())
.then(res => {
if (res.result.error) return alert(res.result.error);
form.reset();
const message = res.result;
document.getElementById("messages").innerHTML += `<br>
<div id="message-${message.id}" style="border: 2px solid #444444; padding: 10px;">
<h3 style="float:right;">${new Date(message.time).toLocaleString()}</h3>
<h2>
<img class="yuvarlak" src=${message.author.avatar} alt=${message.author.name}>
<a href="/users/${message.author.id}"> ${message.author.name}</a>:
</h2>
<h2>${message.content}</h2><br>
<form style="display:inline;" action="/message/${message.id}/delete/" method="post">
</a><button type="submit">DELETE</button>
</form>
<div style="float: right;">
<h3 id="count${message.id}" style="display:inline;">0</h3>
<button style="display:inline;" id="like" value="${message.id}">+🔼</button>
<button style="display:inline;" id="dislike" value="${message.id}" >-🔽</button>
</div>
</div>`;
}).catch(err => {
alert(err);
});
});

View file

@ -38,6 +38,7 @@ app.use(async (req, res, next) => {
res.complate = result => res.status(200).json({ status: 200, result }); res.complate = result => res.status(200).json({ status: 200, result });
if (req.user) return next();
const { username = null, password = null } = req.headers; const { username = null, password = null } = req.headers;
if (!username || !password) if (!username || !password)

View file

@ -40,5 +40,23 @@ app.post("/", rateLimit({
res.complate(message); res.complate(message);
}) })
app.post("/:id/react/:type", async (req, res) => {
const message = await MessageModel.get(req.params.id);
if (message) {
if (req.user.id in message.react)
delete message.react[req.session.userid];
else
message.react[req.session.userid] = req.params.type === "like";
message.markModified("react");
await message.save();
const arr = Object.values(message.react)
res.complate(arr.filter(Boolean).length - arr.filter(x => !x).length)
} else error(res, 404, "We have not got this Message for reacting.");
});
module.exports = app; module.exports = app;

View file

@ -4,7 +4,7 @@ const error = require("../errors/error");
const app = Router(); const app = Router();
const bcrypt = require("bcrypt"); const bcrypt = require("bcrypt");
app.get("/", (req, res) => res.render("login")); app.get("/", (req, res) => res.render("login",{redirect: req.query.redirect}));
app.post("/", async (req, res) => { app.post("/", async (req, res) => {
req.session.userid = null; req.session.userid = null;
@ -23,7 +23,7 @@ app.post("/", async (req, res) => {
req.session.userid = user.id; req.session.userid = user.id;
res.redirect('/'); res.redirect( req.query.redirect || '/');
} else } else
error(res, 403, 'Incorrect Username and/or Password!') error(res, 403, 'Incorrect Username and/or Password!')

View file

@ -1,6 +1,5 @@
const { ThreadModel, MessageModel } = require("../models"); const { MessageModel } = require("../models");
const error = require("../errors/error") const error = require("../errors/error")
const rateLimit = require('express-rate-limit')
const { Router } = require("express"); const { Router } = require("express");
@ -16,28 +15,6 @@ app.get("/:id", async (req, res) => {
app.use(require("../middlewares/login")); app.use(require("../middlewares/login"));
app.post("/", rateLimit({
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);
if (thread) {
const message = await new MessageModel({ content: req.body.content, author: req.user, threadID: thread.id }).takeId();
await message.save();
await thread.push(message.id).save();
res.redirect('/threads/' + req.body.threadID);
}
else
error(res, 404, "We have not got this thread.");
});
app.post("/:id/delete", async (req, res) => { app.post("/:id/delete", async (req, res) => {
const message = await MessageModel.get(req.params.id); const message = await MessageModel.get(req.params.id);
if (!message || message.deleted) return error(res, 404, "We have not got any message declared as this id."); if (!message || message.deleted) return error(res, 404, "We have not got any message declared as this id.");
@ -51,23 +28,6 @@ app.post("/:id/delete", async (req, res) => {
res.status(200).redirect("/threads/" + message.threadID); res.status(200).redirect("/threads/" + message.threadID);
}) })
app.post("/:id/react", async (req, res) => {
const info = req.body;
const message = await MessageModel.get(req.params.id);
if (message) {
if (req.user.id in message.react)
delete message.react[req.session.userid];
else
message.react[req.session.userid] = "like" in info;
await message.save();
res.redirect("/threads/" + message.threadID);
} else error(res, 404, "We have not got this Message for reacting.");
});

View file

@ -34,6 +34,9 @@ app.get("/:id", async (req, res) => {
const messages = await Promise.all(thread.messages.map(async id => { const messages = await Promise.all(thread.messages.map(async id => {
const message = await MessageModel.get(id) const message = await MessageModel.get(id)
const arr = Object.values(message.react)
message.reactCount = arr.filter(Boolean).length - arr.filter(x => !x).length;
return user?.admin || !message?.deleted ? message : null; return user?.admin || !message?.deleted ? message : null;
})); }));

View file

@ -29,8 +29,10 @@
<% } else { %> <% } else { %>
<a style="float: right; background-color: #5F875F;" href="/register">REGISTER</a> <a style="float: right; background-color: #5F875F;" href="/register">REGISTER</a>
<a id="login" style="float: right; background-color:#5F87AF; " href="/login">LOGIN</a>
<a style="float: right; background-color:#5F87AF; " href="/login">LOGIN</a> <script>
document.getElementById("login").href += "?redirect="+window.location.pathname
</script>
<% } %> <% } %>

View file

@ -14,7 +14,7 @@
<h1>Login</h1> <h1>Login</h1>
<hr> <hr>
<form action="/login" method="post"> <form action="/login?redirect=<%= redirect %>" method="post">
<input type="text" name="username" placeholder="Username" id="username" required> <input type="text" name="username" placeholder="Username" id="username" required>
<input type="password" name="password" placeholder="Password" id="password" required> <input type="password" name="password" placeholder="Password" id="password" required>
<input type="submit" value="Login"> <input type="submit" value="Login">

View file

@ -1,7 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<%- include("extra/header", { title : thread.title }) %> <%- include("extra/header", { title: thread.title }) %>
<body> <body>
@ -24,7 +24,8 @@
<% }; %> <% }; %>
<hr> <hr>
<div id="messages">
<% messages.forEach(message=>{ %> <% messages.forEach(message=>{ %>
<% if (message){ %> <% if (message){ %>
@ -50,18 +51,13 @@
<form style="display:inline;" action="/message/<%= message.id %>/delete/" method="post"> <form style="display:inline;" action="/message/<%= message.id %>/delete/" method="post">
</a><button type="submit">DELETE</button> </a><button type="submit">DELETE</button>
</form> </form>
<form style="float: right;" action="/message/<%= message.id %>/react/" method="POST"> <div style="float: right;">
<h3 id="count<%= message.id %>" style="display:inline;"><%= message.reactCount %></h3>
<h3 style="display:inline;"> <button style="display:inline;" id="like" value="<%= message.id %>">+🔼</button>
<%= Object.values(message.react).filter(Boolean).length - Object.values(message.react).filter(x=> <button style="display:inline;" id="dislike" value="<%= message.id %>" >-🔽</button>
!x).length %> </div>
</h3>
<button style="display:inline;" name="like" type="submit">+🔼</button>
<button style="display:inline;" name="dislike" type="submit">-🔽</button>
</form>
<% } %> <% } %>
@ -76,22 +72,38 @@
<% }); %> <% }); %>
<script>
document.addEventListener("click", async e=>{
if (!e.target.id.includes("like"))return;
const res = await fetch("/api/messages/"+e.target.value+"/react/" + e.target.id, { method: 'POST' })
.then(res=>res.json());
document.getElementById("count"+e.target.value).innerHTML = res.result;
});
</script>
</div>
<hr> <hr>
<form action="/message" method="POST"> <form id= "send">
<textarea rows="4" cols="133" name="content"></textarea> <textarea rows="4" cols="133" name="content"></textarea>
<input name="threadID" type="hidden" value="<%= thread.id %>"></input> <input name="threadID" type="hidden" value="<%= thread.id %>"></input>
<br> <br>
<% if (user){ %> <% if (user){ %>
<button type="submit">Send!</button> <button type="submit">Send!</button>
<%} else {%> <%} else {%>
<button disabled>Login for send</button> <button disabled>Login for send</button>
<% }%> <% }%>
</form> </form>
<% if (user){ %>
<script src="/js/send.js"></script>
<% }%>
<%- include("extra/footer") %> <%- include("extra/footer") %>
</body> </body>