Compare commits
3 Commits
e59d3a98f6
...
1d1e2795b0
Author | SHA1 | Date |
---|---|---|
Armored Dragon | 1d1e2795b0 | |
Armored Dragon | 64c49dca11 | |
Armored Dragon | c1c5e5ca1d |
|
@ -80,7 +80,7 @@ async function newUser({ username, password, role } = {}) {
|
|||
// Master user was created; server initialized
|
||||
editSetting({ name: "SETUP_COMPLETE", value: true });
|
||||
}
|
||||
async function getUser({ user_id, username }) {
|
||||
async function getUser({ user_id, username, include_password = false }) {
|
||||
if (!username && !user_id) return _r(false, "Either a user_id or username is needed.");
|
||||
|
||||
let user;
|
||||
|
@ -89,7 +89,11 @@ async function getUser({ user_id, username }) {
|
|||
else if (username) user = await prisma.user.findUnique({ where: { username: username } });
|
||||
|
||||
if (!user) return _r(false, "No matching user");
|
||||
else return { success: true, data: user };
|
||||
|
||||
// Delete the password from responses
|
||||
if (!include_password) delete user.password;
|
||||
|
||||
return { success: true, data: user };
|
||||
}
|
||||
async function editUser({ requester_id, user_id, user_content }) {
|
||||
let user = await getUser({ user_id: user_id });
|
||||
|
@ -120,11 +124,15 @@ async function deleteUser({ user_id }) {
|
|||
|
||||
// Posts
|
||||
async function newPost({ requester_id }) {
|
||||
// const user = await getUser({ id: requester_id });
|
||||
const post = await prisma.post.create({ data: { owner: { connect: { id: requester_id } } } });
|
||||
|
||||
// TODO: Validate request (Does user have perms?)
|
||||
// TODO: Does server allow new posts?
|
||||
|
||||
// Find if user already has a draft
|
||||
let existing_post = await prisma.post.findFirst({ where: { owner: { id: requester_id }, visibility: "DRAFT" } });
|
||||
if (existing_post) return existing_post.id;
|
||||
|
||||
const post = await prisma.post.create({ data: { owner: { connect: { id: requester_id } } } });
|
||||
|
||||
return post.id;
|
||||
}
|
||||
async function getPost({ requester_id, post_id, visibility = "PUBLISHED" } = {}, { search, search_title, search_content, search_tags } = {}, { limit = 10, page = 0, pagination = true } = {}) {
|
||||
|
@ -322,8 +330,8 @@ async function updateBiography({ requester_id, author_id, biography_content }) {
|
|||
}
|
||||
// TODO: Replace
|
||||
async function deleteBlog(blog_id, requester_id) {
|
||||
const user = await getUser({ id: requester_id });
|
||||
const post = await getBlog({ id: blog_id });
|
||||
const user = await getUser({ user_id: requester_id });
|
||||
const post = await getPost({ post_id: blog_id });
|
||||
|
||||
if (!post.success) return { success: false, message: post.message || "Post does not exist" };
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ async function postLogin(req, res) {
|
|||
const { username, password } = req.body; // Get the username and password from the request body
|
||||
|
||||
// Get the user by username
|
||||
const existing_user = await core.getUser({ username: username });
|
||||
const existing_user = await core.getUser({ username: username, include_password: true });
|
||||
if (!existing_user.success) return res.json({ success: false, message: existing_user.message });
|
||||
|
||||
// Check the password
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
const external = require("./core/external_api");
|
||||
const core = require("./core/core");
|
||||
|
||||
function getThemePage(page_name) {
|
||||
function _getThemePage(page_name) {
|
||||
return `themes/${core.settings.theme}/ejs/${page_name}.ejs`;
|
||||
}
|
||||
function getDefaults(req) {
|
||||
async function getDefaults(req) {
|
||||
// TODO: Fix reference to website_name
|
||||
return { logged_in_user: req.session.user, website_name: core.settings.WEBSITE_NAME || "Yet-Another-Blog", settings: core.settings };
|
||||
let user;
|
||||
if (req.session.user) user = await core.getUser({ user_id: req.session.user.id });
|
||||
if (user?.success) user = user.data;
|
||||
return { logged_in_user: user, website_name: core.settings.WEBSITE_NAME || "Yet-Another-Blog", settings: core.settings };
|
||||
}
|
||||
async function index(request, response) {
|
||||
// Check if the master admin has been created
|
||||
|
@ -22,8 +25,8 @@ async function index(request, response) {
|
|||
post.publish_date = formatted_date;
|
||||
});
|
||||
|
||||
response.render(getThemePage("index"), {
|
||||
...getDefaults(request),
|
||||
response.render(_getThemePage("index"), {
|
||||
...(await getDefaults(request)),
|
||||
blog_list: blog_list.data,
|
||||
pagination: blog_list.pagination,
|
||||
current_page: request.query.page || 0,
|
||||
|
@ -31,11 +34,11 @@ async function index(request, response) {
|
|||
tags: tags,
|
||||
});
|
||||
}
|
||||
function register(request, response) {
|
||||
response.render(getThemePage("register"), getDefaults(request));
|
||||
async function register(request, response) {
|
||||
response.render(_getThemePage("register"), await getDefaults(request));
|
||||
}
|
||||
function login(request, response) {
|
||||
response.render(getThemePage("login"), getDefaults(request));
|
||||
async function login(request, response) {
|
||||
response.render(_getThemePage("login"), await getDefaults(request));
|
||||
}
|
||||
async function author(req, res) {
|
||||
const user = await core.getUser({ user_id: req.params.author_id });
|
||||
|
@ -43,15 +46,14 @@ async function author(req, res) {
|
|||
if (!user.success) return res.redirect("/");
|
||||
const profile = await core.getBiography({ author_id: user.data.id });
|
||||
// TODO: Check for success
|
||||
// const posts = await core.getBlog({ owner_id: user.data.id, raw: true });
|
||||
const posts = await core.getPost({ requester_id: user.data.id });
|
||||
|
||||
res.render(getThemePage("author"), { ...getDefaults(req), post: { ...profile.data, post_count: posts.data.length } });
|
||||
res.render(_getThemePage("author"), { ...(await getDefaults(req)), post: { ...profile.data, post_count: posts.data.length } });
|
||||
}
|
||||
async function authorEdit(request, response) {
|
||||
let author = await core.getBiography({ author_id: request.params.author_id });
|
||||
if (!author.success) return response.redirect("/");
|
||||
response.render(getThemePage("authorEdit"), { ...getDefaults(request), profile: author.data });
|
||||
response.render(_getThemePage("authorEdit"), { ...(await getDefaults(request)), profile: author.data });
|
||||
}
|
||||
async function blogList(req, res) {
|
||||
const blog_list = await core.getPost({ requester_id: req.session.user?.id }, { search: req.query.search, search_title: true, search_tags: true, search_content: true });
|
||||
|
@ -62,8 +64,8 @@ async function blogList(req, res) {
|
|||
post.publish_date = formatted_date;
|
||||
});
|
||||
|
||||
res.render(getThemePage("postSearch"), {
|
||||
...getDefaults(req),
|
||||
res.render(_getThemePage("postSearch"), {
|
||||
...(await getDefaults(req)),
|
||||
blog_list: blog_list.data,
|
||||
pagination: blog_list.pagination,
|
||||
current_page: req.query.page || 0,
|
||||
|
@ -73,7 +75,7 @@ async function blogList(req, res) {
|
|||
async function blogSingle(req, res) {
|
||||
const blog = await core.getPost({ post_id: req.params.blog_id });
|
||||
if (blog.success === false) return res.redirect("/");
|
||||
res.render(getThemePage("post"), { ...getDefaults(req), blog_post: blog.data });
|
||||
res.render(_getThemePage("post"), { ...(await getDefaults(req)), blog_post: blog.data });
|
||||
}
|
||||
async function blogNew(request, response) {
|
||||
const new_post = await core.newPost({ requester_id: request.session.user.id });
|
||||
|
@ -81,7 +83,8 @@ async function blogNew(request, response) {
|
|||
}
|
||||
async function blogEdit(req, res) {
|
||||
let existing_blog = await core.getPost({ post_id: req.params.blog_id });
|
||||
if (existing_blog.success) existing_blog = existing_blog.data; // FIXME: Quickfix for .success/.data issue
|
||||
if (!existing_blog.success) return res.redirect("/");
|
||||
existing_blog = existing_blog.data;
|
||||
|
||||
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")}`;
|
||||
|
@ -91,10 +94,10 @@ async function blogEdit(req, res) {
|
|||
const formatted_date = `${published_date_parts[2]}-${published_date_parts[0].padStart(2, "0")}-${published_date_parts[1].padStart(2, "0")}`;
|
||||
existing_blog.publish_date = formatted_date;
|
||||
|
||||
res.render(getThemePage("postNew"), { ...getDefaults(req), existing_blog: existing_blog });
|
||||
res.render(_getThemePage("postNew"), { ...(await getDefaults(req)), existing_blog: existing_blog });
|
||||
}
|
||||
async function admin(request, response) {
|
||||
response.render(getThemePage("admin-settings"), { ...getDefaults(request) });
|
||||
response.render(_getThemePage("admin-settings"), { ...(await getDefaults(request)) });
|
||||
}
|
||||
async function atom(req, res) {
|
||||
res.type("application/xml");
|
||||
|
|
|
@ -1,105 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="stylesheet" type="text/css" href="/css/blogNew.css" />
|
||||
<link rel="stylesheet" type="text/css" href="/css/theme.css" />
|
||||
<script src="/js/generic.js"></script>
|
||||
<title><%= website_name %> | New Blog</title>
|
||||
</head>
|
||||
<body>
|
||||
<%- include("partials/header.ejs", {selected: 'home'}) %>
|
||||
|
||||
<div class="page">
|
||||
<div class="e-header">
|
||||
<div class="e-thumbnail">
|
||||
<%if(existing_blog?.thumbnail) {%>
|
||||
<img src="<%= existing_blog?.thumbnail %>" />
|
||||
<%} else {%>
|
||||
<img src="/img/.dev/square.png" />
|
||||
<% } %>
|
||||
</div>
|
||||
<div class="e-description">
|
||||
<input id="title" type="text" placeholder="Title..." value="<%= existing_blog.title %>" />
|
||||
<textarea id="description" placeholder="Description..."><%= existing_blog.description %></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="e-image-area">
|
||||
<% if(existing_blog.raw_images?.length) { %> <% for (image in existing_blog.raw_images) {%>
|
||||
<div class="image">
|
||||
<img data-image_id="<%=existing_blog.raw_images[image]%>" src="<%= existing_blog.images[image] %>" />
|
||||
<div><a onclick="deleteImage('<%= existing_blog.raw_images[image] %>')">X</a></div>
|
||||
</div>
|
||||
<%}%> <% } else {%>
|
||||
<div class="placeholder">Drop images here</div>
|
||||
<% } %>
|
||||
</div>
|
||||
|
||||
<div class="e-content">
|
||||
<div class="text-actions">
|
||||
<div class="left">
|
||||
<a id="insert-h1"><span>H1</span></a>
|
||||
<a id="insert-h2"><span>H2</span></a>
|
||||
<a id="insert-h3"><span>H3</span></a>
|
||||
<a id="insert-h4"><span>H4</span></a>
|
||||
<a id="insert-underline">
|
||||
<span><u>U</u></span>
|
||||
</a>
|
||||
<a id="insert-italics">
|
||||
<span><i>i</i></span>
|
||||
</a>
|
||||
<a id="insert-bold">
|
||||
<span><strong>B</strong></span>
|
||||
</a>
|
||||
<a id="insert-strike">
|
||||
<span><del>S</del></span>
|
||||
</a>
|
||||
<a id="insert-sup">
|
||||
<span><sup>Sup</sup></span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="right">
|
||||
<a id="insert-sidebyside"><img src="/img/textarea/sidebyside.svg" /></a>
|
||||
<a id="insert-video"><img src="/img/textarea/video.svg" /></a>
|
||||
</div>
|
||||
</div>
|
||||
<textarea id="content" placeholder="Tell us about your subject..."><%= existing_blog.raw_content %></textarea>
|
||||
</div>
|
||||
<div class="e-tags">
|
||||
<input id="tags" type="text" placeholder="Enter a comma separated list of tags" value="<%= existing_blog.tags %>" />
|
||||
</div>
|
||||
<div class="e-settings">
|
||||
<div class="publish-date">
|
||||
<div>Publish On</div>
|
||||
<% if(existing_blog.publish_date) {%>
|
||||
<input id="date" type="date" value="<%= existing_blog.publish_date %>" />
|
||||
<%} else { %>
|
||||
<input id="date" type="date" value="1990-01-01" />
|
||||
<% } %>
|
||||
<!-- -->
|
||||
<% if(existing_blog.publish_date) {%>
|
||||
<input id="time" type="time" value="<%= existing_blog.publish_time %>" />
|
||||
<%} else { %>
|
||||
<input id="time" type="time" value="13:00" />
|
||||
<% } %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="e-settings">
|
||||
<div class="horizontal-buttons">
|
||||
<button onclick="publishBlog(true)" class="yellow"><span>Unlisted</span></button>
|
||||
<% if(existing_blog.id){%>
|
||||
<button onclick="publishBlog(false, true)"><span>Edit</span></button>
|
||||
<% } else {%>
|
||||
<button onclick="publishBlog()"><span>Publish</span></button>
|
||||
<% } %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<%- include("partials/footer.ejs") %>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<script defer src="/js/newBlog.js"></script>
|
|
@ -1,16 +0,0 @@
|
|||
<div class="blog-entry">
|
||||
<a href="/blog/<%= post.id %>" class="thumbnail">
|
||||
<img src="<%= post.thumbnail %>" />
|
||||
</a>
|
||||
<div class="blog-info">
|
||||
<div class="blog-title">
|
||||
<a href="/blog/<%= post.id %>"><%= post.title %> </a>
|
||||
<a href="/author/<%= post.owner.id %>" class="author">By: <%= post.owner.username %></a>
|
||||
</div>
|
||||
<div class="blog-description"><%= post.description %></div>
|
||||
<div class="blog-action">
|
||||
<div class="date"><%= post.publish_date.toLocaleString('en-US', { dateStyle:'medium'}) %></div>
|
||||
<a href="/blog/<%= post.id %>">Read this post -></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -203,6 +203,40 @@ body {
|
|||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.info .info-blip.visibility-flag {
|
||||
margin-left: auto;
|
||||
font-size: 0.9rem;
|
||||
display: flex;
|
||||
padding: 0 0.5rem;
|
||||
border-radius: 5px;
|
||||
border: 2px solid;
|
||||
}
|
||||
.info .info-blip.visibility-flag span {
|
||||
margin: auto;
|
||||
color: black;
|
||||
}
|
||||
.info .visibility-flag.published {
|
||||
border-color: #21b525;
|
||||
background-color: #a0ffa0;
|
||||
}
|
||||
.info .visibility-flag.unlisted {
|
||||
border-color: #bec10f;
|
||||
background-color: #e8ffa0;
|
||||
}
|
||||
.info .visibility-flag.private {
|
||||
border-color: #c10f0f;
|
||||
background-color: #ffd7d7;
|
||||
}
|
||||
.info .visibility-flag.draft {
|
||||
border-color: black;
|
||||
background-color: rgba(0, 0, 0, 0.0588235294);
|
||||
}
|
||||
.info .visibility-flag.scheduled {
|
||||
border-color: #0f77c1;
|
||||
background-color: #d7e9ff;
|
||||
margin-left: inherit;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1280px) {
|
||||
.page-center {
|
||||
width: 95%;
|
||||
|
|
|
@ -217,7 +217,47 @@ body {
|
|||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
.info {
|
||||
.info-blip.visibility-flag {
|
||||
margin-left: auto;
|
||||
font-size: 0.9rem;
|
||||
display: flex;
|
||||
padding: 0 0.5rem;
|
||||
border-radius: 5px;
|
||||
border: 2px solid;
|
||||
|
||||
span {
|
||||
margin: auto;
|
||||
color: black;
|
||||
}
|
||||
}
|
||||
|
||||
.visibility-flag.published {
|
||||
border-color: #21b525;
|
||||
background-color: #a0ffa0;
|
||||
}
|
||||
|
||||
.visibility-flag.unlisted {
|
||||
border-color: #bec10f;
|
||||
background-color: #e8ffa0;
|
||||
}
|
||||
|
||||
.visibility-flag.private {
|
||||
border-color: #c10f0f;
|
||||
background-color: #ffd7d7;
|
||||
}
|
||||
|
||||
.visibility-flag.draft {
|
||||
border-color: black;
|
||||
background-color: #0000000f;
|
||||
}
|
||||
|
||||
.visibility-flag.scheduled {
|
||||
border-color: #0f77c1;
|
||||
background-color: #d7e9ff;
|
||||
margin-left: inherit;
|
||||
}
|
||||
}
|
||||
@media screen and (max-width: 1280px) {
|
||||
.page-center {
|
||||
width: 95%;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
<a href="/posts">
|
||||
<span>Posts</span>
|
||||
</a>
|
||||
<!-- -->
|
||||
<% if (logged_in_user) { %>
|
||||
<a href="/author/<%= logged_in_user.id %>">
|
||||
<span>Account</span>
|
||||
|
@ -18,6 +19,12 @@
|
|||
<span>Login</span>
|
||||
</a>
|
||||
<% } %> <% } %>
|
||||
<!-- -->
|
||||
<% if (logged_in_user?.role == 'ADMIN') { %>
|
||||
<a href="/admin">
|
||||
<span>Admin</span>
|
||||
</a>
|
||||
<% } %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -4,8 +4,17 @@
|
|||
<div class="description"><%= post.description %></div>
|
||||
<div class="badges">
|
||||
<div class="info">
|
||||
<div class="info-blip icon publish-date"><%= post.publish_date ? post.publish_date.toLocaleString('en-US', { dateStyle:'medium'}) : "Null" %></div>
|
||||
<div class="info-blip icon publish-date"><%= post.publish_date ? post.publish_date.toLocaleString('en-US', { dateStyle:'medium'}) : "Unknown Publish Date" %></div>
|
||||
<div class="info-blip icon reading-time">Null minute read</div>
|
||||
<% if (logged_in_user) { %>
|
||||
<!-- -->
|
||||
<div class="info-blip visibility-flag <%= post.visibility.toLowerCase() %>"><span><%= post.visibility %></span></div>
|
||||
<!-- -->
|
||||
<% if (new Date(post.publish_date) > new Date() && post.visibility !== 'PRIVATE') {%>
|
||||
<div class="info-blip visibility-flag scheduled"><span>Scheduled</span></div>
|
||||
<% } %>
|
||||
<!-- -->
|
||||
<% } %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -30,7 +30,7 @@ model Post {
|
|||
description String?
|
||||
content String?
|
||||
media String[]
|
||||
visibility PostStatus @default(UNLISTED)
|
||||
visibility PostStatus @default(DRAFT)
|
||||
owner User? @relation(fields: [ownerid], references: [id], onDelete: Cascade)
|
||||
ownerid String?
|
||||
|
||||
|
@ -38,7 +38,7 @@ model Post {
|
|||
tags Tag[]
|
||||
|
||||
// Dates
|
||||
publish_date DateTime?
|
||||
publish_date DateTime? @default(now())
|
||||
created_date DateTime @default(now())
|
||||
}
|
||||
|
||||
|
@ -81,6 +81,7 @@ enum Role {
|
|||
}
|
||||
|
||||
enum PostStatus {
|
||||
DRAFT
|
||||
PRIVATE
|
||||
UNLISTED
|
||||
PUBLISHED
|
||||
|
|
Loading…
Reference in New Issue