Post searching (#8)
Ability to search for posts Reviewed-on: #8 Co-authored-by: Armored-Dragon <forgejo3829105@armoreddragon.com> Co-committed-by: Armored-Dragon <forgejo3829105@armoreddragon.com>pull/2/head
parent
5ac2196d00
commit
d24f87e23a
|
@ -73,7 +73,83 @@ async function registerUser(username, password, options) {
|
|||
// User has been successfully created
|
||||
return { success: true, message: `Successfully created ${username}` };
|
||||
}
|
||||
// Posts
|
||||
async function getBlog({ id, visibility = "PUBLISHED", owner_id, limit = 10, page = 0, tags = [], search_title = false, search_content = false, search }) {
|
||||
// If we have an ID, we want a single post
|
||||
if (id) {
|
||||
// Get the post by the id
|
||||
let post = await prisma.blogPost.findUnique({ where: { id: id }, include: { owner: true } });
|
||||
if (!post) return { success: false, message: "Post does not exist" };
|
||||
|
||||
// Render the post
|
||||
const rendered_post = await _renderPost(post, true);
|
||||
|
||||
// Return the post with valid image urls
|
||||
return { data: rendered_post, success: true };
|
||||
}
|
||||
// Otherwise build WHERE_OBJECT using data we do have
|
||||
let rendered_post_list = [];
|
||||
let where_object = {
|
||||
OR: [
|
||||
// Standard discovery: Public, and after the publish date
|
||||
{
|
||||
AND: [
|
||||
{
|
||||
visibility: "PUBLISHED",
|
||||
},
|
||||
{
|
||||
publish_date: {
|
||||
lte: new Date(),
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// User owns the post
|
||||
{
|
||||
ownerid: owner_id,
|
||||
},
|
||||
],
|
||||
AND: [],
|
||||
};
|
||||
|
||||
// Build the "where_object" object
|
||||
if (tags.length > 0) {
|
||||
}
|
||||
if (search_title) where_object["AND"].push({ title: { contains: search, mode: "insensitive" } });
|
||||
if (search_content) where_object["AND"].push({ content: { contains: search, mode: "insensitive" } });
|
||||
|
||||
// Execute search
|
||||
const blog_posts = await prisma.blogPost.findMany({
|
||||
where: where_object,
|
||||
take: limit,
|
||||
skip: Math.max(page, 0) * limit,
|
||||
include: { owner: true },
|
||||
orderBy: [{ publish_date: "desc" }, { created_date: "desc" }],
|
||||
});
|
||||
|
||||
// Render each of the posts in the list
|
||||
for (post of blog_posts) {
|
||||
rendered_post_list.push(await _renderPost(post, true));
|
||||
}
|
||||
// Calculate pagination
|
||||
let pagination = await prisma.blogPost.count({
|
||||
where: where_object,
|
||||
});
|
||||
return { data: rendered_post_list, pagination: _getNavigationList(page, Math.ceil(pagination / limit)), success: true };
|
||||
}
|
||||
async function getAuthorPage({ author_id }) {
|
||||
// Get the post by the id
|
||||
|
||||
let post = await prisma.profilePage.findUnique({ where: { ownerid: author_id }, include: { owner: true } });
|
||||
if (!post) return { success: false, message: "Post does not exist" };
|
||||
|
||||
// Render the post
|
||||
const rendered_post = await _renderPost(post, true);
|
||||
|
||||
// Return the post with valid image urls
|
||||
return { data: rendered_post, success: true };
|
||||
}
|
||||
async function getUser({ id, username } = {}) {
|
||||
let user;
|
||||
if (id) user = await prisma.user.findUnique({ where: { id: id } });
|
||||
|
@ -127,7 +203,7 @@ async function postBlog(blog_post, owner_id) {
|
|||
}
|
||||
async function deleteBlog(blog_id, requester_id) {
|
||||
const user = await getUser({ id: requester_id });
|
||||
const post = await getBlog({ id: blog_id });
|
||||
const post = await getPost({ id: blog_id });
|
||||
|
||||
let can_delete = post.owner.id === user.data.id || user.data.role === "ADMIN";
|
||||
|
||||
|
@ -141,7 +217,7 @@ async function deleteBlog(blog_id, requester_id) {
|
|||
}
|
||||
async function updateBlog(blog_post, requester_id) {
|
||||
const user = await getUser({ id: requester_id });
|
||||
const post = await getBlog({ id: blog_post.id, raw: true });
|
||||
const post = await getPost({ id: blog_post.id, raw: true });
|
||||
|
||||
delete blog_post.id;
|
||||
|
||||
|
@ -192,66 +268,9 @@ async function updateBlog(blog_post, requester_id) {
|
|||
|
||||
return { success: true };
|
||||
}
|
||||
async function getBlog({ id, visibility = "PUBLISHED", owner_id, limit = 10, page = 0 } = {}) {
|
||||
if (id) {
|
||||
// Get the database entry for the blog post
|
||||
let post = await prisma.blogPost.findUnique({ where: { id: id }, include: { owner: true } });
|
||||
if (!post) return { success: false, message: "Post does not exist" };
|
||||
|
||||
// Render the post
|
||||
const rendered_post = _renderPost(post, true);
|
||||
|
||||
// Return the post with valid image urls
|
||||
return rendered_post;
|
||||
}
|
||||
|
||||
let rendered_post_list = [];
|
||||
|
||||
const where_object = {
|
||||
OR: [
|
||||
// Standard discovery: Public, and after the publish date
|
||||
{
|
||||
AND: [
|
||||
{
|
||||
visibility: "PUBLISHED",
|
||||
},
|
||||
{
|
||||
publish_date: {
|
||||
lte: new Date(),
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// User owns the post
|
||||
{
|
||||
ownerid: owner_id,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const blog_posts = await prisma.blogPost.findMany({
|
||||
where: where_object,
|
||||
take: limit,
|
||||
skip: Math.max(page, 0) * limit,
|
||||
include: { owner: true },
|
||||
orderBy: [{ publish_date: "desc" }, { created_date: "desc" }],
|
||||
});
|
||||
|
||||
// Render each of the posts in the list
|
||||
for (blog_post of blog_posts) {
|
||||
rendered_post_list.push(await _renderPost(blog_post, true));
|
||||
}
|
||||
|
||||
// Calculate pagination
|
||||
let pagination = await prisma.blogPost.count({
|
||||
where: where_object,
|
||||
});
|
||||
return { data: rendered_post_list, pagination: _getNavigationList(page, Math.ceil(pagination / limit)) };
|
||||
}
|
||||
async function deleteImage(image, requester_id) {
|
||||
const user = await getUser({ id: requester_id });
|
||||
const post = await getBlog({ id: image.parent, raw: true });
|
||||
const post = await getPost({ id: image.parent, raw: true });
|
||||
|
||||
// Check if post exists
|
||||
if (!post) return { success: false, message: "Post does not exist" };
|
||||
|
@ -461,4 +480,4 @@ async function postSetting(key, value) {
|
|||
async function _getGroups() {
|
||||
const group_list = await prisma.group.findMany();
|
||||
}
|
||||
module.exports = { registerUser, getUser, postBlog, updateBlog, getBlogList: getBlog, deleteBlog, deleteImage, postSetting, getSetting, settings };
|
||||
module.exports = { settings, registerUser, getUser, getAuthorPage, postBlog, updateBlog, getBlog, deleteBlog, deleteImage, postSetting, getSetting };
|
||||
|
|
|
@ -8,7 +8,6 @@ function getDefaults(req) {
|
|||
|
||||
async function index(request, response) {
|
||||
// Check if the master admin has been created
|
||||
|
||||
const is_setup_complete = core.settings["SETUP_COMPLETE"];
|
||||
if (!is_setup_complete) return response.redirect("/register");
|
||||
|
||||
|
@ -20,11 +19,15 @@ function register(request, response) {
|
|||
function login(request, response) {
|
||||
response.render("login.ejs", getDefaults(request));
|
||||
}
|
||||
function author(request, response) {
|
||||
response.render("author.ejs", getDefaults(request));
|
||||
async function author(req, res) {
|
||||
const user = await core.getUser({ id: req.params.author_id });
|
||||
// FIXME: Bandage fix for author get error
|
||||
if (!user.success) return res.redirect("/");
|
||||
const profile = await core.getAuthorPage({ author_id: user.data.id });
|
||||
res.render("author.ejs", { ...getDefaults(req), blog_post: profile.data });
|
||||
}
|
||||
async function blogList(req, res) {
|
||||
const blog_list = await core.getBlogList({ owner_id: req.session.user?.id, page: req.query.page || 0 });
|
||||
const blog_list = await core.getBlog({ owner_id: req.session.user?.id, page: req.query.page || 0, search: req.query.search, search_title: true });
|
||||
res.render("blogList.ejs", {
|
||||
...getDefaults(req),
|
||||
blog_list: blog_list.data,
|
||||
|
@ -34,9 +37,9 @@ async function blogList(req, res) {
|
|||
});
|
||||
}
|
||||
async function blogSingle(req, res) {
|
||||
const blog = await core.getBlogList({ id: req.params.blog_id });
|
||||
const blog = await core.getBlog({ id: req.params.blog_id });
|
||||
if (blog.success === false) return res.redirect("/blog");
|
||||
res.render("blogSingle.ejs", { ...getDefaults(req), blog_post: blog });
|
||||
res.render("blogSingle.ejs", { ...getDefaults(req), blog_post: blog.data });
|
||||
}
|
||||
function blogNew(request, response) {
|
||||
// TODO: Turn date formatting into function
|
||||
|
@ -52,7 +55,8 @@ function blogNew(request, response) {
|
|||
response.render("blogNew.ejs", { ...getDefaults(request), existing_blog: existing_blog });
|
||||
}
|
||||
async function blogEdit(req, res) {
|
||||
const existing_blog = await core.getBlogList({ id: req.params.blog_id, raw: true });
|
||||
let existing_blog = await core.getBlog({ id: req.params.blog_id, raw: true });
|
||||
if (existing_blog.success) existing_blog = existing_blog.data; // FIXME: Quickfix for .success/.data issue
|
||||
|
||||
let published_time_parts = new Date(existing_blog.publish_date).toLocaleTimeString([], { timeStyle: "short" }).slice(0, 4).split(":");
|
||||
const formatted_time = `${published_time_parts[0].padStart(2, "0")}:${published_time_parts[1].padStart(2, "0")}`;
|
||||
|
|
|
@ -14,6 +14,30 @@
|
|||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.search-area {
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
.search-area input {
|
||||
width: 50%;
|
||||
background-color: black;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
border-radius: 5px;
|
||||
color: white;
|
||||
height: 100%;
|
||||
text-indent: 5px;
|
||||
margin: 0 10px 0 auto;
|
||||
}
|
||||
.search-area button {
|
||||
height: 100%;
|
||||
min-width: 100px;
|
||||
margin: 0 auto 0 0;
|
||||
}
|
||||
|
||||
.blog-entry {
|
||||
width: 100%;
|
||||
display: grid;
|
||||
|
@ -79,6 +103,20 @@
|
|||
}
|
||||
|
||||
@media screen and (max-width: 500px) {
|
||||
.search-area {
|
||||
height: 60px;
|
||||
flex-direction: column;
|
||||
}
|
||||
.search-area input {
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
margin: 0;
|
||||
}
|
||||
.search-area button {
|
||||
height: 30px;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
.page .blog-entry {
|
||||
grid-template-columns: 75px auto;
|
||||
margin-bottom: 20px;
|
||||
|
|
|
@ -19,6 +19,32 @@ $quiet-text: #9f9f9f;
|
|||
}
|
||||
}
|
||||
|
||||
.search-area {
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
margin-bottom: 10px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
input {
|
||||
width: 50%;
|
||||
background-color: black;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
border-radius: 5px;
|
||||
color: white;
|
||||
height: 100%;
|
||||
text-indent: 5px;
|
||||
margin: 0 10px 0 auto;
|
||||
}
|
||||
|
||||
button {
|
||||
height: 100%;
|
||||
min-width: 100px;
|
||||
margin: 0 auto 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
.blog-entry {
|
||||
width: 100%;
|
||||
display: grid;
|
||||
|
@ -89,6 +115,20 @@ $quiet-text: #9f9f9f;
|
|||
}
|
||||
|
||||
@media screen and (max-width: 500px) {
|
||||
.search-area {
|
||||
height: 60px;
|
||||
flex-direction: column;
|
||||
input {
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
margin: 0;
|
||||
}
|
||||
button {
|
||||
height: 30px;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
.page {
|
||||
.blog-entry {
|
||||
grid-template-columns: 75px auto;
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
qs("#search-btn").addEventListener("click", search);
|
||||
|
||||
function search() {
|
||||
const url_query = `search=${qs("input").value}`;
|
||||
window.location.href = `${window.location.origin}${window.location.pathname}?${url_query}`;
|
||||
}
|
|
@ -14,6 +14,10 @@
|
|||
|
||||
<div class="page">
|
||||
<%if(logged_in_user) {%> <%- include("partials/blog-admin.ejs") %> <%}%>
|
||||
<!-- Search area -->
|
||||
<div class="search-area">
|
||||
<input type="text" placeholder="Search..." /><button id="search-btn"><span>Search</span></button>
|
||||
</div>
|
||||
<!-- -->
|
||||
<% for(post of blog_list) { %>
|
||||
<!-- -->
|
||||
|
@ -25,3 +29,5 @@
|
|||
<%- include("partials/footer.ejs") %>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<script defer src="/js/postList.js"></script>
|
||||
|
|
2
yab.js
2
yab.js
|
@ -39,7 +39,7 @@ app.patch("/api/web/blog", checkAuthenticated, internal.patchBlog);
|
|||
app.get("/", page_scripts.index);
|
||||
app.get("/login", page_scripts.login);
|
||||
app.get("/register", checkNotAuthenticated, page_scripts.register);
|
||||
app.get("/author/:author_username", page_scripts.author);
|
||||
app.get("/author/:author_id", page_scripts.author);
|
||||
app.get("/admin", checkAuthenticated, page_scripts.admin);
|
||||
app.get("/blog", page_scripts.blogList);
|
||||
app.get("/blog/new", checkAuthenticated, page_scripts.blogNew);
|
||||
|
|
Loading…
Reference in New Issue