Added search

This commit is contained in:
Akif9748 2022-09-01 16:23:46 +03:00
parent 0358e9e5a2
commit 5b2399bec5
11 changed files with 183 additions and 26 deletions

View file

@ -31,31 +31,17 @@ Akf-forum has got an API for AJAX (fetch), other clients etc. And, you can learn
<img src="https://user-images.githubusercontent.com/70021050/187901065-fd75ef85-56e3-42ce-8b34-cb8d799a6517.png"></img> <img src="https://user-images.githubusercontent.com/70021050/187901065-fd75ef85-56e3-42ce-8b34-cb8d799a6517.png"></img>
</details> </details>
## Roadmap ## TO-DO list
### TO-DO:
| To do | Is done? | Priority | | To do | Is done? | Priority |
| ----- | -------- | -------- | | ----- | -------- | -------- |
| Profile Message | 🔴 | LOW | | Search & message a | 🟡 | MEDIUM |
| Search | 🔴 | MEDIUM |
| Footer | 🟡 | LOW | | Footer | 🟡 | LOW |
| Better Auth | 🔴 | MEDIUM |
| Local pfp store | 🔴 | MEDIUM | | Local pfp store | 🔴 | MEDIUM |
| IPs of users will add SecretModel | 🔴 | MEDIUM | | IPs of users will add SecretModel | 🔴 | MEDIUM |
| better theme patch UserModel | 🟡 | VERY LOW |
- message counts for API | Category | ⚪ | MEDIUM |
- better theme patch UserModel | Profile Message | 🔴 | LOW |
- ajax, delete update thread dom | Better Auth | 🔴 | MEDIUM |
### API
| To do | Is done?
| ----- | --------
| RATELIMITS | 🟢
| Get a lots of message & thread & user | 🔴
| Create message & thread & user | 🟢
| Get message & thread & user | 🟢
| Delete message & thread & user | 🟢
| Undelete message & thread & user | 🟢
| Edit message & thread & user | 🟢
## Major Version History ## Major Version History
- V4: Caching - V4: Caching

34
public/css/messages.css Normal file
View file

@ -0,0 +1,34 @@
.date {
color: var(--second);
}
.message {
max-width: 800px;
box-shadow: 0 0 5px 0 var(--box-shadow);
margin: 10px auto;
padding: 20px;
display: flex;
gap: 10px;
position: relative;
}
.message .left {
text-align: center;
border-right: 2px solid var(--borders);
}
.message .left img {
width: 100px;
height: 100px;
border-radius: 50%;
margin-right: 5px;
}
.message .left .username a {
color: var(--t-username);
}
.content {
width: 70%;
color: var(--reaction-hover);
}

3
public/css/search.css Normal file
View file

@ -0,0 +1,3 @@
.search {
padding: 10px;
}

View file

@ -0,0 +1,28 @@
const { Router } = require("express")
const { MessageModel, ThreadModel, UserModel } = require("../../../models");
const app = Router();
app.get("/users", async (req, res) => {
if (!req.query.q) return res.error(400, "Missing query parameter 'q' in request body.");
const results = await UserModel.find({ name: { $regex: req.query.q, $options: "i" } }).limit(10);
res.complate(results);
});
app.get("/messages", async (req, res) => {
if (!Object.values(req.query).length) return res.error(400, "Missing query parameters in request body.");
const query = {};
if (req.query.q) query.content = { $regex: req.query.q, $options: "i" };
if (req.query.authorID) query.authorID = req.query.authorID;
const results = await MessageModel.find(query).limit(10);
res.complate(results);
});
app.get("/threads", async (req, res) => {
if (!Object.values(req.query).length) return res.error(400, "Missing query parameters in request body.");
const query = {};
if (req.query.q) query.title = { $regex: req.query.q, $options: "i" };
if (req.query.authorID) query.authorID = req.query.authorID;
const results = await ThreadModel.find(query).limit(10);
res.complate(results);
});
module.exports = app;

31
routes/search.js Normal file
View file

@ -0,0 +1,31 @@
const { UserModel, ThreadModel, MessageModel } = require("../models")
const { Router } = require("express");
const app = Router();
app.get("/", (req, res) => res.reply("search"));
app.get("/users", async (req, res) => {
if (!req.query.q) return res.error(400, "Missing query parameter 'q' in request body.");
const users = await UserModel.find({ name: { $regex: req.query.q, $options: "i" } }).limit(10);
res.reply("users", { users, page: null });
});
app.get("/messages", async (req, res) => {
if (!Object.values(req.query).length) return res.error(400, "Missing query parameters in request body.");
const query = {};
if (req.query.q) query.content = { $regex: req.query.q, $options: "i" };
if (req.query.authorID) query.authorID = req.query.authorID;
const messages = await MessageModel.find(query).limit(10);
res.reply("messages",{messages});
});
app.get("/threads", async (req, res) => {
if (!Object.values(req.query).length) return res.error(400, "Missing query parameters in request body.");
const query = {};
if (req.query.q) query.title = { $regex: req.query.q, $options: "i" };
if (req.query.authorID) query.authorID = req.query.authorID;
const threads = await ThreadModel.find(query).limit(10);
res.reply("threads", { threads, page: null });
});
module.exports = app;

View file

@ -20,7 +20,7 @@
<a id="logout" href="/login" class="btn-primary">Logout</a> <a id="logout" href="/login" class="btn-primary">Logout</a>
<a onclick="invert()" class="btn-outline-primary"><%=(user.theme === "default" ? "black" : "default" ) + " mode" %></a> <a onclick="invert()" class="btn-outline-primary"><%=(user.theme === "default" ? "black" : "default" ) + " mode" %></a>
<script> <script>
async function invert() { async function invert() {
await fetch('/api/users/<%= user.id %>', { await fetch('/api/users/<%= user.id %>', {
method: 'PATCH', method: 'PATCH',
body: JSON.stringify({ body: JSON.stringify({
@ -31,7 +31,7 @@
} }
}) })
location.reload() location.reload()
} }
</script> </script>
<% } else { %> <% } else { %>
@ -45,15 +45,17 @@
</div> </div>
</div> </div>
<div class="menu"> <div class="menu">
<a href="/threads/create/" class="menu-item">Create Thread</a>
<a href="/threads" class="menu-item">Threads</a> <a href="/threads" class="menu-item">Threads</a>
<a href="/users" class="menu-item">Users</a> <a href="/users" class="menu-item">Users</a>
<a href="/search" class="menu-item">Search</a> <a href="/search" class="menu-item">Search</a>
<a href="/threads/create/" class="menu-item">Create Thread</a>
<script> <script>
const menuItems = document.getElementsByClassName("menu-item"); const menuItems = document.getElementsByClassName("menu-item");
for (let i = 0; i < menuItems.length; i++) for (let i = 0; i < menuItems.length; i++)
if (menuItems[i].getAttribute("href") == window.location.pathname) if (window.location.pathname.includes(menuItems[i].getAttribute("href"))) {
menuItems[i].classList.add("active-menu"); menuItems[i].classList.add("active-menu");
break;
}
</script> </script>
</div> </div>

33
views/messages.ejs Normal file
View file

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html lang="en">
<%- include("extra/meta", {title:"Message search!" }) %>
<body style="text-align: center;">
<%- include("extra/navbar") %>
<link rel="stylesheet" href="/css/messages.css" />
<div id="messages">
<% messages.filter(Boolean).forEach(message=>{ %>
<div class="message" id="message-<%= message.id %>">
<div class="left">
<img src="<%= message.author.avatar || '/images/guest.png' %>" />
<div class="username"><a href="/users/<%=message.authorID %>"><%=message.author.name %></a></div>
<div class="date">
<%= new Date(message.time).toLocaleDateString() %>
</div>
<div class="date">
<%= new Date(message.time).toLocaleTimeString() %>
</div>
</div>
<div class="content"><%- message.content %></div>
</div>
<% }); %>
</div>
</body>
</html>

35
views/search.ejs Normal file
View file

@ -0,0 +1,35 @@
<!DOCTYPE html>
<html lang="en">
<%- include("extra/meta", {title: "Search page!" }) %>
<body style="text-align: center;">
<%- include("extra/navbar") %>
<link rel="stylesheet" href="/css/search.css" />
<div id="search">
<form action="/search/users" method="GET">
<input type="text" name="q" placeholder="Search for users" />
<input type="submit" value="Search" />
</form>
</div>
<div id="search">
<form action="/search/messages" method="GET">
<input type="text" name="q" placeholder="Search for messages" />
<input type="text" name="authorID" placeholder="(Not Required) Author id" />
<input type="submit" value="Search" />
</form>
</div>
<div id="search">
<form action="/search/threads" method="GET">
<input type="text" name="q" placeholder="Search for threads" />
<input type="text" name="authorID" placeholder="(Not Required) Author id" />
<input type="submit" value="Search" />
</form>
</div>
</body>
</html>

View file

@ -25,8 +25,6 @@
</div> </div>
</div> </div>
<div style="text-align:center;padding:8px"> <div style="text-align:center;padding:8px">
<!-- THREAD AUTHOR AND PROFILE PHOTO -->
<% if (user && !thread.deleted){ %> <% if (user && !thread.deleted){ %>
<a onclick="delete_thread('<%= thread.id %>')" class="btn-outline-primary">DELETE</a> <a onclick="delete_thread('<%= thread.id %>')" class="btn-outline-primary">DELETE</a>

View file

@ -33,6 +33,8 @@
<% }); %> <% }); %>
</div> </div>
<% if(typeof page === "number"){ %>
<div class="pagination"> <div class="pagination">
<div class="back"> <div class="back">
<% if (page > 0){ %> <% if (page > 0){ %>
@ -53,4 +55,6 @@
</div> </div>
</div> </div>
<% } %>
</body> </body>

View file

@ -24,6 +24,7 @@
<% }); %> <% }); %>
</div> </div>
<% if(typeof page === "number"){ %>
<div class="pagination"> <div class="pagination">
<div class="back"> <div class="back">
<% if (page > 0){ %> <% if (page > 0){ %>
@ -44,4 +45,6 @@
</div> </div>
</div> </div>
<% } %>
</body> </body>