v2.2.0 - Pirate Stache - Markdown and Clensing

Message format has been changed so that all text boxes will be the same
width, rather than they change depending on name length.
TL;DR: changed location of name tag

You can now format your messages with cmark flavored markdown. There
still may be rendering bugs, but I will fix them as they come.

Messages are now properly sanitized with the ammonia package.

Messages now have proper timestamps with help from chrono. Right now
previous versions are not compatible with the new timestamp format. A
patch will be introduced in the next couple of updates to remedy that
issue.

Did some housekeeping in `static/index.css`
This commit is contained in:
saw 2021-08-06 01:01:22 -04:00
parent b92d1e6236
commit 093b6cd868
12 changed files with 124 additions and 90 deletions

View File

@ -1,6 +1,6 @@
[package]
name = "board_server"
version = "2.1.0"
version = "2.2.0"
edition = "2018"
license = "Zlib"
repository = "https://git.solow.xyz/cgit.cgi/Boarders/"
@ -22,6 +22,9 @@ futures = "0.3.15"
handlebars = "4.0.1"
maplit = "1.0.2"
simple_logger = "1.11.0"
chrono = "0.4.19"
ammonia = "3.1.2"
pulldown-cmark = "0.8.0"
[lib]
name = "boarders"

View File

@ -18,10 +18,11 @@ use crate::{
};
use handlebars::to_json;
use maplit::btreemap;
use super::TimeDerive;
use chrono::{DateTime, Utc};
use ammonia::clean;
use pulldown_cmark::{Parser, Options, html::push_html};
#[get("/boards/")]
pub async fn list_boards(
@ -76,7 +77,30 @@ pub async fn get_board(
};
if let Some(a) = Board::search(boards.iter(), board_id) {
let data = btreemap!(
"messages" => to_json(&a.messages),
"messages" => {
let mut msg_json = to_json(&a.messages);
let mut op = Options::empty();
op.insert(Options::ENABLE_TABLES);
let msg_json = msg_json.as_array_mut().unwrap().iter_mut().zip(a.messages.borrow().iter()).map(|x| {
let parse = Parser::new_ext(&x.1.text, op);
let o = x.0.as_object_mut().unwrap();
o.insert(
"time_meta".to_string(),
to_json(DateTime::<Utc>::from(x.1.timestamp).to_rfc2822().trim_matches(|c| c=='0' || c=='+' || c==' '))
);
o.insert(
"render_text".to_string(),
{
let mut dirty_html = String::new();
push_html(&mut dirty_html, parse);
to_json(dirty_html)
}
);
x.0
}).collect::<Vec<&mut serde_json::Value>>();
to_json(msg_json)
},
"user" => match uid {
Ok(a) => to_json(data.user_manager.lock().unwrap().get_user_by_id(a.id)),
Err(_) => to_json(None::<Option<u8>>)
@ -112,7 +136,6 @@ pub async fn board_post(
let um = data.user_manager.lock().unwrap();
match board {
Some(ref mut a) => {
//let a: &mut Board = board.unwrap();
let msg = mf.create_message({
let user = um.get_user_by_id(form.user_id).ok_or_else(|| {
HttpResponse::NotFound().body("Not Found: User does not exist")
@ -122,8 +145,7 @@ pub async fn board_post(
} else {
return Err(HttpResponse::Unauthorized().body("Unauthorized: Bad login attempt, invalid auth token"));
}
}, form.content.clone().trim());
println!("new message");
}, clean(&form.content));
a.add_message(msg);
Ok(HttpResponse::SeeOther().header("location", format!("/board/{}/", a.id)).finish())
},

View File

@ -33,7 +33,7 @@ impl Board {
/* backwards compatability */
if let Ok(ref mut b) = b {
if b.last_active.is_none() {
b.last_active = b.messages.borrow().last().map(|x| x.timestamp);
b.last_active = b.messages.borrow().last().map(|x| x.as_secs());
}
}
b
@ -50,7 +50,7 @@ impl Board {
}
pub fn add_message(&mut self, msg: Message) -> &Board {
self.last_active = Some(msg.timestamp);
self.last_active = Some(msg.as_secs());
self.messages.borrow_mut().push(msg);
self
}

View File

@ -14,10 +14,16 @@ use super::{
pub struct Message {
pub text: String,
pub id: u32,
pub timestamp: u64,
pub timestamp: SystemTime,
pub author: RefCell<User>
}
impl Message {
pub fn as_secs(&self) -> u64 {
self.timestamp.duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs()
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct MessageFactory {
pub next_id: u32,
@ -36,11 +42,10 @@ impl MessageFactory {
pub fn create_message<S>(&mut self, user: User, content: S) -> Message where S: AsRef<str> {
self.next_id += 1;
let time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs();
Message {
text: String::from(content.as_ref()),
id: self.next_id-1,
timestamp: time,
timestamp: SystemTime::now(),
author: RefCell::new(user)
}
}

View File

@ -42,7 +42,7 @@ use tokio::{
select
};
use handlebars::Handlebars;
use handlebars::{Handlebars, handlebars_helper};
use console::style;
use maplit::btreemap;
@ -274,13 +274,16 @@ async fn main() -> std::io::Result<()> {
* variable at compile time
*/
/* register handlebars partials here */
h.register_partial("login_status", include_str!("res/snippets/login_status.hbs")).unwrap();
h.register_partial("board_bar", include_str!("res/snippets/board_bar.hbs")).unwrap();
handlebars_helper!(msg_helper: |s: str| format!("helped: {}", s.to_string()));
h.register_helper("msg", Box::new(msg_helper));
h.register_partial("head", include_str!("res/snippets/head.hbs")).unwrap();
h.register_partial("login_status", include_str!("res/snippets/login_status.hbs")).unwrap();
h.register_partial("board_bar", include_str!("res/snippets/board_bar.hbs")).unwrap();
/* register handlebars templates here */
h.register_template_string("board_index", include_str!("res/board_index.hbs")).unwrap();
h.register_template_string("welcome", include_str!("res/welcome.hbs")).unwrap();
h.register_template_string("auth", include_str!("res/auth.hbs")).unwrap();
h.register_template_string("board", include_str!("res/board.hbs")).unwrap();
h.register_template_string("welcome", include_str!("res/welcome.hbs")).unwrap();
h.register_template_string("auth", include_str!("res/auth.hbs")).unwrap();
h.register_template_string("board", include_str!("res/board.hbs")).unwrap();
h
}
}).app_data(web_data.clone())

View File

@ -1,8 +1,6 @@
<html>
<head>
<link rel="stylesheet" type="text/css" href="https://orbitalfox.us/Music/index.css">
<link rel="stylesheet" type="text/css" href="/static/index.css">
</head>
<!DOCTYPE html>
<html lang="en">
{{> head}}
<body>
<div id="title" class="bar">
{{#if user.nick}}

View File

@ -1,8 +1,6 @@
<html>
<head>
<link rel="stylesheet" type="text/css" href="https://orbitalfox.us/Music/index.css">
<link rel="stylesheet" type="text/css" href="/static/index.css">
</head>
<!DOCTYPE html>
<html lang="en">
{{> head}}
<body style="overflow-x: hidden;">
{{> board_bar board=board user=user}}
<div id="index">
@ -18,16 +16,16 @@
<b>{{msg.author.username}}</b>
{{/if}}
<div class="message-content">
<pre>{{msg.text}}</pre>
<pre>{{{msg.render_text}}}</pre>
</div>
<div class="message-time">
{{msg.timestamp}}
{{msg.time_meta}}
</div>
</div>
{{/each}}
</div>
<form action="/boards/post" method="post" style="display: flex; align-items: center; flex-direction: column;">
<label for="content">Content:</label><br/>
<label for="content">Write a message:</label><br/>
<input type="hidden" id="board_id" name="board_id" value="{{board.id}}">
<input type="hidden" id="user_id" name="user_id" value="{{user.user_id}}">
<textarea name="content" id="content" rows=12 cols=50 placeholder="Enter message here..."></textarea>

View File

@ -1,8 +1,6 @@
<html>
<head>
<link rel="stylesheet" type="text/css" href="https://orbitalfox.us/Music/index.css">
<link rel="stylesheet" type="text/css" href="/static/index.css">
</head>
<!DOCTYPE html>
<html lang="en">
{{> head}}
<body style="overflow-x: hidden;">
<div id="title" class="bar">
<div>

View File

@ -1,8 +1,6 @@
<html>
<head>
<link rel="stylesheet" type="text/css" href="https://orbitalfox.us/Music/index.css">
<link rel="stylesheet" type="text/css" href="/static/index.css">
</head>
<!DOCTYPE html>
<html lang="en">
{{> head}}
<body>
<div id="title" class="bar">
<h1>Hello, {{name}}</h1>

View File

@ -0,0 +1,9 @@
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<link rel="stylesheet" type="text/css" href="https://orbitalfox.us/Music/index.css">
<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon"/>
{{#if nolocal}}
{{else}}
<link rel="stylesheet" type="text/css" href="/static/index.css">
{{/if}}
</head>

View File

@ -1,7 +1,6 @@
<html>
<head>
<link rel="stylesheet" type="text/css" href="https://orbitalfox.us/Music/index.css">
</head>
<!DOCTYPE html>
<html lang="en">
{{> head nolocal=1}}
<body>
<h1>
<div style="display: flex; align-items: center; flex-direction: column;">

View File

@ -60,56 +60,17 @@ body {
font-size: 2.5em !important;
}
#nav {
width: 3em;
position: fixed;
right: 0;
top: 0;
margin-left: 3rem;
height: 100%;
}
.arrow {
width: 2.5rem;
background-color: #07a6ea;
color: white;
padding: 0.25rem;
border-radius: 0.5em;
}
.orange-arrow {
width: 2.5rem;
color: orange;
padding: 0.25rem;
border-radius: 0.5em;
}
.down {
transform: rotate(180deg);
-webkit-transform:rotate(180deg);
-moz-transform: rotate(180deg);
-ms-transform: rotate(180deg);
-o-transform: rotate(180deg);
}
#navbar > img.arrow.down {
unset: top;
bottom: 0;
margin-bottom: 0.5em;
}
#navbar > img.arrow {
position: relative;
}
.message {
margin-top: 0.5em;
margin-bottom: 0.5em;
border-bottom: 1px solid #555;
display: flex;
flex-direction: row;
flex-direction: inherit;
justify-content: flex-start;
align-items: center;
}
.message > b {
padding-left: 1em;
}
.message > * {
@ -197,7 +158,12 @@ tr.board:hover {
.message-content {
flex-grow: 1;
max-width: 90%;
/*max-width: 90%; */
}
.message-content > pre {
margin-top: 0.1rem;
margin-bottom: 0.1rem;
}
pre {
@ -207,3 +173,38 @@ pre {
white-space: -o-pre-wrap; /* Opera 7 */
word-wrap: break-word; /* Internet Explorer 5.5+ */
}
pre > h1 {
font-size: 2rem;
}
pre > h2 {
font-size: 1.75rem;
}
pre > h3 {
font-size: 1.5rem;
}
pre > h4 {
font-size: 1.25rem;
}
pre > h5 {
font-size: 1rem;
}
pre > *:last-child {
margin-bottom: unset;
}
code {
background-color: #222;
padding: 0.5rem;
border-radius: 0.25rem;
}
.message-time {
font-size: 0.75rem;
color: #555
}