diff --git a/README.md b/README.md index b259af2..5c106b9 100644 --- a/README.md +++ b/README.md @@ -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 "" - 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 | diff --git a/models/Message.js b/models/Message.js index 2808503..5cdeff9 100644 --- a/models/Message.js +++ b/models/Message.js @@ -14,7 +14,8 @@ const schema = new mongoose.Schema({ react: { like: [Number], dislike: [Number] - } + }, + index: { type: Number, default: 0 } }) diff --git a/models/Secret.js b/models/Secret.js index b4bb922..e8c71e0 100644 --- a/models/Secret.js +++ b/models/Secret.js @@ -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 } - - + id: { type: String, unique: true } }); -module.exports = model('secret', schema); \ No newline at end of file +module.exports = mongoose.model('secret', schema); \ No newline at end of file diff --git a/public/js/thread.js b/public/js/thread.js index 0f14e00..1e6b885 100644 --- a/public/js/thread.js +++ b/public/js/thread.js @@ -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 = ` - -

${new Date(message.time).toLocaleString()}

- -

- - ${message.author.name}: -

- -

${message.content.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll("\"", """).replaceAll("'", "'").replaceAll("\n", "
")}


-
- ${/* if */!message.deleted ? - ` - DELETE - EDIT - ` /* else */ : - `

This message has been deleted

- UNDELETE - ` - - } -
-
-

${message.reactCount}

- +🔼 - -🔽 -
-`; - - message_div.appendChild(messageElement); - message_div.innerHTML += "
"; -}; - -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 = `DELETE`; + if (response.deleted) return; + document.getElementById("deleted-" + id).remove(); + document.getElementById("dot-" + id).innerHTML = ` + DELETE + EDIT + ` + } -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 = ` -

This message has been deleted

+ document.getElementById("dots-" + id).innerHTML = ` + + `+ document.getElementById("dots-" + id).innerHTML; + + document.getElementById("dot-" + id).innerHTML = ` UNDELETE`;// 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; \ No newline at end of file diff --git a/routes/admin.js b/routes/admin.js index d662bef..fec6ead 100644 --- a/routes/admin.js +++ b/routes/admin.js @@ -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; +module.exports = app; \ No newline at end of file diff --git a/routes/api/routes/messages.js b/routes/api/routes/messages.js index 6c194c0..fc80d0c 100644 --- a/routes/api/routes/messages.js +++ b/routes/api/routes/messages.js @@ -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(); diff --git a/routes/api/routes/threads.js b/routes/api/routes/threads.js index 9d9ab0b..a2c6df9 100644 --- a/routes/api/routes/threads.js +++ b/routes/api/routes/threads.js @@ -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; diff --git a/routes/login.js b/routes/login.js index abb073e..12d9c03 100644 --- a/routes/login.js +++ b/routes/login.js @@ -3,7 +3,7 @@ const { Router } = require("express"); const app = Router(); 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) => { req.session.userid = null; @@ -14,19 +14,19 @@ app.post("/", async (req, res) => { const user = await SecretModel.findOne({ username }); 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 }); - 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; - res.redirect( req.query.redirect || '/'); + res.redirect(req.query.redirect || '/'); } else - res.error( 403, 'Incorrect Username and/or Password!') + res.error(403, 'Incorrect Username and/or Password!') } else - res.error( 400, "You forgot entering some values") + res.error(400, "You forgot entering some values") diff --git a/routes/messages.js b/routes/messages.js index 917ed5f..26fdc2e 100644 --- a/routes/messages.js +++ b/routes/messages.js @@ -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}`); }); diff --git a/routes/threads.js b/routes/threads.js index 6d01ae3..e539a0d 100644 --- a/routes/threads.js +++ b/routes/threads.js @@ -1,7 +1,7 @@ const { Router } = require("express"); const app = Router(); -const { ThreadModel,MessageModel } = require("../models") +const { ThreadModel, MessageModel } = require("../models") 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("/: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); - thread.views++; + const { user, params: { id } } = req - if (thread && (req.user?.admin || !thread.deleted)) { - const messages = await Promise.all(thread.messages.map(async id => { - const message = await MessageModel.get(id) - message.content = message.content.replaceAll("&", "&") - .replaceAll("<", "<").replaceAll(">", ">") - .replaceAll("\"", """).replaceAll("'", "'") - .replaceAll("\n", "
"); - return req.user?.admin || !message?.deleted ? message.toObject({ virtuals: true }) : null; - })); + 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; + + 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", "
"); + 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(); }); diff --git a/routes/users.js b/routes/users.js index 2bcda13..76400f1 100644 --- a/routes/users.js +++ b/routes/users.js @@ -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}.`); }); diff --git a/views/extra/ot.ejs b/views/extra/ot.ejs index 7c59c47..e69de29 100644 --- a/views/extra/ot.ejs +++ b/views/extra/ot.ejs @@ -1,97 +0,0 @@ - - - -<%- include("extra/meta", {title: "Thread list!" }) %> - - - - <%- include("extra/navbar") %> - - - <% if (user){ %> - - <% }%> - - -

<%= thread.title %>

-

View count: <%= thread.views %>

- -

By <%= thread.author.name %> - -

- - <% if (user && !thread.deleted){ %> - - DELETE - EDIT - <% } else if (thread.deleted) { %> -

This thread has been deleted

- UNDELETE - - <% }; %> - - -
- - -
- - <% messages.filter(Boolean).forEach(message=>{ %> - -
- -

<%= new Date(message.time).toLocaleString() %>

- -

- - <%=message.author.name %>: -

- -

<%= message.content%>


-
- - <% if (!message.deleted){ %> - - DELETE - EDIT - <% }else{ %> -

This message has been deleted

- UNDELETE - <% } %> - -
-
-

<%=message.reactCount %>

- +🔼 - -🔽 -
-
- <% }); %> - -
- -
- - -
- - - -
- <% if (user){ %> - - <%} else {%> - - <% }%> - -
- - - - - - - - \ No newline at end of file diff --git a/views/thread.ejs b/views/thread.ejs index 7c4bb62..aaa5f8d 100644 --- a/views/thread.ejs +++ b/views/thread.ejs @@ -12,65 +12,96 @@ <% if (user){ %> <% }; %> +
<%= thread.title %>
<%= new Date(thread.time).toLocaleString() %> • Views: <%= thread.views %>
+
+
+ + + <% if (user && !thread.deleted){ %> + + DELETE + EDIT + <% } else if (thread.deleted) { %> +

This thread has been deleted

+ UNDELETE + + <% }; %> +
+
- <% messages.filter(Boolean).forEach(message=>{ %> + <% messages.filter(Boolean).forEach(message=>{ %> -
-
- - -
- <%= new Date(message.time).toLocaleDateString() %> +
+
+ + +
+ <%= new Date(message.time).toLocaleDateString() %> +
+
+ <%= new Date(message.time).toLocaleTimeString() %> +
+
+ +
<%- message.content %>
+ <% if(user){ %> + <% if(user.id === message.author.id || user.admin){ %> + +
+ <% if (message.deleted){ %> + + <% } %> +
-
- <%= new Date(message.time).toLocaleTimeString() %> -
-
-
<%- message.content %>
-<% if(user){ %> - <% if(user.id === message.author.id || user.admin){ %> - -
- -
- - <% if (!message.deleted){ %> -
+ <% if (!message.deleted){ %> Delete Edit -
<% }else if (user.admin){ %> -
- UNDELETE -
- <% } %> - - <% } %> + Undelete + <% } %> +
+ <% } %> -
-
- <%=message.react.like.length %> -
-
- <%=message.react.dislike.length %> -
-
- <% }; %> +
+
+ +
<%=message.react.like.length %>
+
+
+ +
<%=message.react.dislike.length %>
+
+
+ <% }; %> -
+
<% }); %>
+
+
+ + + + + + <% if (user){ %> + + <%} else {%> + Login for send + <% }%> +
+