Commit ef8a8cea authored by Zachary Dunn's avatar Zachary Dunn

Add rustfmt.toml and run cargo fmt

parent e2a20466
# Generated with `rustfmt --print-config default default.toml`
# Run that command and diff default.toml with this file to see
# project specific styles
max_width = 120
hard_tabs = false
tab_spaces = 4
newline_style = "Auto"
use_small_heuristics = "Default"
indent_style = "Block"
wrap_comments = false
format_doc_comments = true
comment_width = 80
normalize_comments = false
normalize_doc_attributes = false
license_template_path = ""
format_strings = false
format_macro_matchers = false
format_macro_bodies = true
empty_item_single_line = true
struct_lit_single_line = true
fn_single_line = false
where_single_line = false
imports_indent = "Block"
imports_layout = "Mixed"
merge_imports = true
reorder_imports = true
reorder_modules = true
reorder_impl_items = true
type_punctuation_density = "Wide"
space_before_colon = false
space_after_colon = true
spaces_around_ranges = false
binop_separator = "Front"
remove_nested_parens = true
combine_control_expr = true
struct_field_align_threshold = 0
enum_discrim_align_threshold = 20
match_arm_blocks = true
force_multiline_blocks = false
fn_args_density = "Tall"
brace_style = "SameLineWhere"
control_brace_style = "ClosingNextLine"
trailing_semicolon = true
trailing_comma = "Vertical"
match_block_trailing_comma = true
blank_lines_upper_bound = 1
blank_lines_lower_bound = 0
edition = "2015"
merge_derives = true
use_try_shorthand = false
use_field_init_shorthand = true
force_explicit_abi = true
condense_wildcard_suffixes = true
color = "Auto"
unstable_features = false
disable_all_formatting = false
skip_children = false
hide_parse_errors = false
error_on_line_overflow = false
error_on_unformatted = false
report_todo = "Always"
report_fixme = "Always"
ignore = []
emit_mode = "Files"
make_backup = false
overflow_delimited_expr = true
use log::error;
use rocket::{
http::{ ContentType, Status },
http::{ContentType, Status},
request::Request,
response::{ self, Responder, Response },
response::{self, Responder, Response},
};
use std::io::Cursor;
......@@ -17,24 +17,22 @@ impl<'r> Responder<'r> for APResponse {
fn respond_to(self, _: &Request) -> response::Result<'r> {
let mut builder = Response::build();
let ( status, body ) = match self {
let (status, body) = match self {
APResponse::NotImplemented => (
Status::NotImplemented,
Some("I haven't gottent to this yet".to_string()),
),
APResponse::BadRequest(err) => ( Status::BadRequest, Some(err) ),
APResponse::BadRequest(err) => (Status::BadRequest, Some(err)),
APResponse::Created(url) => {
builder.raw_header("Location", url);
( Status::Created, None )
(Status::Created, None)
},
};
if let Some(err) = body {
error!("{}", err);
builder
.header(ContentType::JSON)
.sized_body(Cursor::new(err));
builder.header(ContentType::JSON).sized_body(Cursor::new(err));
}
builder.status(status).ok()
......
......@@ -7,10 +7,7 @@ extern crate pest_derive;
use dotenv::dotenv;
use log4rs;
use rocket_contrib::{
serve::StaticFiles,
templates::Template,
};
use rocket_contrib::{serve::StaticFiles, templates::Template};
pub mod activity_pub;
pub mod micropub;
......
use crate::micropub::{
post::{ PostType, PostView },
post::{PostType, PostView},
sanitize::Sanitizer,
};
use std::{
boxed::Box,
collections::hash_map::DefaultHasher,
hash::{ Hash, Hasher },
hash::{Hash, Hasher},
};
fn hash(opt: &Option<String>) -> String {
......@@ -71,31 +71,41 @@ impl<'a> PostBuilder<'a> {
}
pub fn content<S>(mut self, content: Option<S>) -> PostBuilder<'a>
where S: Into<String> {
where
S: Into<String>,
{
self.content = content.map(|s| s.into());
self
}
pub fn name<S>(mut self, name: Option<S>) -> PostBuilder<'a>
where S: Into<String> {
where
S: Into<String>,
{
self.name = name.map(|s| s.into());
self
}
pub fn summary<S>(mut self, summary: Option<S>) -> PostBuilder<'a>
where S: Into<String> {
where
S: Into<String>,
{
self.summary = summary.map(|s| s.into());
self
}
pub fn published<S>(mut self, published: S) -> PostBuilder<'a>
where S: Into<String> {
where
S: Into<String>,
{
self.published = Some(published.into());
self
}
pub fn slug<S>(mut self, slug: Option<S>) -> PostBuilder<'a>
where S: Into<String> {
where
S: Into<String>,
{
self.slug = slug.map(|s| s.into());
self
}
......@@ -106,25 +116,33 @@ impl<'a> PostBuilder<'a> {
}
pub fn in_reply_to<S>(mut self, in_reply_to: Option<S>) -> PostBuilder<'a>
where S: Into<String> {
where
S: Into<String>,
{
self.in_reply_to = in_reply_to.map(|i| i.into());
self
}
pub fn repost_of<S>(mut self, repost_of: Option<S>) -> PostBuilder<'a>
where S: Into<String> {
where
S: Into<String>,
{
self.repost_of = repost_of.map(|i| i.into());
self
}
pub fn like_of<S>(mut self, like_of: Option<S>) -> PostBuilder<'a>
where S: Into<String> {
where
S: Into<String>,
{
self.like_of = like_of.map(|i| i.into());
self
}
pub fn photo<S>(mut self, photo: Option<S>) -> PostBuilder<'a>
where S: Into<String> {
where
S: Into<String>,
{
self.photo = photo.map(|i| i.into());
self
}
......@@ -137,7 +155,7 @@ impl<'a> PostBuilder<'a> {
let post_type = PostType::from(post_type_str);
if let PostType::Unsupported(unsupported_type) = post_type {
return Err(format!("Unsupported post type {}", unsupported_type))
return Err(format!("Unsupported post type {}", unsupported_type));
}
let url = format!("{host}/{type}s/{slug}", host=self.host, type=post_type_str, slug=slug);
......@@ -161,14 +179,14 @@ impl<'a> PostBuilder<'a> {
pub fn validate(self) -> Result<InnerBuilder<'a>, &'static str> {
if self.like_of.is_some() || self.repost_of.is_some() {
let ( target_url, path, post_type ) = if self.like_of.is_some() {
( &self.like_of, "likes", PostType::Like)
let (target_url, path, post_type) = if self.like_of.is_some() {
(&self.like_of, "likes", PostType::Like)
}
else {
( &self.repost_of, "boosts", PostType::Boost )
(&self.repost_of, "boosts", PostType::Boost)
};
let slug = hash(target_url);
let url = format!("{host}/{path}/{slug}", host=self.host, path=path, slug=&slug);
let url = format!("{host}/{path}/{slug}", host = self.host, path = path, slug = &slug);
return Ok(InnerBuilder {
post_type,
......@@ -184,10 +202,12 @@ impl<'a> PostBuilder<'a> {
in_reply_to: self.in_reply_to,
repost_of: self.repost_of,
like_of: self.like_of,
})
});
}
let slug = self.slug.as_ref()
let slug = self
.slug
.as_ref()
.or_else(|| self.name.as_ref())
.map(|s| &**s)
.map(|s| Sanitizer::slugify_name(s))
......@@ -200,10 +220,10 @@ impl<'a> PostBuilder<'a> {
if self.photo.is_some() {
let post_type = PostType::Photo;
if self.name.is_none() {
return Err("'name' property is required for photo posts")
return Err("'name' property is required for photo posts");
}
let url = format!("{host}/photos/{slug}", host=self.host, slug=slug);
let url = format!("{host}/photos/{slug}", host = self.host, slug = slug);
return Ok(InnerBuilder {
post_type,
url,
......@@ -218,19 +238,19 @@ impl<'a> PostBuilder<'a> {
in_reply_to: self.in_reply_to,
repost_of: self.repost_of,
like_of: self.like_of,
})
});
}
let has_name = self.name.as_ref().map_or(false, |n| !n.is_empty());
let has_summary = self.summary.as_ref().map_or(false, |s| !s.is_empty());
let ( post_type, path ) = if has_summary && has_name {
( PostType::Article, "articles" )
let (post_type, path) = if has_summary && has_name {
(PostType::Article, "articles")
}
else {
( PostType::Note, "notes" )
(PostType::Note, "notes")
};
let url = format!("{host}/{path}/{slug}", host=self.host, path=path, slug=slug);
let url = format!("{host}/{path}/{slug}", host = self.host, path = path, slug = slug);
Ok(InnerBuilder {
post_type,
url,
......@@ -251,32 +271,52 @@ impl<'a> PostBuilder<'a> {
impl<'a> InnerBuilder<'a> {
pub fn build(self) -> PostSuccess<'a> {
let InnerBuilder { author, content, name, summary, published, slug, tags, in_reply_to, repost_of, like_of, photo, post_type, url, .. } = self;
let InnerBuilder {
author,
content,
name,
summary,
published,
slug,
tags,
in_reply_to,
repost_of,
like_of,
photo,
post_type,
url,
..
} = self;
let raw_content = content.unwrap_or_else(String::new);
let ( post_type, content, summary, tags, links ) = match post_type {
let (post_type, content, summary, tags, links) = match post_type {
PostType::Photo => {
let summary = summary.or_else(|| Some(String::from("")));
( PostType::Photo, raw_content, summary, tags, None )
(PostType::Photo, raw_content, summary, tags, None)
},
PostType::Article => {
let summary = summary.or_else(|| Some(raw_content.lines().take(3).collect()));
let ( content, mut links ) = Sanitizer::parse_article(&raw_content);
let (content, mut links) = Sanitizer::parse_article(&raw_content);
if in_reply_to.is_some() {
links.push(in_reply_to.clone().unwrap());
}
( PostType::Article, content, summary, tags, Some(links) )
(PostType::Article, content, summary, tags, Some(links))
},
PostType::Note => {
let ( content, tags, mut links ) = Sanitizer::parse_note(&raw_content);
let (content, tags, mut links) = Sanitizer::parse_note(&raw_content);
if in_reply_to.is_some() {
links.push(in_reply_to.clone().unwrap());
}
( PostType::Note, content, None, tags, Some(links) )
(PostType::Note, content, None, tags, Some(links))
},
pt @ PostType::Like | pt @ PostType::Boost => {
let target = if pt == PostType::Like { like_of.clone() } else { repost_of.clone() };
( pt, raw_content, None, Vec::new(), Some(vec![ target.unwrap() ]) )
let target = if pt == PostType::Like {
like_of.clone()
}
else {
repost_of.clone()
};
(pt, raw_content, None, Vec::new(), Some(vec![target.unwrap()]))
},
PostType::Unsupported(pt) => panic!("Can't build post with unsupported type: {}", pt),
};
......@@ -295,13 +335,13 @@ impl<'a> InnerBuilder<'a> {
repost_of,
like_of,
};
( Box::new(post), links )
(Box::new(post), links)
}
}
#[cfg(test)]
mod tests {
use crate::micropub::{ builder::PostBuilder, post::PostType };
use crate::micropub::{builder::PostBuilder, post::PostType};
fn post_builder() -> PostBuilder<'static> {
PostBuilder::new("Tester", "example.com", "YYYY-MM-dd")
......@@ -371,4 +411,3 @@ mod tests {
assert!(builder.repost_of.is_some());
}
}
use serde_derive::{ Serialize, Deserialize };
use serde_derive::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "kebab-case")]
......@@ -44,4 +44,3 @@ pub struct EntryRequest {
pub h: Option<Vec<String>>,
pub properties: Properties,
}
use rocket::FromForm;
use serde_derive::{ Serialize, Deserialize };
use serde_derive::{Deserialize, Serialize};
/// Micropub request for creating a post in fomr-encoded format
///
......@@ -47,4 +47,3 @@ pub struct EntryRequest {
#[form(field = "mp-slug")]
pub mp_slug: Option<String>,
}
......@@ -31,7 +31,9 @@ pub struct Card {
impl Card {
pub fn new<S>(name: S, url: S, nickname: S, email: Option<S>) -> Card
where S: Into<String> {
where
S: Into<String>,
{
Card {
name: name.into(),
url: url.into(),
......@@ -40,4 +42,3 @@ impl Card {
}
}
}
......@@ -41,4 +41,3 @@ pub struct PostView {
pub repost_of: Option<String>,
pub like_of: Option<String>,
}
use log::error;
use serde_derive::Serialize;
use std::io::Cursor;
use rocket::{
http::{ ContentType, Status },
http::{ContentType, Status},
request::Request,
response::{ self, Response, Responder }
response::{self, Responder, Response},
};
use serde_json::{ json, self };
use serde_derive::Serialize;
use serde_json::{self, json};
use std::io::Cursor;
#[derive(Serialize)]
pub struct MicropubError {
......@@ -25,7 +25,9 @@ pub enum MicropubResponse {
}
fn micropub_error_json<S>(error: S, error_description: S) -> Option<serde_json::Value>
where S: Into<String> {
where
S: Into<String>,
{
let json = json!({
"error": error.into(),
"error_description": error_description.into(),
......@@ -37,30 +39,30 @@ impl<'r> Responder<'r> for MicropubResponse {
fn respond_to(self, _: &Request) -> response::Result<'r> {
let mut builder = Response::build();
let ( status, body ) = match self {
let (status, body) = match self {
MicropubResponse::MissingContent => (
Status::BadRequest,
micropub_error_json("invalid_request", "Missing 'content' property")
micropub_error_json("invalid_request", "Missing 'content' property"),
),
MicropubResponse::NotImplemented => (
Status::NotImplemented,
micropub_error_json("Not Implemented", "I haven't gottent to this yet")
micropub_error_json("Not Implemented", "I haven't gottent to this yet"),
),
MicropubResponse::UnsupportedType(h_type) => (
Status::BadRequest,
micropub_error_json("invalid_request", &format!("Unsupported h-type: {}", h_type))
micropub_error_json("invalid_request", &format!("Unsupported h-type: {}", h_type)),
),
MicropubResponse::UnsupportedQuery(query) => (
Status::BadRequest,
micropub_error_json("invalid_request", &format!("Unsupported query type: {}", query))
micropub_error_json("invalid_request", &format!("Unsupported query type: {}", query)),
),
MicropubResponse::BadRequest(err) => (
Status::BadRequest,
micropub_error_json(String::from("invalid_request"), err)
micropub_error_json(String::from("invalid_request"), err),
),
MicropubResponse::Created(url) => {
builder.raw_header("Location", url);
( Status::Created, None )
(Status::Created, None)
},
};
......@@ -72,8 +74,7 @@ impl<'r> Responder<'r> for MicropubResponse {
.header(ContentType::JSON)
.sized_body(Cursor::new(json.to_string()));
}
builder.status(status).ok()
}
}
......@@ -16,12 +16,10 @@ impl Sanitizer {
}
pub fn format_published_date(published: Option<String>, date_format: &str) -> String {
published.unwrap_or_else(|| {
time::strftime(date_format, &time::now()).expect("Couldn't format published date")
})
published.unwrap_or_else(|| time::strftime(date_format, &time::now()).expect("Couldn't format published date"))
}
pub fn parse_note(content: &str) -> ( String, Vec<String>, Vec<String> ) {
pub fn parse_note(content: &str) -> (String, Vec<String>, Vec<String>) {
let parse_result = PostParser::parse(Rule::note_content, content)
.expect("unsuccessful parse")
.next()
......@@ -37,7 +35,10 @@ impl Sanitizer {
let tag = inner_rule.next().unwrap().as_str();
tags.push(String::from(tag));
Some(format!(" <a href=\"/tags/{}\" class=\"hashtag\" title=\"{} tag\">#{}</a> ", tag, tag, tag))
Some(format!(
" <a href=\"/tags/{}\" class=\"hashtag\" title=\"{} tag\">#{}</a> ",
tag, tag, tag
))
},
Rule::link => {
let link = token.as_str();
......@@ -50,10 +51,10 @@ impl Sanitizer {
})
.collect();
( output, tags, links )
(output, tags, links)
}
pub fn parse_article(content: &str) -> ( String, Vec<String> ) {
pub fn parse_article(content: &str) -> (String, Vec<String>) {
let parse_result = PostParser::parse(Rule::article_content, content)
.expect("unsuccessful parse")
.next()
......@@ -74,7 +75,7 @@ impl Sanitizer {
})
.collect();
( output, links )
(output, links)
}
}
......@@ -111,4 +112,3 @@ mod tests {
// TODO: Add more tests here
}
}
......@@ -75,4 +75,3 @@ impl SyndicationTarget {
self
}
}
use crate::{
activity_pub::responders::APResponse,
site::Site
};
use rocket::{
http::ContentType,
response::Content,
get,
post,
routes,
Route,
State
};
use crate::{activity_pub::responders::APResponse, site::Site};
use rocket::{get, http::ContentType, post, response::Content, routes, Route, State};
use serde_json::json;
pub fn routes() -> Vec<Route> {
routes![
ap_actor,
ap_inbox,
incoming_message,
ap_outbox,
outgoing_message,
]
routes![ap_actor, ap_inbox, incoming_message, ap_outbox, outgoing_message,]
}
#[get("/actor")]
......@@ -40,7 +23,8 @@ fn ap_actor(site: State<Site>) -> Content<String> {
"preferredUsername": &site.h_card.nickname,
"name": &site.h_card.name,