new theme is fixed in everypage

This commit is contained in:
Akif9748 2022-08-29 16:16:44 +03:00
parent 9ad7c03162
commit facaf105eb
13 changed files with 143 additions and 254 deletions

View file

@ -33,11 +33,13 @@ Akf-forum has got an API for AJAX, other clients etc. And, you can learn about A
- Profile photos will store in database - Profile photos will store in database
- regex for pfp for now and - regex for pfp for now and
- admin perm for undelete, thread + message - admin perm for undelete, thread + message
- page support for threads - page support for threads, send, if multi page, send => other page
- message "<b>" - message "<b>"
- author name of thread - author name of thread
- page for threads - users - page for threads - users
- edit & delete button for thread - API, ?fast=
- fix error messages, ~~declared as id~~, other...
### Frontend ### Frontend
### User ### User
| To do | Is done? | Priority | | To do | Is done? | Priority |

View file

@ -14,7 +14,8 @@ const schema = new mongoose.Schema({
react: { react: {
like: [Number], like: [Number],
dislike: [Number] dislike: [Number]
} },
index: { type: Number, default: 0 }
}) })

View file

@ -1,12 +1,9 @@
const { Schema, model } = require("mongoose") const mongoose = require("mongoose")
const schema = new Schema({
const schema = new mongoose.Schema({
username: { type: String, unique: true }, username: { type: String, unique: true },
password: String, password: String,
id: { type:String, unique: true } id: { type: String, unique: true }
}); });
module.exports = model('secret', schema); module.exports = mongoose.model('secret', schema);

View file

@ -1,46 +1,4 @@
import request from "./request.js"; import request from "./request.js";
const message_div = document.getElementById("messages");
function render_message(message) {
const messageElement = document.createElement("div");
messageElement.classList.add("message");
messageElement.setAttribute("id", "message-" + message.id);
messageElement.innerHTML = `
<h3 style="float:right;">${new Date(message.time).toLocaleString()}</h3>
<h2>
<img class="circle" src="${message.author.avatar}">
<a href="/users/${message.author.id}"> ${message.author.name}</a>:
</h2>
<p>${message.content.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;").replaceAll("'", "&#39;").replaceAll("\n", "<br>")}</p><br>
<div id="message-delete-${message.id}">
${/* if */!message.deleted ?
`
<a onclick="delete_message('${message.id}');">DELETE</a>
<a onclick="edit_message('${message.id}');">EDIT</a>
` /* else */ :
`<h3 style=\"display:inline;\">This message has been deleted</h3>
<a onclick="undelete_message('${message.id}');">UNDELETE</a>
`
}
</div>
<div style="float: right;">
<h3 id="count${message.id}" style="display:inline;">${message.reactCount}</h3>
<a onclick="react('${message.id}', 'like');">+🔼</a>
<a onclick="react('${message.id}', 'dislike');">-🔽</a>
</div>
`;
message_div.appendChild(messageElement);
message_div.innerHTML += "<br>";
};
window.scrollTo(0, document.body.scrollHeight);
/** /**
* Message Sender * Message Sender
@ -52,10 +10,7 @@ document.getElementById("send")?.addEventListener("submit", async e => {
const data = new FormData(form); const data = new FormData(form);
request("/api/messages", "POST", { threadID: data.get("threadID"), content: data.get("content") }) request("/api/messages", "POST", { threadID: data.get("threadID"), content: data.get("content") })
.then(res => { .then(res => {
if (!res) return; if (res) location.href = `/messages/${res.id}`;
form.reset();
res.reactCount = 0;
render_message(res);
}); });
}); });
@ -63,7 +18,7 @@ document.getElementById("send")?.addEventListener("submit", async e => {
* OTHER FUNCTIONS * OTHER FUNCTIONS
*/ */
async function delete_thread(id) { window.delete_thread = async function (id) {
const response = await request("/api/threads/" + id + "/delete"); const response = await request("/api/threads/" + id + "/delete");
if (response.deleted) { if (response.deleted) {
alert("Thread deleted"); alert("Thread deleted");
@ -71,37 +26,39 @@ async function delete_thread(id) {
} }
} }
async function undelete_thread(id) { window.undelete_thread = async function (id) {
const response = await request("/api/threads/" + id + "/undelete"); const response = await request("/api/threads/" + id + "/undelete");
if (!response.deleted) { if (!response.deleted) {
alert("Thread undeleted"); alert("Thread undeleted");
location.reload(); location.reload();
} }
} }
async function undelete_message(id) { window.undelete_message = async function (id) {
const response = await request(`/api/messages/${id}/undelete`); const response = await request(`/api/messages/${id}/undelete`);
if (!response.deleted) if (response.deleted) return;
document.getElementById("message-delete-" + id).innerHTML = `<a onclick=\"delete_message('${id}');\">DELETE</a>`; document.getElementById("deleted-" + id).remove();
document.getElementById("dot-" + id).innerHTML = `
<a onclick="delete_message('${id}');">DELETE</a>
<a onclick="edit_message('${id}');">EDIT</a>
`
} }
async function delete_message(id) { window.delete_message = async function (id) {
const response = await request(`/api/messages/${id}/delete`); const response = await request(`/api/messages/${id}/delete`);
if (response.deleted) { if (response.deleted) {
alert("Message deleted"); alert("Message deleted");
document.getElementById("message-delete-" + id).innerHTML = ` document.getElementById("dots-" + id).innerHTML = `
<h3 style=\"display:inline;\">This message has been deleted</h3> <i class='bx bx-trash bx-sm' id="deleted-${id}" style="color: RED;"></i>
`+ document.getElementById("dots-" + id).innerHTML;
document.getElementById("dot-" + id).innerHTML = `
<a onclick="undelete_message('${id}');">UNDELETE</a>`;// ADMIN PERM FIX <a onclick="undelete_message('${id}');">UNDELETE</a>`;// ADMIN PERM FIX
} }
} }
async function react(id, type) { window.react = async function (id, type) {
const res = await request(`/api/messages/${id}/react/${type}`) const res = await request(`/api/messages/${id}/react/${type}`)
document.getElementById(`count${id}`).innerHTML = res.reactCount; document.getElementById(`like-${id}`).innerHTML = res.react.like.length;
document.getElementById(`dislike-${id}`).innerHTML = res.react.dislike.length;
} }
window.delete_message = delete_message;
window.undelete_message = undelete_message;
window.react = react;
window.delete_thread = delete_thread;
window.undelete_thread = undelete_thread;

View file

@ -3,15 +3,7 @@ const { Router } = require("express")
const app = Router(); const app = Router();
app.get("/", async (req, res) => { app.get("/", async (req, res) => {
if (!req.session.userid) return res.redirect('/login'); if (!req.user?.admin) return res.error(403, "You have not got permissions for view to this page.");
res.reply("admin")
const user = req.user;
if (!user?.admin) return res.error( 403, "You have not got permissions for view to this page.");
res.reply("admin", { user2: false })
}); });
module.exports = app; module.exports = app;

View file

@ -31,7 +31,7 @@ app.post("/", rateLimit({
if (!thread) return res.error(404, `We don't have any thread with id ${threadID}.`); if (!thread) return res.error(404, `We don't have any thread with id ${threadID}.`);
const message = await new MessageModel({ content, author: req.user, threadID: thread.id }).takeId(); const message = await new MessageModel({ content, author: req.user, threadID: thread.id, index: thread.messages.length }).takeId();
await message.save(); await message.save();
await thread.push(message.id).save(); await thread.push(message.id).save();

View file

@ -26,7 +26,7 @@ app.get("/:id/messages/", async (req, res) => {
const query = { threadID: id }; const query = { threadID: id };
if (!req.user.admin) query.deleted = false; if (!req.user.admin) query.deleted = false;
const options = { sort: { date: -1 } }; const options = { sort: { time: -1 } };
if (limit) options.limit = limit; if (limit) options.limit = limit;
if (skip) options.skip = skip; if (skip) options.skip = skip;

View file

@ -3,7 +3,7 @@ const { Router } = require("express");
const app = Router(); const app = Router();
const bcrypt = require("bcrypt"); const bcrypt = require("bcrypt");
app.get("/", (req, res) => res.reply("login",{redirect: req.query.redirect,user:null})); app.get("/", (req, res) => res.reply("login", { redirect: req.query.redirect, user: null }));
app.post("/", async (req, res) => { app.post("/", async (req, res) => {
req.session.userid = null; req.session.userid = null;
@ -14,19 +14,19 @@ app.post("/", async (req, res) => {
const user = await SecretModel.findOne({ username }); const user = await SecretModel.findOne({ username });
if (user) { if (user) {
if (!await bcrypt.compare(password, user.password)) return res.error( 403, 'Incorrect Password!') if (!await bcrypt.compare(password, user.password)) return res.error(403, 'Incorrect Password!')
const member = await UserModel.findOne({ name: username }); const member = await UserModel.findOne({ name: username });
if (!member || member.deleted) return res.error( 403, 'Incorrect Username and/or Password!') 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 || '/'); res.redirect(req.query.redirect || '/');
} else } else
res.error( 403, 'Incorrect Username and/or Password!') res.error(403, 'Incorrect Username and/or Password!')
} else } else
res.error( 400, "You forgot entering some values") res.error(400, "You forgot entering some values")

View file

@ -7,8 +7,9 @@ const app = Router();
app.get("/:id", async (req, res) => { app.get("/:id", async (req, res) => {
const message = await MessageModel.get(req.params.id); const message = await MessageModel.get(req.params.id);
if (!message || (message.deleted && req.user && !req.user.admin)) return res.error( 404, "We have not got any message declared as this id."); if (!message || (message.deleted && req.user && !req.user.admin)) return res.error( 404,
res.redirect("/threads/" + message.threadID+"?scroll="+req.params.id); `We don't have any message with id ${req.params.id}.`);
res.redirect(`/threads/${message.threadID}?scroll=${req.params.id}`);
}); });

View file

@ -1,7 +1,7 @@
const { Router } = require("express"); const { Router } = require("express");
const app = Router(); const app = Router();
const { ThreadModel,MessageModel } = require("../models") const { ThreadModel, MessageModel } = require("../models")
app.get("/", async (req, res) => { app.get("/", async (req, res) => {
@ -14,27 +14,33 @@ app.get("/", async (req, res) => {
app.get("/create*", (req, res) => res.reply("create_thread")); app.get("/create*", (req, res) => res.reply("create_thread"));
app.get("/:id", async (req, res) => { app.get("/:id/", async (req, res) => {
const { id } = req.params; const { user, params: { id } } = req
const page = req.query.page || 0;
const thread = await ThreadModel.get(id).skip(page * 10).limit(page * 10 + 10); const page = Number(req.query.page || 0);
const thread = await ThreadModel.get(id)
if (thread && (user?.admin || !thread.deleted)) {
thread.views++; thread.views++;
const query = { threadID: id };
if (!user || !user.admin) query.deleted = false;
if (thread && (req.user?.admin || !thread.deleted)) { const messages = await MessageModel.find(query).sort({ time: 1 }).skip(page * 10).limit(page * 10 + 10)
const messages = await Promise.all(thread.messages.map(async id => { .then(messages => messages.map(message => {
const message = await MessageModel.get(id)
message.content = message.content.replaceAll("&", "&amp;") message.content = message.content.replaceAll("&", "&amp;")
.replaceAll("<", "&lt;").replaceAll(">", "&gt;") .replaceAll("<", "&lt;").replaceAll(">", "&gt;")
.replaceAll("\"", "&quot;").replaceAll("'", "&#39;") .replaceAll("\"", "&quot;").replaceAll("'", "&#39;")
.replaceAll("\n", "<br>"); .replaceAll("\n", "<br>");
return req.user?.admin || !message?.deleted ? message.toObject({ virtuals: true }) : null; return message.toObject({ virtuals: true });
})); }))
res.reply("thread", { page, thread, messages, scroll: req.query.scroll || thread.messages[0].id });
thread.save();
res.reply("thread", { page,thread, messages, scroll: req.query.scroll || thread.messages[0]});
} else } else
res.error(404, "We have not got this thread."); res.error(404, "We have not got this thread.");
thread.save();
}); });

View file

@ -11,17 +11,16 @@ app.get("/", async ({ user }, res) => {
app.get("/:id", async (req, res) => { app.get("/:id", async (req, res) => {
const user = req.user const user = req.user
const { id = null } = req.params; const { id } = req.params;
const member = await UserModel.get(id); const member = await UserModel.get(id);
if (member && (user?.admin || !member.deleted)) { if (member && (user?.admin || !member.deleted)) {
const message = await MessageModel.count({ "author.id": id });// this place was having problem. fixed const message = await MessageModel.count({ "author.id": id });
const thread = await ThreadModel.count({ "author.id": id }); const thread = await ThreadModel.count({ "author.id": id });
res.reply("user", { member, counts: { message, thread } }) res.reply("user", { member, counts: { message, thread } })
} }
else res.error(404, "We have not got this user."); else res.error(404, `We don't have any user with id ${id}.`);
}); });

View file

@ -1,97 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<%- include("extra/meta", {title: "Thread list!" }) %>
<body style="text-align: center;">
<%- include("extra/navbar") %>
<link rel="stylesheet" href="/css/thread.css" />
<% if (user){ %>
<script type="module" src="/js/thread.js"></script>
<% }%>
<h1 style="font-size: 35px;color: #4d18e6;" ><%= thread.title %></h1>
<h3 >View count: <%= thread.views %></h1>
<h2 style="display:inline;">By <a href="<%='/users/' + thread.author.id %>"> <%= thread.author.name %></a>
<img class="circle" src="<%=thread.author.avatar %>">
</h2>
<% if (user && !thread.deleted){ %>
<a onclick="delete_thread('<%= thread.id %>' )" value=style="display:inline;" >DELETE</a>
<a onclick="edit_thread('<%= thread.id %>')" style="display:inline;" >EDIT</a>
<% } else if (thread.deleted) { %>
<h3 style="display:inline;">This thread has been deleted</h3>
<a onclick="undelete_thread('<%= thread.id %>')" style="display:inline;" >UNDELETE</a>
<% }; %>
<hr>
<div id="messages" value="<%= thread.id %>">
<% messages.filter(Boolean).forEach(message=>{ %>
<div class="message" id="message-<%= message.id %>">
<h3 style="float:right;"><%= new Date(message.time).toLocaleString() %> </h3>
<h2>
<img class="circle" src="<%= message.author.avatar %>">
<a href="/users/<%=message.author.id %>"><%=message.author.name %></a>:
</h2>
<p><%= message.content%></p><br>
<div id="message-delete-<%=message.id %>">
<% if (!message.deleted){ %>
<a onclick="delete_message('<%=message.id %>');">DELETE</a>
<a onclick="edit_message('<%=message.id %>');">EDIT</a>
<% }else{ %>
<h3 style="display:inline;">This message has been deleted</h3>
<a onclick="undelete_message('<%=message.id %>');">UNDELETE</a>
<% } %>
</div>
<div style="float: right;">
<h3 id="count<%=message.id %>" style="display:inline;"><%=message.reactCount %></h3>
<a onclick="react('<%=message.id %>', 'like');">+🔼</a>
<a onclick="react('<%=message.id %>', 'dislike');">-🔽</a>
</div>
</div>
<% }); %>
</div>
<hr>
<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>
<% }%>
</form>
<script>
document.getElementById("message-<%= scroll %>").scrollIntoView();
</script>
<!-- BURAYA Bİ İLERİ BİR GERİ SAYFA BUTONU GELMEZ Mİ BE-->
</body>
</html>

View file

@ -12,12 +12,28 @@
<% if (user){ %> <% if (user){ %>
<script type="module" src="/js/thread.js"></script> <script type="module" src="/js/thread.js"></script>
<% }; %> <% }; %>
<div style="text-align:center;padding:8px"> <div style="text-align:center;padding:8px">
<div class="title"><%= thread.title %></div> <div class="title"><%= thread.title %></div>
<div class="date"> <div class="date">
<%= new Date(thread.time).toLocaleString() %> • Views: <%= thread.views %> <%= new Date(thread.time).toLocaleString() %> • Views: <%= thread.views %>
</div> </div>
</div> </div>
<div style="text-align:center;padding:8px">
<!-- THREAD AUTHOR AND PROFILE PHOTO -->
<% if (user && !thread.deleted){ %>
<a onclick="delete_thread('<%= thread.id %>' )" class="btn-outline-primary" >DELETE</a>
<a onclick="edit_thread('<%= thread.id %>')" class="btn-outline-primary" >EDIT</a>
<% } else if (thread.deleted) { %>
<h3 style="display:inline;">This thread has been deleted</h3>
<a onclick="undelete_thread('<%= thread.id %>')" class="btn-primary" >UNDELETE</a>
<% }; %>
</div>
<div id="messages" value="<%= thread.id %>"> <div id="messages" value="<%= thread.id %>">
<% messages.filter(Boolean).forEach(message=>{ %> <% messages.filter(Boolean).forEach(message=>{ %>
@ -35,34 +51,35 @@
</div> </div>
<div class="content"><%- message.content %></div> <div class="content"><%- message.content %></div>
<% if(user){ %> <% if(user){ %>
<% if(user.id === message.author.id || user.admin){ %> <% if(user.id === message.author.id || user.admin){ %>
<div class="dots" onclick="dots('<%=message.id %>')"> <div class="dots" id="dots-<%=message.id %>" onclick="dots('<%=message.id %>')">
<% if (message.deleted){ %>
<i class='bx bx-trash bx-sm' id="deleted-<%=message.id %>" style="color: RED;"></i>
<% } %>
<i class='bx bx-dots-horizontal-rounded' ></i> <i class='bx bx-dots-horizontal-rounded' ></i>
</div> </div>
<% if (!message.deleted){ %>
<div class="dots-menu" id="dot-<%=message.id %>"> <div class="dots-menu" id="dot-<%=message.id %>">
<% if (!message.deleted){ %>
<a onclick="delete_message('<%=message.id %>');">Delete</a> <a onclick="delete_message('<%=message.id %>');">Delete</a>
<a onclick="edit_message('<%=message.id %>');">Edit</a> <a onclick="edit_message('<%=message.id %>');">Edit</a>
</div>
<% }else if (user.admin){ %> <% }else if (user.admin){ %>
<div class="dots-menu" id="dot-<%=message.id %>"> <a onclick="undelete_message('<%=message.id %>');">Undelete</a>
<a onclick="undelete_message('<%=message.id %>');">UNDELETE</a>
</div>
<% } %> <% } %>
</div>
<% } %> <% } %>
<div class="reactions"> <div class="reactions">
<div> <div>
<i class='bx bx-like'></i> <%=message.react.like.length %> <i onclick='react("<%= message.id %>","like");' class='bx bx-like'></i>
<div id="like-<%= message.id %>"><%=message.react.like.length %></div>
</div> </div>
<div> <div>
<i class='bx bx-dislike'></i> <%=message.react.dislike.length %> <i onclick='react("<%= message.id %>","dislike");' class='bx bx-dislike'></i>
<div id="dislike-<%= message.id %>"><%=message.react.dislike.length %></div>
</div> </div>
</div> </div>
<% }; %> <% }; %>
@ -71,6 +88,20 @@
<% }); %> <% }); %>
</div> </div>
<div class="message">
<form id="send">
<textarea rows="4" cols="100" name="content"></textarea>
<input name="threadID" type="hidden" value="<%= thread.id %>"></input>
<% if (user){ %>
<button class="btn-primary">Send!</button>
<%} else {%>
<a class="btn-outline-primary" href="/login?redirect=<%= thread.getLink() %>">Login for send</a>
<% }%>
</form>
</div>
<div class="pagination"> <div class="pagination">
<div class="back"> <div class="back">
<% if (page > 0){ %> <% if (page > 0){ %>
@ -80,13 +111,13 @@
<div class="numbers"> <div class="numbers">
<% for(let i=0;i< Math.ceil(messages.length/10);i++){ %> <% for(let i=0;i <= Math.ceil(messages.length/10) ;i++){ %>
<a class="number <%= i==page?'active':'' %>" href="<%= thread.getLink() %>?page=<%= i %>"><%= i %></a> <a class="number <%= i==page?'active':'' %>" href="<%= thread.getLink() %>?page=<%= i %>"><%= i+1 %></a>
<% } %> <% } %>
</div> </div>
<div class="after"> <div class="after">
<% if (Math.ceil(messages.length/10)-1 > page){ %> <% if (Math.ceil(messages.length/10) > page){ %>
<a href="<%= thread.getLink() %>?page=<%= page +1 %>" class='bx bxs-chevron-right'></a> <a href="<%= thread.getLink() %>?page=<%= page +1 %>" class='bx bxs-chevron-right'></a>
<% } %> <% } %>
</div> </div>