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:
parent
b92d1e6236
commit
093b6cd868
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "board_server"
|
name = "board_server"
|
||||||
version = "2.1.0"
|
version = "2.2.0"
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "Zlib"
|
license = "Zlib"
|
||||||
repository = "https://git.solow.xyz/cgit.cgi/Boarders/"
|
repository = "https://git.solow.xyz/cgit.cgi/Boarders/"
|
||||||
@ -22,6 +22,9 @@ futures = "0.3.15"
|
|||||||
handlebars = "4.0.1"
|
handlebars = "4.0.1"
|
||||||
maplit = "1.0.2"
|
maplit = "1.0.2"
|
||||||
simple_logger = "1.11.0"
|
simple_logger = "1.11.0"
|
||||||
|
chrono = "0.4.19"
|
||||||
|
ammonia = "3.1.2"
|
||||||
|
pulldown-cmark = "0.8.0"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
name = "boarders"
|
name = "boarders"
|
||||||
|
|||||||
@ -18,10 +18,11 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use handlebars::to_json;
|
use handlebars::to_json;
|
||||||
|
|
||||||
use maplit::btreemap;
|
use maplit::btreemap;
|
||||||
|
|
||||||
use super::TimeDerive;
|
use super::TimeDerive;
|
||||||
|
use chrono::{DateTime, Utc};
|
||||||
|
use ammonia::clean;
|
||||||
|
use pulldown_cmark::{Parser, Options, html::push_html};
|
||||||
|
|
||||||
#[get("/boards/")]
|
#[get("/boards/")]
|
||||||
pub async fn list_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) {
|
if let Some(a) = Board::search(boards.iter(), board_id) {
|
||||||
let data = btreemap!(
|
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 {
|
"user" => match uid {
|
||||||
Ok(a) => to_json(data.user_manager.lock().unwrap().get_user_by_id(a.id)),
|
Ok(a) => to_json(data.user_manager.lock().unwrap().get_user_by_id(a.id)),
|
||||||
Err(_) => to_json(None::<Option<u8>>)
|
Err(_) => to_json(None::<Option<u8>>)
|
||||||
@ -112,7 +136,6 @@ pub async fn board_post(
|
|||||||
let um = data.user_manager.lock().unwrap();
|
let um = data.user_manager.lock().unwrap();
|
||||||
match board {
|
match board {
|
||||||
Some(ref mut a) => {
|
Some(ref mut a) => {
|
||||||
//let a: &mut Board = board.unwrap();
|
|
||||||
let msg = mf.create_message({
|
let msg = mf.create_message({
|
||||||
let user = um.get_user_by_id(form.user_id).ok_or_else(|| {
|
let user = um.get_user_by_id(form.user_id).ok_or_else(|| {
|
||||||
HttpResponse::NotFound().body("Not Found: User does not exist")
|
HttpResponse::NotFound().body("Not Found: User does not exist")
|
||||||
@ -122,8 +145,7 @@ pub async fn board_post(
|
|||||||
} else {
|
} else {
|
||||||
return Err(HttpResponse::Unauthorized().body("Unauthorized: Bad login attempt, invalid auth token"));
|
return Err(HttpResponse::Unauthorized().body("Unauthorized: Bad login attempt, invalid auth token"));
|
||||||
}
|
}
|
||||||
}, form.content.clone().trim());
|
}, clean(&form.content));
|
||||||
println!("new message");
|
|
||||||
a.add_message(msg);
|
a.add_message(msg);
|
||||||
Ok(HttpResponse::SeeOther().header("location", format!("/board/{}/", a.id)).finish())
|
Ok(HttpResponse::SeeOther().header("location", format!("/board/{}/", a.id)).finish())
|
||||||
},
|
},
|
||||||
|
|||||||
@ -33,7 +33,7 @@ impl Board {
|
|||||||
/* backwards compatability */
|
/* backwards compatability */
|
||||||
if let Ok(ref mut b) = b {
|
if let Ok(ref mut b) = b {
|
||||||
if b.last_active.is_none() {
|
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
|
b
|
||||||
@ -50,7 +50,7 @@ impl Board {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_message(&mut self, msg: Message) -> &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.messages.borrow_mut().push(msg);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,10 +14,16 @@ use super::{
|
|||||||
pub struct Message {
|
pub struct Message {
|
||||||
pub text: String,
|
pub text: String,
|
||||||
pub id: u32,
|
pub id: u32,
|
||||||
pub timestamp: u64,
|
pub timestamp: SystemTime,
|
||||||
pub author: RefCell<User>
|
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)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct MessageFactory {
|
pub struct MessageFactory {
|
||||||
pub next_id: u32,
|
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> {
|
pub fn create_message<S>(&mut self, user: User, content: S) -> Message where S: AsRef<str> {
|
||||||
self.next_id += 1;
|
self.next_id += 1;
|
||||||
let time = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs();
|
|
||||||
Message {
|
Message {
|
||||||
text: String::from(content.as_ref()),
|
text: String::from(content.as_ref()),
|
||||||
id: self.next_id-1,
|
id: self.next_id-1,
|
||||||
timestamp: time,
|
timestamp: SystemTime::now(),
|
||||||
author: RefCell::new(user)
|
author: RefCell::new(user)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
15
src/main.rs
15
src/main.rs
@ -42,7 +42,7 @@ use tokio::{
|
|||||||
select
|
select
|
||||||
};
|
};
|
||||||
|
|
||||||
use handlebars::Handlebars;
|
use handlebars::{Handlebars, handlebars_helper};
|
||||||
use console::style;
|
use console::style;
|
||||||
use maplit::btreemap;
|
use maplit::btreemap;
|
||||||
|
|
||||||
@ -274,13 +274,16 @@ async fn main() -> std::io::Result<()> {
|
|||||||
* variable at compile time
|
* variable at compile time
|
||||||
*/
|
*/
|
||||||
/* register handlebars partials here */
|
/* register handlebars partials here */
|
||||||
h.register_partial("login_status", include_str!("res/snippets/login_status.hbs")).unwrap();
|
handlebars_helper!(msg_helper: |s: str| format!("helped: {}", s.to_string()));
|
||||||
h.register_partial("board_bar", include_str!("res/snippets/board_bar.hbs")).unwrap();
|
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 */
|
/* register handlebars templates here */
|
||||||
h.register_template_string("board_index", include_str!("res/board_index.hbs")).unwrap();
|
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("welcome", include_str!("res/welcome.hbs")).unwrap();
|
||||||
h.register_template_string("auth", include_str!("res/auth.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("board", include_str!("res/board.hbs")).unwrap();
|
||||||
h
|
h
|
||||||
}
|
}
|
||||||
}).app_data(web_data.clone())
|
}).app_data(web_data.clone())
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
<html>
|
<!DOCTYPE html>
|
||||||
<head>
|
<html lang="en">
|
||||||
<link rel="stylesheet" type="text/css" href="https://orbitalfox.us/Music/index.css">
|
{{> head}}
|
||||||
<link rel="stylesheet" type="text/css" href="/static/index.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
<body>
|
||||||
<div id="title" class="bar">
|
<div id="title" class="bar">
|
||||||
{{#if user.nick}}
|
{{#if user.nick}}
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
<html>
|
<!DOCTYPE html>
|
||||||
<head>
|
<html lang="en">
|
||||||
<link rel="stylesheet" type="text/css" href="https://orbitalfox.us/Music/index.css">
|
{{> head}}
|
||||||
<link rel="stylesheet" type="text/css" href="/static/index.css">
|
|
||||||
</head>
|
|
||||||
<body style="overflow-x: hidden;">
|
<body style="overflow-x: hidden;">
|
||||||
{{> board_bar board=board user=user}}
|
{{> board_bar board=board user=user}}
|
||||||
<div id="index">
|
<div id="index">
|
||||||
@ -18,16 +16,16 @@
|
|||||||
<b>{{msg.author.username}}</b>
|
<b>{{msg.author.username}}</b>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<div class="message-content">
|
<div class="message-content">
|
||||||
<pre>{{msg.text}}</pre>
|
<pre>{{{msg.render_text}}}</pre>
|
||||||
</div>
|
</div>
|
||||||
<div class="message-time">
|
<div class="message-time">
|
||||||
{{msg.timestamp}}
|
{{msg.time_meta}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</div>
|
</div>
|
||||||
<form action="/boards/post" method="post" style="display: flex; align-items: center; flex-direction: column;">
|
<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="board_id" name="board_id" value="{{board.id}}">
|
||||||
<input type="hidden" id="user_id" name="user_id" value="{{user.user_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>
|
<textarea name="content" id="content" rows=12 cols=50 placeholder="Enter message here..."></textarea>
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
<html>
|
<!DOCTYPE html>
|
||||||
<head>
|
<html lang="en">
|
||||||
<link rel="stylesheet" type="text/css" href="https://orbitalfox.us/Music/index.css">
|
{{> head}}
|
||||||
<link rel="stylesheet" type="text/css" href="/static/index.css">
|
|
||||||
</head>
|
|
||||||
<body style="overflow-x: hidden;">
|
<body style="overflow-x: hidden;">
|
||||||
<div id="title" class="bar">
|
<div id="title" class="bar">
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
<html>
|
<!DOCTYPE html>
|
||||||
<head>
|
<html lang="en">
|
||||||
<link rel="stylesheet" type="text/css" href="https://orbitalfox.us/Music/index.css">
|
{{> head}}
|
||||||
<link rel="stylesheet" type="text/css" href="/static/index.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
<body>
|
||||||
<div id="title" class="bar">
|
<div id="title" class="bar">
|
||||||
<h1>Hello, {{name}}</h1>
|
<h1>Hello, {{name}}</h1>
|
||||||
|
|||||||
9
src/res/snippets/head.hbs
Normal file
9
src/res/snippets/head.hbs
Normal 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>
|
||||||
@ -1,7 +1,6 @@
|
|||||||
<html>
|
<!DOCTYPE html>
|
||||||
<head>
|
<html lang="en">
|
||||||
<link rel="stylesheet" type="text/css" href="https://orbitalfox.us/Music/index.css">
|
{{> head nolocal=1}}
|
||||||
</head>
|
|
||||||
<body>
|
<body>
|
||||||
<h1>
|
<h1>
|
||||||
<div style="display: flex; align-items: center; flex-direction: column;">
|
<div style="display: flex; align-items: center; flex-direction: column;">
|
||||||
|
|||||||
@ -60,56 +60,17 @@ body {
|
|||||||
font-size: 2.5em !important;
|
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 {
|
.message {
|
||||||
margin-top: 0.5em;
|
margin-top: 0.5em;
|
||||||
margin-bottom: 0.5em;
|
margin-bottom: 0.5em;
|
||||||
border-bottom: 1px solid #555;
|
border-bottom: 1px solid #555;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: inherit;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: center;
|
}
|
||||||
|
|
||||||
|
.message > b {
|
||||||
|
padding-left: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message > * {
|
.message > * {
|
||||||
@ -197,7 +158,12 @@ tr.board:hover {
|
|||||||
|
|
||||||
.message-content {
|
.message-content {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
max-width: 90%;
|
/*max-width: 90%; */
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-content > pre {
|
||||||
|
margin-top: 0.1rem;
|
||||||
|
margin-bottom: 0.1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
pre {
|
pre {
|
||||||
@ -207,3 +173,38 @@ pre {
|
|||||||
white-space: -o-pre-wrap; /* Opera 7 */
|
white-space: -o-pre-wrap; /* Opera 7 */
|
||||||
word-wrap: break-word; /* Internet Explorer 5.5+ */
|
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
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user