diff --git a/index.js b/index.js index dbeb6d3..8d734e2 100644 --- a/index.js +++ b/index.js @@ -22,8 +22,7 @@ app.use( session({ secret: 'secret', resave: true, saveUninitialized: true }), express.static("public"), express.json(), ipBlock(app.ips), async (req, res, next) => { - if (req.session.userID) - req.user = await UserModel.findOneAndUpdate({ id: req.session.userID }, { lastSeen: Date.now() }); + req.user = req.session.userID ? await UserModel.findOneAndUpdate({ id: req.session.userID }, { lastSeen: Date.now() }) : null; res.reply = (page, options = {}, status = 200) => res.status(status) .render(page, { user: req.user, theme: req.user?.theme || def_theme, forum_name, desp, ...options }); diff --git a/models/Category.js b/models/Category.js index c43f7f5..15c278a 100644 --- a/models/Category.js +++ b/models/Category.js @@ -11,6 +11,11 @@ schema.methods.takeId = async function () { this.id = String(await model.count() || 0); return this; } + +schema.methods.getLink = function (id = this.id) { + return "/categories/" + this.id; +} + const model = mongoose.model('category', schema); module.exports = model; \ No newline at end of file diff --git a/routes/api/routes/categories.js b/routes/api/routes/categories.js index cac0c3a..ed85e65 100644 --- a/routes/api/routes/categories.js +++ b/routes/api/routes/categories.js @@ -40,8 +40,8 @@ app.post("/", async (req, res) => { if (!name) return res.error(400, "You have to give a name for the category."); if (await CategoryModel.exists({ name })) return res.error(400, "This category is already opened."); - - res.complate(await CategoryModel.create({ name, desp, authorID: req.user.id }).then(c => c.takeId())); + const category = await new CategoryModel({ name, desp, authorID: req.user.id }).takeId(); + res.complate(await category.save()); }); diff --git a/routes/api/routes/threads.js b/routes/api/routes/threads.js index e3fed7a..2895605 100644 --- a/routes/api/routes/threads.js +++ b/routes/api/routes/threads.js @@ -39,7 +39,7 @@ app.get("/:id/messages/", async (req, res) => { app.post("/", async (req, res) => { const { title, content } = req.body; - +return console.log(req.body) if (!content || !title) return res.error(400, "Missing content/title in request body."); const { user } = req; diff --git a/routes/categories.js b/routes/categories.js new file mode 100644 index 0000000..ba3a3d7 --- /dev/null +++ b/routes/categories.js @@ -0,0 +1,25 @@ +const { CategoryModel,ThreadModel } = require("../models"); + +const { Router } = require("express"); + +const app = Router(); +app.get("/", async (req, res) => { + const categories = await CategoryModel.find({}); + res.reply("categories", { categories }); +}); + +app.get("/create",(req,res)=>res.reply("create_category")); +app.get("/:id", async (req, res) => { + const category = await CategoryModel.findOne({ id: req.params.id }); + if (!category) return res.error(404, "Category not found."); + const page = Number(req.query.page) || 0; + const query = { categoryID: category.id }; + if (!req.user?.admin) query.deleted= false; + + let threads = await ThreadModel.find(query).limit(10).skip(page * 10); + threads = await Promise.all(threads.map(thread => thread.get_author())); + + res.reply("threads", { threads, page, title: `Threads in ${category.name}`, desp: category.desp, pages: Math.ceil(await ThreadModel.count(query) / 10) }); +}); + +module.exports = app; \ No newline at end of file diff --git a/routes/search.js b/routes/search.js index ee7eb19..14807d3 100644 --- a/routes/search.js +++ b/routes/search.js @@ -42,8 +42,7 @@ app.get("/threads", async (req, res) => { if (req.query.authorID) query.authorID = req.query.authorID; const threads = await ThreadModel.find(query, null, req.so) res.reply("threads", { - threads, - page: null, page: req.page, + threads, page: req.page, title: "Threads with query " + req.query.q, pages: Math.ceil(await ThreadModel.count(query) / 10) }); }); diff --git a/routes/threads.js b/routes/threads.js index e58b0bf..f8a9010 100644 --- a/routes/threads.js +++ b/routes/threads.js @@ -1,7 +1,7 @@ const { Router } = require("express"); const app = Router(); const { clearContent } = require("../lib"); -const { ThreadModel, MessageModel } = require("../models") +const { ThreadModel, MessageModel, CategoryModel } = require("../models") app.get("/", async (req, res) => { const page = Number(req.query.page) || 0; @@ -9,11 +9,11 @@ app.get("/", async (req, res) => { let threads = await ThreadModel.find(query).limit(10).skip(page * 10); threads = await Promise.all(threads.map(thread => thread.get_author())); - return res.reply("threads", { threads, page, pages: Math.ceil(await ThreadModel.count(query) / 10) }); + return res.reply("threads", { threads, page, title: "Threads", desp: threads.length + " thread listed", pages: Math.ceil(await ThreadModel.count(query) / 10) }); }); -app.get("/create/", (req, res) => res.reply("create_thread")); +app.get("/create/", async (req, res) => res.reply("create_thread", { categories: await CategoryModel.find() })); app.get("/:id/", async (req, res) => { diff --git a/views/categories.ejs b/views/categories.ejs new file mode 100644 index 0000000..31a1a06 --- /dev/null +++ b/views/categories.ejs @@ -0,0 +1,58 @@ +<!DOCTYPE html> +<html lang="en"> +<%- include("extra/meta", {title: "Thread list!" }) %> + +<body> + <link href='https://unpkg.com/boxicons@2.1.2/css/boxicons.min.css' rel='stylesheet'> + + <link rel="stylesheet" href="/css/threads.css" /> + <link rel="stylesheet" href="/css/pages.css" /> + + <%- include("extra/navbar") %> + <div class="threads"> + <%if(user?.admin) {%> + <a href="/categories/create" class="btn-primary">Create Category</a> + <% }; %> + <% categories.forEach(category=>{ %> + <a href="<%= category.getLink() %>" > + <div class="threads-box"> + <div class="thread-box-title"> + <%= category.name %> + </div> + + <div class="box-username"> <%if(user?.admin) {%> + <a class="btn-danger" onclick="fetch('/api/categories/<%= category.id %>/',{method:'DELETE'})"><i class="bx bx-trash bx-sm"></i></a> + <% }; %><%= category.desp %> + </div> + + </div> + </a> + <br> + <% }); %> + + </div> + <% if(typeof page === "number"){ %> + + <div class="pagination"> + <div class="back"> + <% if (page > 0){ %> + <a href="/threads?page=<%= page-1 %>" class='bx bxs-chevron-left'></a> + <% } %> + </div> + + <div class="numbers"> + <% for(let i=0; i < pages; i++){ %> + <a class="number <%= i==page?'active':'' %>" href="/threads?page=<%= i %>"><%= i+1 %></a> + <% } %> + </div> + + <div class="after"> + <% if (pages-1 > page) { %> + <a href="/threads?page=<%= page +1 %>" class='bx bxs-chevron-right'></a> + <% } %> + </div> + + </div> + <% } %> + +</body> \ No newline at end of file diff --git a/views/create_category.ejs b/views/create_category.ejs new file mode 100644 index 0000000..c9e6717 --- /dev/null +++ b/views/create_category.ejs @@ -0,0 +1,38 @@ +<!DOCTYPE html> +<html lang="en"> +<%- include("extra/meta", {title: "Create Category!" }) %> + +<body> + <link rel="stylesheet" href="/css/create_thread.css" /> + + <%- include("extra/navbar") %> + + <form> + <h2 class="title" style="align-self: baseline;">Name:</h2> + <input name="name" class="input"></input> + <h2 class="title" style="align-self: baseline;">Description:</h2> + <textarea rows="4" cols="50" name="desp" class="input"></textarea> + <button class="btn-primary" style="width:100%" type="submit">Create Category!</button> + </form> + + + <script type="module"> + import request from "../../js/request.js"; + + document.addEventListener("submit", async e => { + e.preventDefault(); + const data = new FormData(e.target); + + const response = await request("/api/categories/", "POST", { + name: data.get("name"), + desp: data.get("desp") + }); + + if (response) + window.location.href = "/categories/" + response.id; + + + }); + </script> + +</body> \ No newline at end of file diff --git a/views/create_thread.ejs b/views/create_thread.ejs index 3b23a43..54b3d6b 100644 --- a/views/create_thread.ejs +++ b/views/create_thread.ejs @@ -12,11 +12,13 @@ <form> <h2 class="title" style="align-self: baseline;">Title:</h2> <input name="title" class="input"></input> - - <h2 class="title" style="align-self: baseline;">Content:</h2> <textarea rows="4" cols="50" name="content" class="input"></textarea> - + <select name="category"> + <% for (const category of categories) { %> + <option name="<%= category.id %>" value="<%= category.name %>"><%= category.name %></option> + <% } %> + </select> <button class="btn-primary" style="width:100%" type="submit">Create Thread!</button> </form> @@ -32,7 +34,8 @@ const response = await request("/api/threads/", "POST", { title: data.get("title"), - content: data.get("content") + content: data.get("content"), + categord: data.get("category") }); diff --git a/views/extra/navbar.ejs b/views/extra/navbar.ejs index b40e075..14057f6 100644 --- a/views/extra/navbar.ejs +++ b/views/extra/navbar.ejs @@ -43,6 +43,7 @@ </div> <div class="menu"> <a href="/threads/create/" class="menu-item">Create Thread</a> + <a href="/categories" class="menu-item">Categories</a> <a href="/threads" class="menu-item">Threads</a> <a href="/users" class="menu-item">Users</a> <a href="/search" class="menu-item">Search</a> diff --git a/views/threads.ejs b/views/threads.ejs index 3c9ae23..458c666 100644 --- a/views/threads.ejs +++ b/views/threads.ejs @@ -9,7 +9,8 @@ <link rel="stylesheet" href="/css/pages.css" /> <%- include("extra/navbar") %> - + <h1><%= title || "Threads" %></h1> + <h2><%= desp %></h2> <div class="threads"> <% threads.forEach(thread=>{ %>