mirror of
https://github.com/Akif9748/akf-forum.git
synced 2024-12-22 23:59:08 +03:00
Added search
This commit is contained in:
parent
0358e9e5a2
commit
5b2399bec5
11 changed files with 183 additions and 26 deletions
26
README.md
26
README.md
|
@ -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>
|
||||
</details>
|
||||
|
||||
## Roadmap
|
||||
### TO-DO:
|
||||
## TO-DO list
|
||||
| To do | Is done? | Priority |
|
||||
| ----- | -------- | -------- |
|
||||
| Profile Message | 🔴 | LOW |
|
||||
| Search | 🔴 | MEDIUM |
|
||||
| Search & message a | 🟡 | MEDIUM |
|
||||
| Footer | 🟡 | LOW |
|
||||
| Better Auth | 🔴 | MEDIUM |
|
||||
| Local pfp store | 🔴 | MEDIUM |
|
||||
| IPs of users will add SecretModel | 🔴 | MEDIUM |
|
||||
|
||||
- message counts for API
|
||||
- better theme patch UserModel
|
||||
- ajax, delete update thread dom
|
||||
|
||||
### 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 | 🟢
|
||||
| better theme patch UserModel | 🟡 | VERY LOW |
|
||||
| Category | ⚪ | MEDIUM |
|
||||
| Profile Message | 🔴 | LOW |
|
||||
| Better Auth | 🔴 | MEDIUM |
|
||||
|
||||
## Major Version History
|
||||
- V4: Caching
|
||||
|
|
34
public/css/messages.css
Normal file
34
public/css/messages.css
Normal 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
3
public/css/search.css
Normal file
|
@ -0,0 +1,3 @@
|
|||
.search {
|
||||
padding: 10px;
|
||||
}
|
28
routes/api/routes/search.js
Normal file
28
routes/api/routes/search.js
Normal 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
31
routes/search.js
Normal 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;
|
||||
|
|
@ -20,7 +20,7 @@
|
|||
<a id="logout" href="/login" class="btn-primary">Logout</a>
|
||||
<a onclick="invert()" class="btn-outline-primary"><%=(user.theme === "default" ? "black" : "default" ) + " mode" %></a>
|
||||
<script>
|
||||
async function invert() {
|
||||
async function invert() {
|
||||
await fetch('/api/users/<%= user.id %>', {
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify({
|
||||
|
@ -31,7 +31,7 @@
|
|||
}
|
||||
})
|
||||
location.reload()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<% } else { %>
|
||||
|
||||
|
@ -45,15 +45,17 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="menu">
|
||||
<a href="/threads/create/" class="menu-item">Create Thread</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>
|
||||
<a href="/threads/create/" class="menu-item">Create Thread</a>
|
||||
<script>
|
||||
const menuItems = document.getElementsByClassName("menu-item");
|
||||
|
||||
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");
|
||||
break;
|
||||
}
|
||||
</script>
|
||||
</div>
|
33
views/messages.ejs
Normal file
33
views/messages.ejs
Normal 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
35
views/search.ejs
Normal 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>
|
|
@ -25,8 +25,6 @@
|
|||
</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>
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
<% }); %>
|
||||
|
||||
</div>
|
||||
<% if(typeof page === "number"){ %>
|
||||
|
||||
<div class="pagination">
|
||||
<div class="back">
|
||||
<% if (page > 0){ %>
|
||||
|
@ -53,4 +55,6 @@
|
|||
</div>
|
||||
|
||||
</div>
|
||||
<% } %>
|
||||
|
||||
</body>
|
|
@ -24,6 +24,7 @@
|
|||
<% }); %>
|
||||
|
||||
</div>
|
||||
<% if(typeof page === "number"){ %>
|
||||
<div class="pagination">
|
||||
<div class="back">
|
||||
<% if (page > 0){ %>
|
||||
|
@ -44,4 +45,6 @@
|
|||
</div>
|
||||
|
||||
</div>
|
||||
<% } %>
|
||||
|
||||
</body>
|
Loading…
Reference in a new issue