mirror of
https://github.com/Akif9748/akf-forum.git
synced 2024-11-22 20:10:40 +03:00
new theme is fixed in everypage
This commit is contained in:
parent
9ad7c03162
commit
facaf105eb
13 changed files with 143 additions and 254 deletions
|
@ -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
|
||||
- regex for pfp for now and
|
||||
- admin perm for undelete, thread + message
|
||||
- page support for threads
|
||||
- page support for threads, send, if multi page, send => other page
|
||||
- message "<b>"
|
||||
- author name of thread
|
||||
- page for threads - users
|
||||
- edit & delete button for thread
|
||||
- API, ?fast=
|
||||
- fix error messages, ~~declared as id~~, other...
|
||||
|
||||
### Frontend
|
||||
### User
|
||||
| To do | Is done? | Priority |
|
||||
|
|
|
@ -14,7 +14,8 @@ const schema = new mongoose.Schema({
|
|||
react: {
|
||||
like: [Number],
|
||||
dislike: [Number]
|
||||
}
|
||||
},
|
||||
index: { type: Number, default: 0 }
|
||||
|
||||
})
|
||||
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
const { Schema, model } = require("mongoose")
|
||||
|
||||
const schema = new Schema({
|
||||
const mongoose = require("mongoose")
|
||||
|
||||
const schema = new mongoose.Schema({
|
||||
username: { type: String, unique: true },
|
||||
password: String,
|
||||
id: { type: String, unique: true }
|
||||
|
||||
|
||||
});
|
||||
|
||||
module.exports = model('secret', schema);
|
||||
module.exports = mongoose.model('secret', schema);
|
|
@ -1,46 +1,4 @@
|
|||
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("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll("\"", """).replaceAll("'", "'").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
|
||||
|
@ -52,10 +10,7 @@ document.getElementById("send")?.addEventListener("submit", async e => {
|
|||
const data = new FormData(form);
|
||||
request("/api/messages", "POST", { threadID: data.get("threadID"), content: data.get("content") })
|
||||
.then(res => {
|
||||
if (!res) return;
|
||||
form.reset();
|
||||
res.reactCount = 0;
|
||||
render_message(res);
|
||||
if (res) location.href = `/messages/${res.id}`;
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -63,7 +18,7 @@ document.getElementById("send")?.addEventListener("submit", async e => {
|
|||
* OTHER FUNCTIONS
|
||||
*/
|
||||
|
||||
async function delete_thread(id) {
|
||||
window.delete_thread = async function (id) {
|
||||
const response = await request("/api/threads/" + id + "/delete");
|
||||
if (response.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");
|
||||
if (!response.deleted) {
|
||||
alert("Thread undeleted");
|
||||
location.reload();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
async function undelete_message(id) {
|
||||
window.undelete_message = async function (id) {
|
||||
const response = await request(`/api/messages/${id}/undelete`);
|
||||
if (!response.deleted)
|
||||
document.getElementById("message-delete-" + id).innerHTML = `<a onclick=\"delete_message('${id}');\">DELETE</a>`;
|
||||
if (response.deleted) return;
|
||||
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`);
|
||||
if (response.deleted) {
|
||||
alert("Message deleted");
|
||||
document.getElementById("message-delete-" + id).innerHTML = `
|
||||
<h3 style=\"display:inline;\">This message has been deleted</h3>
|
||||
document.getElementById("dots-" + id).innerHTML = `
|
||||
<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
|
||||
}
|
||||
}
|
||||
async function react(id, type) {
|
||||
window.react = async function (id, 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;
|
|
@ -3,15 +3,7 @@ const { Router } = require("express")
|
|||
const app = Router();
|
||||
|
||||
app.get("/", async (req, res) => {
|
||||
if (!req.session.userid) return res.redirect('/login');
|
||||
|
||||
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 })
|
||||
if (!req.user?.admin) return res.error(403, "You have not got permissions for view to this page.");
|
||||
res.reply("admin")
|
||||
});
|
||||
|
||||
|
||||
|
||||
module.exports = app;
|
|
@ -31,7 +31,7 @@ app.post("/", rateLimit({
|
|||
|
||||
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 thread.push(message.id).save();
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ app.get("/:id/messages/", async (req, res) => {
|
|||
const query = { threadID: id };
|
||||
if (!req.user.admin) query.deleted = false;
|
||||
|
||||
const options = { sort: { date: -1 } };
|
||||
const options = { sort: { time: -1 } };
|
||||
if (limit) options.limit = limit;
|
||||
if (skip) options.skip = skip;
|
||||
|
||||
|
|
|
@ -7,8 +7,9 @@ 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, "We have not got any message declared as this id.");
|
||||
res.redirect("/threads/" + message.threadID+"?scroll="+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.redirect(`/threads/${message.threadID}?scroll=${req.params.id}`);
|
||||
|
||||
});
|
||||
|
||||
|
|
|
@ -14,27 +14,33 @@ app.get("/", async (req, res) => {
|
|||
|
||||
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 page = req.query.page || 0;
|
||||
const thread = await ThreadModel.get(id).skip(page * 10).limit(page * 10 + 10);
|
||||
const { user, params: { id } } = req
|
||||
|
||||
const page = Number(req.query.page || 0);
|
||||
const thread = await ThreadModel.get(id)
|
||||
if (thread && (user?.admin || !thread.deleted)) {
|
||||
thread.views++;
|
||||
const query = { threadID: id };
|
||||
if (!user || !user.admin) query.deleted = false;
|
||||
|
||||
if (thread && (req.user?.admin || !thread.deleted)) {
|
||||
const messages = await Promise.all(thread.messages.map(async id => {
|
||||
const message = await MessageModel.get(id)
|
||||
const messages = await MessageModel.find(query).sort({ time: 1 }).skip(page * 10).limit(page * 10 + 10)
|
||||
.then(messages => messages.map(message => {
|
||||
message.content = message.content.replaceAll("&", "&")
|
||||
.replaceAll("<", "<").replaceAll(">", ">")
|
||||
.replaceAll("\"", """).replaceAll("'", "'")
|
||||
.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
|
||||
res.error(404, "We have not got this thread.");
|
||||
thread.save();
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -11,17 +11,16 @@ app.get("/", async ({ user }, res) => {
|
|||
|
||||
app.get("/:id", async (req, res) => {
|
||||
const user = req.user
|
||||
const { id = null } = req.params;
|
||||
const { id } = req.params;
|
||||
const member = await UserModel.get(id);
|
||||
|
||||
|
||||
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 });
|
||||
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}.`);
|
||||
|
||||
});
|
||||
|
||||
|
|
|
@ -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>
|
|
@ -12,12 +12,28 @@
|
|||
<% if (user){ %>
|
||||
<script type="module" src="/js/thread.js"></script>
|
||||
<% }; %>
|
||||
|
||||
<div style="text-align:center;padding:8px">
|
||||
<div class="title"><%= thread.title %></div>
|
||||
<div class="date">
|
||||
<%= new Date(thread.time).toLocaleString() %> • Views: <%= thread.views %>
|
||||
</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 %>">
|
||||
|
||||
<% messages.filter(Boolean).forEach(message=>{ %>
|
||||
|
@ -38,31 +54,32 @@
|
|||
<% if(user){ %>
|
||||
<% 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>
|
||||
</div>
|
||||
|
||||
<% if (!message.deleted){ %>
|
||||
|
||||
<div class="dots-menu" id="dot-<%=message.id %>">
|
||||
<% if (!message.deleted){ %>
|
||||
<a onclick="delete_message('<%=message.id %>');">Delete</a>
|
||||
<a onclick="edit_message('<%=message.id %>');">Edit</a>
|
||||
</div>
|
||||
<% }else if (user.admin){ %>
|
||||
<div class="dots-menu" id="dot-<%=message.id %>">
|
||||
<a onclick="undelete_message('<%=message.id %>');">UNDELETE</a>
|
||||
</div>
|
||||
<a onclick="undelete_message('<%=message.id %>');">Undelete</a>
|
||||
<% } %>
|
||||
|
||||
</div>
|
||||
<% } %>
|
||||
|
||||
|
||||
<div class="reactions">
|
||||
<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>
|
||||
<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>
|
||||
<% }; %>
|
||||
|
@ -71,6 +88,20 @@
|
|||
|
||||
<% }); %>
|
||||
</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="back">
|
||||
<% if (page > 0){ %>
|
||||
|
@ -80,13 +111,13 @@
|
|||
|
||||
|
||||
<div class="numbers">
|
||||
<% for(let i=0;i< Math.ceil(messages.length/10);i++){ %>
|
||||
<a class="number <%= i==page?'active':'' %>" href="<%= thread.getLink() %>?page=<%= i %>"><%= i %></a>
|
||||
<% for(let i=0;i <= Math.ceil(messages.length/10) ;i++){ %>
|
||||
<a class="number <%= i==page?'active':'' %>" href="<%= thread.getLink() %>?page=<%= i %>"><%= i+1 %></a>
|
||||
<% } %>
|
||||
</div>
|
||||
|
||||
<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>
|
||||
<% } %>
|
||||
</div>
|
||||
|
|
Loading…
Reference in a new issue