mirror of
https://github.com/Akif9748/akf-forum.git
synced 2024-12-22 23:59:08 +03:00
V3
This commit is contained in:
parent
0d158c4fef
commit
aa33c97db3
11 changed files with 108 additions and 68 deletions
|
@ -20,15 +20,15 @@ And, you can learn about API in `util/APIDOCS.md`.
|
|||
* [Camroku](https://github.com/Camroku) - Made stylesheets
|
||||
|
||||
## 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.
|
||||
- the forum will only use api path...
|
||||
- the forum will only use api path... this added for messages and reactions...
|
||||
|
||||
## Roadmap
|
||||
### User
|
||||
| To do | Is done? | Priority |
|
||||
| ----- | -------- | -------- |
|
||||
| Login | 🟢 | HIGH |
|
||||
| Login via redirect query | 🟢 | HIGH |
|
||||
| Register | 🟢 | HIGH |
|
||||
| Logout | 🟢 | HIGH |
|
||||
| Admin | 🟢 | HIGH |
|
||||
|
|
2
index.js
2
index.js
|
@ -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.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
44
public/js/send.js
Normal 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);
|
||||
});
|
||||
});
|
|
@ -38,6 +38,7 @@ app.use(async (req, res, next) => {
|
|||
|
||||
res.complate = result => res.status(200).json({ status: 200, result });
|
||||
|
||||
if (req.user) return next();
|
||||
const { username = null, password = null } = req.headers;
|
||||
|
||||
if (!username || !password)
|
||||
|
|
|
@ -40,5 +40,23 @@ app.post("/", rateLimit({
|
|||
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;
|
|
@ -4,7 +4,7 @@ const error = require("../errors/error");
|
|||
const app = Router();
|
||||
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) => {
|
||||
req.session.userid = null;
|
||||
|
@ -23,7 +23,7 @@ app.post("/", async (req, res) => {
|
|||
|
||||
req.session.userid = user.id;
|
||||
|
||||
res.redirect('/');
|
||||
res.redirect( req.query.redirect || '/');
|
||||
} else
|
||||
error(res, 403, 'Incorrect Username and/or Password!')
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
const { ThreadModel, MessageModel } = require("../models");
|
||||
const { MessageModel } = require("../models");
|
||||
const error = require("../errors/error")
|
||||
const rateLimit = require('express-rate-limit')
|
||||
|
||||
const { Router } = require("express");
|
||||
|
||||
|
@ -16,28 +15,6 @@ app.get("/:id", async (req, res) => {
|
|||
|
||||
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) => {
|
||||
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.");
|
||||
|
@ -51,23 +28,6 @@ app.post("/:id/delete", async (req, res) => {
|
|||
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.");
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -34,6 +34,9 @@ app.get("/:id", async (req, res) => {
|
|||
|
||||
const messages = await Promise.all(thread.messages.map(async 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;
|
||||
}));
|
||||
|
||||
|
|
|
@ -29,8 +29,10 @@
|
|||
|
||||
<% } else { %>
|
||||
<a style="float: right; background-color: #5F875F;" href="/register">REGISTER</a>
|
||||
|
||||
<a style="float: right; background-color:#5F87AF; " href="/login">LOGIN</a>
|
||||
<a id="login" style="float: right; background-color:#5F87AF; " href="/login">LOGIN</a>
|
||||
<script>
|
||||
document.getElementById("login").href += "?redirect="+window.location.pathname
|
||||
</script>
|
||||
|
||||
|
||||
<% } %>
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
<h1>Login</h1>
|
||||
<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="password" name="password" placeholder="Password" id="password" required>
|
||||
<input type="submit" value="Login">
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<%- include("extra/header", { title : thread.title }) %>
|
||||
<%- include("extra/header", { title: thread.title }) %>
|
||||
|
||||
<body>
|
||||
|
||||
|
@ -24,7 +24,8 @@
|
|||
|
||||
<% }; %>
|
||||
|
||||
<hr>
|
||||
<hr>
|
||||
<div id="messages">
|
||||
<% messages.forEach(message=>{ %>
|
||||
<% if (message){ %>
|
||||
|
||||
|
@ -50,18 +51,13 @@
|
|||
<form style="display:inline;" action="/message/<%= message.id %>/delete/" method="post">
|
||||
</a><button type="submit">DELETE</button>
|
||||
</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>
|
||||
<button style="display:inline;" id="like" value="<%= message.id %>">+🔼</button>
|
||||
<button style="display:inline;" id="dislike" value="<%= message.id %>" >-🔽</button>
|
||||
</div>
|
||||
|
||||
<h3 style="display:inline;">
|
||||
<%= Object.values(message.react).filter(Boolean).length - Object.values(message.react).filter(x=>
|
||||
!x).length %>
|
||||
</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>
|
||||
|
||||
|
||||
<form action="/message" method="POST">
|
||||
<form id= "send">
|
||||
<textarea rows="4" cols="133" name="content"></textarea>
|
||||
<input name="threadID" type="hidden" value="<%= thread.id %>"></input>
|
||||
|
||||
<br>
|
||||
<% if (user){ %>
|
||||
<button type="submit">Send!</button>
|
||||
<%} else {%>
|
||||
<button disabled>Login for send</button>
|
||||
<% }%>
|
||||
<%} else {%>
|
||||
<button disabled>Login for send</button>
|
||||
<% }%>
|
||||
|
||||
</form>
|
||||
|
||||
<% if (user){ %>
|
||||
<script src="/js/send.js"></script>
|
||||
<% }%>
|
||||
|
||||
<%- include("extra/footer") %>
|
||||
</body>
|
||||
|
|
Loading…
Reference in a new issue