Update 2024 #1

Open
mtrx wants to merge 11 commits from update-2024 into main
12 changed files with 164 additions and 235 deletions
Showing only changes of commit 7fe997acff - Show all commits

View file

@ -29,18 +29,18 @@ All configuration options are defined in .env which should be placed in the path
`.env` `.env`
``` ```
USERNAME=yourusername CL_USERNAME=yourusername
EMAIL=me@mydomain.tld # optional CL_EMAIL=me@mydomain.tld # optional
BIND_PORT=8000 # optional CL_BIND_PORT=8000 # optional
SUBMIT_TOKEN=Submit!123 # required, token needed for submitting CL_SUBMIT_TOKEN=Submit!123 # required, token needed for submitting
GITHUB_ACCOUNT=yourusername # optional CL_GITHUB_ACCOUNT=yourusername # optional
TWITTER_ACCOUNT=yourusername # optional CL_TWITTER_ACCOUNT=yourusername # optional
MASTODON_ACCOUNT=yourusername@mastodon.social # optional CL_MASTODON_ACCOUNT=yourusername@mastodon.social # optional
REDDIT_ACCOUNT=yourusername # optional CL_REDDIT_ACCOUNT=yourusername # optional
DISCORD_ACCOUNT=yourusername # optional CL_DISCORD_ACCOUNT=yourusername # optional
# only needed when not using a docker container # only needed when not using a docker container
ROOT_PATH=/path/to/template/directory/and/sqliteDB CL_ROOT_PATH=/path/to/template/directory/and/sqliteDB
``` ```
## Routes ## Routes

View file

@ -10,13 +10,18 @@ html {
padding-left: 20%; padding-left: 20%;
} }
img { .social-icon {
height: 1rem;
width: 1rem;
}
.post-img {
width: 50%; width: 50%;
padding: 20px 0px 20px 0px; padding: 20px 0px 20px 0px;
} }
article { article {
padding-top: 2em; padding-top: 2rem;
display: flex; display: flex;
} }
@ -29,20 +34,21 @@ article {
} }
.post-publish-date { .post-publish-date {
font-size: 0.7em; font-size: 0.7rem;
} }
.post-body { .post-body {
padding-top: 1em; padding-top: 1rem;
} }
#submit-form { #submit-form {
padding-top: 2em; padding-top: 2rem;
} }
#submit-body, #submit-title { #submit-body,
#submit-title {
width: 100%; width: 100%;
margin-bottom: 2em; margin-bottom: 2rem;
resize: none; resize: none;
} }

View file

@ -1,24 +0,0 @@
* {
margin: 0;
padding: 0;
}
html {
font-family: sans-serif;
padding: 20px;
width: 60%;
padding-left: 20%;
}
.social-icon {
height: 1em;
width: 1em;
}
@media (max-width:1080px) {
html {
font-family: sans-serif;
padding: 20px;
width: 90%;
padding-left: 5%;
}

View file

@ -1,35 +0,0 @@
function setTokenCookie() {
let token = document.getElementById('set-token').value;
let tokenCookie = 'token=' + token + "; SameSite=None; secure";
document.cookie = tokenCookie;
setFormTokens(token);
document.getElementById("cookie-block").hidden = true;
}
function clearTokenCookie() {
document.cookie = "token=; expires=Thu, 01 Jan 1970 00:00:00 UTC; SameSite=None; secure";
document.getElementById("cookie-block").hidden = false;
}
function setFormTokens(token) {
let tokenFields = document.querySelectorAll(".token");
for (t of tokenFields) {
t.value = token;
}
}
// if cookie is set, use it to pass the token
let c_pairs = document.cookie.split(";");
let cookie_set = false;
for (c of c_pairs) {
if (c.trim().split("=")[0].startsWith("token")){
// stick token into all the form input fields
let token = c.split("=")[1];
setFormTokens(token);
cookie_set = true;
}
}
if (!cookie_set) {
document.getElementById("cookie-block").hidden = false;
}

View file

@ -1,43 +1,55 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head>
<head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta property="og:title" content="{{ username }}' site'" /> <meta property="og:title" content="{{ username }}' site'" />
<meta property="og:image" content="/static/site-image.png" /> <meta property="og:image" content="/static/site-image.png" />
<title>{{ username }}' site</title> <title>{{ username }}' site</title>
<link rel="stylesheet" href="/static/css/index.css"> <link rel="stylesheet" href="/static/css/blog.css">
<link rel="shortcut icon" type="image/jpg" href="/static/favicon.ico"/> <link rel="shortcut icon" type="image/jpg" href="/static/favicon.ico" />
</head> </head>
<body> <body>
<h1>Hi, I'm {{ username }}</h1> <h1>Hi, I'm {{ username }}</h1>
<p style="text-align: right"> <p style="text-align: right">
<a href="/">Back to the blog</a> <a href="/">Back to the blog</a>
</p> </p>
<p> <p>
This is my blog. If you have questions or input for me please send me an E-Mail to {{ email }} This is my blog.
{% if email %}
If you have questions or input for me please send me an E-Mail to <img class="social-icon"
src="/static/social-icons/mail.png" /> {{ email }}
{% endif %}
</p> </p>
<br> <br>
<p> <p>
<ul style="list-style: none;"> <ul style="list-style: none;">
{% if github_account %} {% if github_account %}
<li><img class="social-icon" src="/static/social-icons/github.ico"><a href="https://github.com/{{ github_account }}"> {{ github_account }}</a></li> <li><img class="social-icon" src="/static/social-icons/github.ico"><a
href="https://github.com/{{ github_account }}"> {{ github_account }}</a></li>
{% endif %} {% endif %}
{% if twitter_account %} {% if twitter_account %}
<li><img class="social-icon" src="/static/social-icons/twitter.ico"><a href="https://twitter.com/{{ twitter_account }}"> {{ twitter_account }}</a></li> <li><img class="social-icon" src="/static/social-icons/twitter.ico"><a
href="https://twitter.com/{{ twitter_account }}"> {{ twitter_account }}</a></li>
{% endif %} {% endif %}
{% if reddit_account %} {% if reddit_account %}
<li><img class="social-icon" src="/static/social-icons/reddit.ico"><a href="https://reddit.com/u/{{ reddit_account }}"> {{ reddit_account }}</a></li> <li><img class="social-icon" src="/static/social-icons/reddit.ico"><a
href="https://reddit.com/u/{{ reddit_account }}"> {{ reddit_account }}</a></li>
{% endif %} {% endif %}
{% if mastodon_account %} {% if mastodon_account %}
<li><img class="social-icon" src="/static/social-icons/mastodon.ico"><a href="https://mastodon.social/"> {{ mastodon_account }}</a></li> <li><img class="social-icon" src="/static/social-icons/mastodon.ico"><a href="https://mastodon.social/"> {{
mastodon_account }}</a></li>
{% endif %} {% endif %}
{% if discord_account %} {% if discord_account %}
<li><img class="social-icon" src="/static/social-icons/discord.ico"><a href="https://discord.com/"> {{ discord_account }}</a></li> <li><img class="social-icon" src="/static/social-icons/discord.ico"><a href="https://discord.com/"> {{
discord_account }}</a></li>
{% endif %} {% endif %}
</ul> </ul>
</p> </p>
</body> </body>
</html> </html>

View file

@ -1,22 +1,23 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head>
<head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta property="og:title" content="Edit '{{ title }}'"/> <meta property="og:title" content="Edit '{{ title }}'" />
<meta property="og:image" content="/static/site-image.png" /> <meta property="og:image" content="/static/site-image.png" />
<title>Edit '{{ title }}'</title> <title>Edit '{{ title }}'</title>
<link rel="stylesheet" href="/static/css/blog.css"> <link rel="stylesheet" href="/static/css/blog.css">
<link rel="shortcut icon" type="image/jpg" href="/static/favicon.ico"/> <link rel="shortcut icon" type="image/jpg" href="/static/favicon.ico" />
</head> </head>
<body>
<body>
<div id="cookie-block" hidden> <div id="cookie-block" hidden>
<p>Please set your token cookie first.</p> <label for="token">Password</label>
<input id="set-token" type="text" name="set-token"> </br>
<button onclick="setTokenCookie()">Set Token Cookie</button> <input id="token" type="password" name="token">
</div> </div>
<button onclick="clearTokenCookie()">Clear Token Cookie</button>
<form id="submit-form" action="/api/blog/posts/edit/{{ id }}" method=POST> <form id="submit-form" action="/api/blog/posts/edit/{{ id }}" method=POST>
<input class="token" type="text" name="token" hidden> <input class="token" type="text" name="token" hidden>
@ -37,6 +38,6 @@
<input class="token" type="text" name="token" hidden> <input class="token" type="text" name="token" hidden>
<button type="submit">Delete post</button> <button type="submit">Delete post</button>
</form> </form>
<script src="/static/js/blog.js"></script> </body>
</body>
</html> </html>

View file

@ -1,6 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head>
<head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta property="og:title" content="Submit post" /> <meta property="og:title" content="Submit post" />
@ -8,15 +9,15 @@
<title>Submit post</title> <title>Submit post</title>
<link rel="stylesheet" href="/static/css/blog.css"> <link rel="stylesheet" href="/static/css/blog.css">
<link rel="shortcut icon" type="image/jpg" href="/static/favicon.ico"/> <link rel="shortcut icon" type="image/jpg" href="/static/favicon.ico" />
</head> </head>
<body>
<body>
<div id="cookie-block" hidden> <div id="cookie-block" hidden>
<p>Please set your token cookie first.</p> <label for="token">Password</label>
<input id="set-token" type="text" name="set-token"> <br />
<button onclick="setTokenCookie()">Set Token Cookie</button> <input id="token" type="password" name="token">
</div> </div>
<button onclick="clearTokenCookie()">Clear Token Cookie</button>
<form id="submit-form" action="/api/blog/create" method=POST> <form id="submit-form" action="/api/blog/create" method=POST>
<input class="token" type="text" name="token" hidden> <input class="token" type="text" name="token" hidden>
@ -28,6 +29,6 @@
<br> <br>
<button id="submit-button" type="submit">Submit</button> <button id="submit-button" type="submit">Submit</button>
</form> </form>
<script src="/static/js/blog.js"></script> </body>
</body>
</html> </html>

View file

@ -31,10 +31,7 @@ async fn blog_create_post(form: Form<NewPostForm>) -> impl Responder {
} }
#[post("/api/blog/posts/edit/{post_id}")] #[post("/api/blog/posts/edit/{post_id}")]
async fn blog_edit_post( async fn blog_edit_post(post_id: web::Path<String>, form: Form<NewPostForm>) -> impl Responder {
post_id: web::Path<String>,
form: Form<NewPostForm>,
) -> impl Responder {
let (valid, id) = id_valid(post_id.into_inner()); let (valid, id) = id_valid(post_id.into_inner());
if valid && CONFIG.submit_token == form.token { if valid && CONFIG.submit_token == form.token {
edit_post_by_id( edit_post_by_id(
@ -73,10 +70,7 @@ async fn blog_delete_post(
} }
#[post("/api/blog/posts/hide/{post_id}")] #[post("/api/blog/posts/hide/{post_id}")]
async fn blog_hide_post( async fn blog_hide_post(post_id: web::Path<String>, form: Form<BlogActionForm>) -> impl Responder {
post_id: web::Path<String>,
form: Form<BlogActionForm>,
) -> impl Responder {
let (valid, id) = id_valid(post_id.into_inner()); let (valid, id) = id_valid(post_id.into_inner());
if valid && CONFIG.submit_token == form.token { if valid && CONFIG.submit_token == form.token {
println!("Hid post: {}", id); println!("Hid post: {}", id);

View file

@ -7,12 +7,12 @@ pub struct Config {
pub submit_token: String, pub submit_token: String,
pub root_path: String, pub root_path: String,
pub username: String, pub username: String,
pub email: String,
pub bind_port: String, pub bind_port: String,
pub accounts: Accounts, pub accounts: Accounts,
} }
pub struct Accounts { pub struct Accounts {
pub email: Option<String>,
pub github: Option<String>, pub github: Option<String>,
pub twitter: Option<String>, pub twitter: Option<String>,
pub mastodon: Option<String>, pub mastodon: Option<String>,
@ -68,9 +68,9 @@ fn load_config() -> Config {
submit_token: eval_conf_var("SUBMIT_TOKEN", true, None).unwrap(), submit_token: eval_conf_var("SUBMIT_TOKEN", true, None).unwrap(),
root_path: eval_conf_var("ROOT_PATH", false, Some("./content")).unwrap(), root_path: eval_conf_var("ROOT_PATH", false, Some("./content")).unwrap(),
username: eval_conf_var("USERNAME", true, None).unwrap(), username: eval_conf_var("USERNAME", true, None).unwrap(),
email: eval_conf_var("EMAIL", false, None).unwrap(),
bind_port: eval_conf_var("BIND_PORT", false, Some("8000")).unwrap(), bind_port: eval_conf_var("BIND_PORT", false, Some("8000")).unwrap(),
accounts: Accounts { accounts: Accounts {
email: eval_conf_var("EMAIL", false, None),
github: eval_conf_var("GITHUB_ACCOUNT", false, None), github: eval_conf_var("GITHUB_ACCOUNT", false, None),
discord: eval_conf_var("DISCORD_ACCOUNT", false, None), discord: eval_conf_var("DISCORD_ACCOUNT", false, None),
twitter: eval_conf_var("TWITTER_ACCOUNT", false, None), twitter: eval_conf_var("TWITTER_ACCOUNT", false, None),

View file

@ -1,13 +0,0 @@
use diesel::prelude::*;
use chrono;
#[derive(Queryable, Selectable)]
#[diesel(table_name = crate::schema::posts)]
#[diesel(check_for_backend(diesel::pg::Pg))]
pub struct Post {
pub id: i32,
pub title: String,
pub body: String,
pub published: bool,
pub publish_date: chrono::Timestamp
}

View file

@ -36,31 +36,30 @@ pub fn replace_br_tags(x: &str) -> String {
#[get("/about")] #[get("/about")]
async fn about(tmpl: web::Data<tera::Tera>) -> Result<HttpResponse, Error> { async fn about(tmpl: web::Data<tera::Tera>) -> Result<HttpResponse, Error> {
let mut context = Context::new(); let mut context = Context::new();
context.insert( context.insert("username", &CONFIG.username);
"username", match &CONFIG.accounts.email {
&CONFIG.username Some(acc) => context.insert("email", &acc.replace("@", " (at) ")),
); None => (),
context.insert("email", &CONFIG.email); }
match &CONFIG.accounts.github { match &CONFIG.accounts.github {
Some(acc) => context.insert("github_account", &acc), Some(acc) => context.insert("github_account", &acc),
None => () None => (),
}; };
match &CONFIG.accounts.twitter { match &CONFIG.accounts.twitter {
Some(acc) => context.insert("twitter_account", &acc), Some(acc) => context.insert("twitter_account", &acc),
None => () None => (),
}; };
match &CONFIG.accounts.mastodon { match &CONFIG.accounts.mastodon {
Some(acc) => context.insert("mastodon_account", &acc), Some(acc) => context.insert("mastodon_account", &acc),
None => () None => (),
}; };
match &CONFIG.accounts.reddit { match &CONFIG.accounts.reddit {
Some(acc) => context.insert("reddit_account", &acc), Some(acc) => context.insert("reddit_account", &acc),
None => () None => (),
}; };
match &CONFIG.accounts.discord { match &CONFIG.accounts.discord {
Some(acc) => context.insert("discord_account", &acc), Some(acc) => context.insert("discord_account", &acc),
None => () None => (),
}; };
let result = tmpl let result = tmpl
@ -103,8 +102,7 @@ async fn blog_all(tmpl: web::Data<tera::Tera>) -> Result<HttpResponse, Error> {
#[get("/id/{post_id}")] #[get("/id/{post_id}")]
async fn blog_by_id( async fn blog_by_id(
tmpl: web::Data<tera::Tera>, tmpl: web::Data<tera::Tera>,
post_id: web::Path<String> post_id: web::Path<String>, // web::Path(post_id): web::Path<String>,
// web::Path(post_id): web::Path<String>,
) -> Result<HttpResponse, Error> { ) -> Result<HttpResponse, Error> {
let (valid, id) = id_valid(post_id.into_inner()); let (valid, id) = id_valid(post_id.into_inner());
if valid { if valid {
@ -157,7 +155,7 @@ async fn blog_edit(tmpl: web::Data<tera::Tera>) -> Result<HttpResponse, Error> {
#[get("/edit/{post_id}")] #[get("/edit/{post_id}")]
async fn blog_edit_by_id( async fn blog_edit_by_id(
tmpl: web::Data<tera::Tera>, tmpl: web::Data<tera::Tera>,
post_id: web::Path<String> post_id: web::Path<String>,
) -> Result<HttpResponse, Error> { ) -> Result<HttpResponse, Error> {
let (valid, id) = id_valid(post_id.into_inner()); let (valid, id) = id_valid(post_id.into_inner());
if valid { if valid {

View file

@ -1,11 +0,0 @@
// @generated automatically by Diesel CLI.
diesel::table! {
posts (id) {
id -> Nullable<Integer>,
title -> Text,
body -> Text,
published -> Bool,
publish_date -> Timestamp,
}
}