diff --git a/plume-cli/src/instance.rs b/plume-cli/src/instance.rs index 7872adaf..0bd45db1 100644 --- a/plume-cli/src/instance.rs +++ b/plume-cli/src/instance.rs @@ -46,12 +46,12 @@ fn new<'a>(args: &ArgMatches<'a>, conn: &Connection) { .unwrap_or_else(|| env::var("BASE_URL") .unwrap_or_else(|_| super::ask_for("Domain name"))); let name = args.value_of("name").map(String::from).unwrap_or_else(|| super::ask_for("Instance name")); - let license = args.value_of("default-license").map(String::from).unwrap_or(String::from("CC-BY-SA")); + let license = args.value_of("default-license").map(String::from).unwrap_or_else(|| String::from("CC-BY-SA")); let open_reg = !args.is_present("private"); Instance::insert(conn, NewInstance { public_domain: domain, - name: name, + name, local: true, long_description: SafeString::new(""), short_description: SafeString::new(""), diff --git a/plume-cli/src/users.rs b/plume-cli/src/users.rs index a00f8579..89be12ef 100644 --- a/plume-cli/src/users.rs +++ b/plume-cli/src/users.rs @@ -70,8 +70,8 @@ fn new<'a>(args: &ArgMatches<'a>, conn: &Connection) { username, display_name, admin, - bio, + &bio, email, - User::hash_pass(password), + User::hash_pass(&password), ).update_boxes(conn); } diff --git a/plume-common/src/activity_pub/inbox.rs b/plume-common/src/activity_pub/inbox.rs index 940411ef..2820b14f 100644 --- a/plume-common/src/activity_pub/inbox.rs +++ b/plume-common/src/activity_pub/inbox.rs @@ -37,7 +37,7 @@ pub trait Notify { pub trait Deletable { fn delete(&self, conn: &C) -> A; - fn delete_id(id: String, actor_id: String, conn: &C); + fn delete_id(id: &str, actor_id: &str, conn: &C); } pub trait WithInbox { diff --git a/plume-common/src/activity_pub/mod.rs b/plume-common/src/activity_pub/mod.rs index 9238fdda..4dbd25a7 100644 --- a/plume-common/src/activity_pub/mod.rs +++ b/plume-common/src/activity_pub/mod.rs @@ -15,10 +15,10 @@ pub mod inbox; pub mod request; pub mod sign; -pub const CONTEXT_URL: &'static str = "https://www.w3.org/ns/activitystreams"; -pub const PUBLIC_VISIBILTY: &'static str = "https://www.w3.org/ns/activitystreams#Public"; +pub const CONTEXT_URL: &str = "https://www.w3.org/ns/activitystreams"; +pub const PUBLIC_VISIBILTY: &str = "https://www.w3.org/ns/activitystreams#Public"; -pub const AP_CONTENT_TYPE: &'static str = r#"application/ld+json; profile="https://www.w3.org/ns/activitystreams""#; +pub const AP_CONTENT_TYPE: &str = r#"application/ld+json; profile="https://www.w3.org/ns/activitystreams""#; pub fn ap_accept_header() -> Vec<&'static str> { vec![ @@ -84,7 +84,7 @@ impl<'a, 'r> FromRequest<'a, 'r> for ApRequest { .get_one("Accept") .map(|header| { header - .split(",") + .split(',') .map(|ct| match ct.trim() { // bool for Forward: true if found a valid Content-Type for Plume first (HTML), false otherwise "application/ld+json; profile=\"https://w3.org/ns/activitystreams\"" @@ -95,7 +95,7 @@ impl<'a, 'r> FromRequest<'a, 'r> for ApRequest { _ => Outcome::Forward(false), }) .fold(Outcome::Forward(false), |out, ct| { - if out.clone().forwarded().unwrap_or(out.is_success()) { + if out.clone().forwarded().unwrap_or_else(|| out.is_success()) { out } else { ct @@ -114,7 +114,7 @@ pub fn broadcast( let boxes = to .into_iter() .filter(|u| !u.is_local()) - .map(|u| u.get_shared_inbox_url().unwrap_or(u.get_inbox_url())) + .map(|u| u.get_shared_inbox_url().unwrap_or_else(|| u.get_inbox_url())) .collect::>() .unique(); @@ -124,13 +124,14 @@ pub fn broadcast( for inbox in boxes { // TODO: run it in Sidekiq or something like that + let body = signed.to_string(); let mut headers = request::headers(); - headers.insert("Digest", request::Digest::digest(signed.to_string())); + headers.insert("Digest", request::Digest::digest(&body)); let res = Client::new() - .post(&inbox[..]) + .post(&inbox) .headers(headers.clone()) - .header("Signature", request::signature(sender, headers)) - .body(signed.to_string()) + .header("Signature", request::signature(sender, &headers)) + .body(body) .send(); match res { Ok(mut r) => { @@ -161,6 +162,12 @@ impl Into for Id { } } +impl AsRef for Id { + fn as_ref(&self) -> &str { + &self.0 + } +} + pub trait IntoId { fn into_id(self) -> Id; } diff --git a/plume-common/src/activity_pub/request.rs b/plume-common/src/activity_pub/request.rs index 3f13dc9d..eea7dcf3 100644 --- a/plume-common/src/activity_pub/request.rs +++ b/plume-common/src/activity_pub/request.rs @@ -8,28 +8,28 @@ use std::time::SystemTime; use activity_pub::{AP_CONTENT_TYPE, ap_accept_header}; use activity_pub::sign::Signer; -const PLUME_USER_AGENT: &'static str = concat!("Plume/", env!("CARGO_PKG_VERSION")); +const PLUME_USER_AGENT: &str = concat!("Plume/", env!("CARGO_PKG_VERSION")); pub struct Digest(String); impl Digest { - pub fn digest(body: String) -> HeaderValue { + pub fn digest(body: &str) -> HeaderValue { let mut hasher = Hasher::new(MessageDigest::sha256()).expect("Digest::digest: initialization error"); hasher - .update(&body.into_bytes()[..]) + .update(body.as_bytes()) .expect("Digest::digest: content insertion error"); let res = base64::encode(&hasher.finish().expect("Digest::digest: finalizing error")); HeaderValue::from_str(&format!("SHA-256={}", res)) .expect("Digest::digest: header creation error") } - pub fn verify(&self, body: String) -> bool { + pub fn verify(&self, body: &str) -> bool { if self.algorithm() == "SHA-256" { let mut hasher = Hasher::new(MessageDigest::sha256()).expect("Digest::digest: initialization error"); hasher - .update(&body.into_bytes()) + .update(body.as_bytes()) .expect("Digest::digest: content insertion error"); self.value().deref() == hasher @@ -60,7 +60,7 @@ impl Digest { pub fn from_header(dig: &str) -> Result { if let Some(pos) = dig.find('=') { let pos = pos + 1; - if let Ok(_) = base64::decode(&dig[pos..]) { + if base64::decode(&dig[pos..]).is_ok() { Ok(Digest(dig.to_owned())) } else { Err(()) @@ -94,7 +94,7 @@ pub fn headers() -> HeaderMap { headers } -pub fn signature(signer: &S, headers: HeaderMap) -> HeaderValue { +pub fn signature(signer: &S, headers: &HeaderMap) -> HeaderValue { let signed_string = headers .iter() .map(|(h, v)| { @@ -114,8 +114,8 @@ pub fn signature(signer: &S, headers: HeaderMap) -> HeaderValue { .join(" ") .to_lowercase(); - let data = signer.sign(signed_string); - let sign = base64::encode(&data[..]); + let data = signer.sign(&signed_string); + let sign = base64::encode(&data); HeaderValue::from_str(&format!( "keyId=\"{key_id}\",algorithm=\"rsa-sha256\",headers=\"{signed_headers}\",signature=\"{signature}\"", diff --git a/plume-common/src/activity_pub/sign.rs b/plume-common/src/activity_pub/sign.rs index 83d1b3b7..6c8835ee 100644 --- a/plume-common/src/activity_pub/sign.rs +++ b/plume-common/src/activity_pub/sign.rs @@ -24,9 +24,9 @@ pub trait Signer { fn get_key_id(&self) -> String; /// Sign some data with the signer keypair - fn sign(&self, to_sign: String) -> Vec; + fn sign(&self, to_sign: &str) -> Vec; /// Verify if the signature is valid - fn verify(&self, data: String, signature: Vec) -> bool; + fn verify(&self, data: &str, signature: &[u8]) -> bool; } pub trait Signable { @@ -37,9 +37,9 @@ pub trait Signable { where T: Signer; - fn hash(data: String) -> String { - let bytes = data.into_bytes(); - hex::encode(sha256(&bytes[..])) + fn hash(data: &str) -> String { + let bytes = data.as_bytes(); + hex::encode(sha256(bytes)) } } @@ -53,15 +53,15 @@ impl Signable for serde_json::Value { }); let options_hash = Self::hash( - json!({ + &json!({ "@context": "https://w3id.org/identity/v1", "created": creation_date }).to_string(), ); - let document_hash = Self::hash(self.to_string()); + let document_hash = Self::hash(&self.to_string()); let to_be_signed = options_hash + &document_hash; - let signature = base64::encode(&creator.sign(to_be_signed)); + let signature = base64::encode(&creator.sign(&to_be_signed)); options["signatureValue"] = serde_json::Value::String(signature); self["signature"] = options; @@ -85,14 +85,14 @@ impl Signable for serde_json::Value { }; let creation_date = &signature_obj["created"]; let options_hash = Self::hash( - json!({ + &json!({ "@context": "https://w3id.org/identity/v1", "created": creation_date }).to_string(), ); - let document_hash = Self::hash(self.to_string()); + let document_hash = Self::hash(&self.to_string()); let to_be_signed = options_hash + &document_hash; - creator.verify(to_be_signed, signature) + creator.verify(&to_be_signed, &signature) } } @@ -105,15 +105,15 @@ pub enum SignatureValidity { } impl SignatureValidity { - pub fn is_secure(&self) -> bool { - self == &SignatureValidity::Valid + pub fn is_secure(self) -> bool { + self == SignatureValidity::Valid } } pub fn verify_http_headers( sender: &S, - all_headers: HeaderMap, - data: String, + all_headers: &HeaderMap, + data: &str, ) -> SignatureValidity { let sig_header = all_headers.get_one("Signature"); if sig_header.is_none() { @@ -151,7 +151,7 @@ pub fn verify_http_headers( .collect::>() .join("\n"); - if !sender.verify(h, base64::decode(signature).unwrap_or(Vec::new())) { + if !sender.verify(&h, &base64::decode(signature).unwrap_or_default()) { return SignatureValidity::Invalid; } if !headers.contains(&"digest") { @@ -160,7 +160,7 @@ pub fn verify_http_headers( } let digest = all_headers.get_one("digest").unwrap_or(""); let digest = request::Digest::from_header(digest); - if !digest.map(|d| d.verify(data)).unwrap_or(false) { + if !digest.map(|d| d.verify(&data)).unwrap_or(false) { // signature was valid, but body content does not match its digest SignatureValidity::Invalid } else { diff --git a/plume-common/src/utils.rs b/plume-common/src/utils.rs index 899c40bf..b82a4734 100644 --- a/plume-common/src/utils.rs +++ b/plume-common/src/utils.rs @@ -16,17 +16,15 @@ pub fn random_hex() -> String { } /// Remove non alphanumeric characters and CamelCase a string -pub fn make_actor_id(name: String) -> String { - name.as_str() - .to_camel_case() - .to_string() +pub fn make_actor_id(name: &str) -> String { + name.to_camel_case() .chars() .filter(|c| c.is_alphanumeric()) .collect() } -pub fn requires_login(message: &str, url: Uri) -> Flash { - Flash::new(Redirect::to(format!("/login?m={}", gettext(message.to_string()))), "callback", url.to_string()) +pub fn requires_login>>(message: &str, url: T) -> Flash { + Flash::new(Redirect::to(format!("/login?m={}", gettext(message.to_string()))), "callback", url.into().to_string()) } #[derive(Debug)] @@ -41,27 +39,26 @@ enum State { pub fn md_to_html(md: &str) -> (String, HashSet, HashSet) { let parser = Parser::new_ext(md, Options::all()); - let (parser, mentions, hashtags): (Vec>, Vec>, Vec>) = parser.map(|evt| match evt { + let (parser, mentions, hashtags): (Vec, Vec, Vec) = parser.map(|evt| match evt { Event::Text(txt) => { - let (evts, _, _, _, new_mentions, new_hashtags) = txt.chars().fold((vec![], State::Ready, String::new(), 0, vec![], vec![]), |(mut events, state, text_acc, n, mut mentions, mut hashtags), c| { + let (evts, _, _, _, new_mentions, new_hashtags) = txt.chars().fold((vec![], State::Ready, String::new(), 0, vec![], vec![]), |(mut events, state, mut text_acc, n, mut mentions, mut hashtags), c| { match state { State::Mention => { let char_matches = c.is_alphanumeric() || c == '@' || c == '.' || c == '-' || c == '_'; if char_matches && (n < (txt.chars().count() - 1)) { - (events, State::Mention, text_acc + c.to_string().as_ref(), n + 1, mentions, hashtags) + text_acc.push(c); + (events, State::Mention, text_acc, n + 1, mentions, hashtags) } else { - let mention = if char_matches { - text_acc + c.to_string().as_ref() - } else { - text_acc - }; - let short_mention = mention.clone(); - let short_mention = short_mention.splitn(1, '@').nth(0).unwrap_or(""); - let link = Tag::Link(format!("/@/{}/", mention).into(), short_mention.to_string().into()); + if char_matches { + text_acc.push(c) + } + let mention = text_acc; + let short_mention = mention.splitn(1, '@').nth(0).unwrap_or(""); + let link = Tag::Link(format!("/@/{}/", &mention).into(), short_mention.to_owned().into()); - mentions.push(mention); + mentions.push(mention.clone()); events.push(Event::Start(link.clone())); - events.push(Event::Text(format!("@{}", short_mention).into())); + events.push(Event::Text(format!("@{}", &short_mention).into())); events.push(Event::End(link)); (events, State::Ready, c.to_string(), n + 1, mentions, hashtags) @@ -70,24 +67,25 @@ pub fn md_to_html(md: &str) -> (String, HashSet, HashSet) { State::Hashtag => { let char_matches = c.is_alphanumeric(); if char_matches && (n < (txt.chars().count() -1)) { - (events, State::Hashtag, text_acc + c.to_string().as_ref(), n+1, mentions, hashtags) + text_acc.push(c); + (events, State::Hashtag, text_acc, n+1, mentions, hashtags) } else { - let hashtag = if char_matches { - text_acc + c.to_string().as_ref() - } else { - text_acc - }; - let link = Tag::Link(format!("/tag/{}", hashtag.to_camel_case()).into(), hashtag.to_string().into()); + if char_matches { + text_acc.push(c); + } + let hashtag = text_acc; + let link = Tag::Link(format!("/tag/{}", &hashtag.to_camel_case()).into(), hashtag.to_owned().into()); hashtags.push(hashtag.clone()); events.push(Event::Start(link.clone())); - events.push(Event::Text(format!("#{}", hashtag).into())); + events.push(Event::Text(format!("#{}", &hashtag).into())); events.push(Event::End(link)); (events, State::Ready, c.to_string(), n + 1, mentions, hashtags) } } State::Ready => { + text_acc.push(c); if c == '@' { events.push(Event::Text(text_acc.into())); (events, State::Mention, String::new(), n + 1, mentions, hashtags) @@ -96,27 +94,28 @@ pub fn md_to_html(md: &str) -> (String, HashSet, HashSet) { (events, State::Hashtag, String::new(), n + 1, mentions, hashtags) } else if c.is_alphanumeric() { if n >= (txt.chars().count() - 1) { // Add the text after at the end, even if it is not followed by a mention. - events.push(Event::Text((text_acc.clone() + c.to_string().as_ref()).into())) + events.push(Event::Text(text_acc.clone().into())) } - (events, State::Word, text_acc + c.to_string().as_ref(), n + 1, mentions, hashtags) + (events, State::Word, text_acc, n + 1, mentions, hashtags) } else { if n >= (txt.chars().count() - 1) { // Add the text after at the end, even if it is not followed by a mention. - events.push(Event::Text((text_acc.clone() + c.to_string().as_ref()).into())) + events.push(Event::Text(text_acc.clone().into())) } - (events, State::Ready, text_acc + c.to_string().as_ref(), n + 1, mentions, hashtags) + (events, State::Ready, text_acc, n + 1, mentions, hashtags) } } State::Word => { + text_acc.push(c); if c.is_alphanumeric() { if n >= (txt.chars().count() - 1) { // Add the text after at the end, even if it is not followed by a mention. - events.push(Event::Text((text_acc.clone() + c.to_string().as_ref()).into())) + events.push(Event::Text(text_acc.clone().into())) } - (events, State::Word, text_acc + c.to_string().as_ref(), n + 1, mentions, hashtags) + (events, State::Word, text_acc, n + 1, mentions, hashtags) } else { if n >= (txt.chars().count() - 1) { // Add the text after at the end, even if it is not followed by a mention. - events.push(Event::Text((text_acc.clone() + c.to_string().as_ref()).into())) + events.push(Event::Text(text_acc.clone().into())) } - (events, State::Ready, text_acc + c.to_string().as_ref(), n + 1, mentions, hashtags) + (events, State::Ready, text_acc, n + 1, mentions, hashtags) } } } @@ -124,15 +123,15 @@ pub fn md_to_html(md: &str) -> (String, HashSet, HashSet) { (evts, new_mentions, new_hashtags) }, _ => (vec![evt], vec![], vec![]) - }).fold((vec![],vec![],vec![]), |(mut parser, mut mention, mut hashtag), (p, m, h)| { - parser.push(p); - mention.push(m); - hashtag.push(h); + }).fold((vec![],vec![],vec![]), |(mut parser, mut mention, mut hashtag), (mut p, mut m, mut h)| { + parser.append(&mut p); + mention.append(&mut m); + hashtag.append(&mut h); (parser, mention, hashtag) }); - let parser = parser.into_iter().flatten(); - let mentions = mentions.into_iter().flatten().map(|m| String::from(m.trim())); - let hashtags = hashtags.into_iter().flatten().map(|h| String::from(h.trim())); + let parser = parser.into_iter(); + let mentions = mentions.into_iter().map(|m| String::from(m.trim())); + let hashtags = hashtags.into_iter().map(|h| String::from(h.trim())); // TODO: fetch mentionned profiles in background, if needed diff --git a/plume-models/src/api_tokens.rs b/plume-models/src/api_tokens.rs index d215cca0..b3f45773 100644 --- a/plume-models/src/api_tokens.rs +++ b/plume-models/src/api_tokens.rs @@ -42,7 +42,7 @@ pub struct NewApiToken { impl ApiToken { get!(api_tokens); insert!(api_tokens, NewApiToken); - find_by!(api_tokens, find_by_value, value as String); + find_by!(api_tokens, find_by_value, value as &str); pub fn can(&self, what: &'static str, scope: &'static str) -> bool { let full_scope = what.to_owned() + ":" + scope; @@ -78,11 +78,11 @@ impl<'a, 'r> FromRequest<'a, 'r> for ApiToken { if auth_type == "Bearer" { let conn = request.guard::().expect("Couldn't connect to DB"); - if let Some(token) = ApiToken::find_by_value(&*conn, val.to_string()) { + if let Some(token) = ApiToken::find_by_value(&*conn, val) { return Outcome::Success(token); } } - return Outcome::Forward(()); + Outcome::Forward(()) } } diff --git a/plume-models/src/apps.rs b/plume-models/src/apps.rs index ddae4814..d3883930 100644 --- a/plume-models/src/apps.rs +++ b/plume-models/src/apps.rs @@ -47,8 +47,8 @@ impl Provider for App { conn, NewApp { name: data.name, - client_id: client_id, - client_secret: client_secret, + client_id, + client_secret, redirect_uri: data.redirect_uri, website: data.website, }, @@ -76,5 +76,5 @@ impl Provider for App { impl App { get!(apps); insert!(apps, NewApp); - find_by!(apps, find_by_client_id, client_id as String); + find_by!(apps, find_by_client_id, client_id as &str); } diff --git a/plume-models/src/blogs.rs b/plume-models/src/blogs.rs index 69583cd7..82a6e0aa 100644 --- a/plume-models/src/blogs.rs +++ b/plume-models/src/blogs.rs @@ -58,13 +58,13 @@ pub struct NewBlog { pub public_key: String, } -const BLOG_PREFIX: &'static str = "~"; +const BLOG_PREFIX: &str = "~"; impl Blog { insert!(blogs, NewBlog); get!(blogs); - find_by!(blogs, find_by_ap_url, ap_url as String); - find_by!(blogs, find_by_name, actor_id as String, instance_id as i32); + find_by!(blogs, find_by_ap_url, ap_url as &str); + find_by!(blogs, find_by_name, actor_id as &str, instance_id as i32); pub fn get_instance(&self, conn: &Connection) -> Instance { Instance::get(conn, self.instance_id).expect("Blog::get_instance: instance not found error") @@ -93,28 +93,24 @@ impl Blog { .expect("Blog::find_for_author: blog loading error") } - pub fn find_local(conn: &Connection, name: String) -> Option { + pub fn find_local(conn: &Connection, name: &str) -> Option { Blog::find_by_name(conn, name, Instance::local_id(conn)) } - pub fn find_by_fqn(conn: &Connection, fqn: String) -> Option { - if fqn.contains("@") { + pub fn find_by_fqn(conn: &Connection, fqn: &str) -> Option { + if fqn.contains('@') { // remote blog match Instance::find_by_domain( conn, - String::from( - fqn.split("@") - .last() - .expect("Blog::find_by_fqn: unreachable"), - ), + fqn.split('@') + .last() + .expect("Blog::find_by_fqn: unreachable"), ) { Some(instance) => match Blog::find_by_name( conn, - String::from( - fqn.split("@") - .nth(0) - .expect("Blog::find_by_fqn: unreachable"), - ), + fqn.split('@') + .nth(0) + .expect("Blog::find_by_fqn: unreachable"), instance.id, ) { Some(u) => Some(u), @@ -128,8 +124,8 @@ impl Blog { } } - fn fetch_from_webfinger(conn: &Connection, acct: String) -> Option { - match resolve(acct.clone(), *USE_HTTPS) { + fn fetch_from_webfinger(conn: &Connection, acct: &str) -> Option { + match resolve(acct.to_owned(), *USE_HTTPS) { Ok(wf) => wf .links .into_iter() @@ -137,7 +133,7 @@ impl Blog { .and_then(|l| { Blog::fetch_from_url( conn, - l.href + &l.href .expect("Blog::fetch_from_webfinger: href not found error"), ) }), @@ -148,9 +144,9 @@ impl Blog { } } - fn fetch_from_url(conn: &Connection, url: String) -> Option { + fn fetch_from_url(conn: &Connection, url: &str) -> Option { let req = Client::new() - .get(&url[..]) + .get(url) .header( ACCEPT, HeaderValue::from_str( @@ -173,27 +169,26 @@ impl Blog { json.custom_props = ap_sign; // without this workaround, publicKey is not correctly deserialized Some(Blog::from_activity( conn, - json, - Url::parse(url.as_ref()) + &json, + Url::parse(url) .expect("Blog::fetch_from_url: url parsing error") .host_str() - .expect("Blog::fetch_from_url: host extraction error") - .to_string(), + .expect("Blog::fetch_from_url: host extraction error"), )) } Err(_) => None, } } - fn from_activity(conn: &Connection, acct: CustomGroup, inst: String) -> Blog { - let instance = match Instance::find_by_domain(conn, inst.clone()) { + fn from_activity(conn: &Connection, acct: &CustomGroup, inst: &str) -> Blog { + let instance = match Instance::find_by_domain(conn, inst) { Some(instance) => instance, None => { Instance::insert( conn, NewInstance { - public_domain: inst.clone(), - name: inst.clone(), + public_domain: inst.to_owned(), + name: inst.to_owned(), local: false, // We don't really care about all the following for remote instances long_description: SafeString::new(""), @@ -251,72 +246,72 @@ impl Blog { ) } - pub fn into_activity(&self, _conn: &Connection) -> CustomGroup { + pub fn to_activity(&self, _conn: &Connection) -> CustomGroup { let mut blog = Group::default(); blog.ap_actor_props .set_preferred_username_string(self.actor_id.clone()) - .expect("Blog::into_activity: preferredUsername error"); + .expect("Blog::to_activity: preferredUsername error"); blog.object_props .set_name_string(self.title.clone()) - .expect("Blog::into_activity: name error"); + .expect("Blog::to_activity: name error"); blog.ap_actor_props .set_outbox_string(self.outbox_url.clone()) - .expect("Blog::into_activity: outbox error"); + .expect("Blog::to_activity: outbox error"); blog.ap_actor_props .set_inbox_string(self.inbox_url.clone()) - .expect("Blog::into_activity: inbox error"); + .expect("Blog::to_activity: inbox error"); blog.object_props .set_summary_string(self.summary.clone()) - .expect("Blog::into_activity: summary error"); + .expect("Blog::to_activity: summary error"); blog.object_props .set_id_string(self.ap_url.clone()) - .expect("Blog::into_activity: id error"); + .expect("Blog::to_activity: id error"); let mut public_key = PublicKey::default(); public_key .set_id_string(format!("{}#main-key", self.ap_url)) - .expect("Blog::into_activity: publicKey.id error"); + .expect("Blog::to_activity: publicKey.id error"); public_key .set_owner_string(self.ap_url.clone()) - .expect("Blog::into_activity: publicKey.owner error"); + .expect("Blog::to_activity: publicKey.owner error"); public_key .set_public_key_pem_string(self.public_key.clone()) - .expect("Blog::into_activity: publicKey.publicKeyPem error"); + .expect("Blog::to_activity: publicKey.publicKeyPem error"); let mut ap_signature = ApSignature::default(); ap_signature .set_public_key_publickey(public_key) - .expect("Blog::into_activity: publicKey error"); + .expect("Blog::to_activity: publicKey error"); CustomGroup::new(blog, ap_signature) } pub fn update_boxes(&self, conn: &Connection) { let instance = self.get_instance(conn); - if self.outbox_url.len() == 0 { + if self.outbox_url.is_empty() { diesel::update(self) .set(blogs::outbox_url.eq(instance.compute_box( BLOG_PREFIX, - self.actor_id.clone(), + &self.actor_id, "outbox", ))) .execute(conn) .expect("Blog::update_boxes: outbox update error"); } - if self.inbox_url.len() == 0 { + if self.inbox_url.is_empty() { diesel::update(self) .set(blogs::inbox_url.eq(instance.compute_box( BLOG_PREFIX, - self.actor_id.clone(), + &self.actor_id, "inbox", ))) .execute(conn) .expect("Blog::update_boxes: inbox update error"); } - if self.ap_url.len() == 0 { + if self.ap_url.is_empty() { diesel::update(self) - .set(blogs::ap_url.eq(instance.compute_box(BLOG_PREFIX, self.actor_id.clone(), ""))) + .set(blogs::ap_url.eq(instance.compute_box(BLOG_PREFIX, &self.actor_id, ""))) .execute(conn) .expect("Blog::update_boxes: ap_url update error"); } @@ -367,7 +362,7 @@ impl Blog { mime_type: Some(String::from("application/atom+xml")), href: Some(self.get_instance(conn).compute_box( BLOG_PREFIX, - self.actor_id.clone(), + &self.actor_id, "feed.atom", )), template: None, @@ -382,11 +377,11 @@ impl Blog { } } - pub fn from_url(conn: &Connection, url: String) -> Option { - Blog::find_by_ap_url(conn, url.clone()).or_else(|| { + pub fn from_url(conn: &Connection, url: &str) -> Option { + Blog::find_by_ap_url(conn, url).or_else(|| { // The requested blog was not in the DB // We try to fetch it if it is remote - if Url::parse(url.as_ref()) + if Url::parse(url) .expect("Blog::from_url: ap_url parsing error") .host_str() .expect("Blog::from_url: host extraction error") != BASE_URL.as_str() @@ -454,7 +449,7 @@ impl sign::Signer for Blog { format!("{}#main-key", self.ap_url) } - fn sign(&self, to_sign: String) -> Vec { + fn sign(&self, to_sign: &str) -> Vec { let key = self.get_keypair(); let mut signer = Signer::new(MessageDigest::sha256(), &key).expect("Blog::sign: initialization error"); @@ -466,7 +461,7 @@ impl sign::Signer for Blog { .expect("Blog::sign: finalization error") } - fn verify(&self, data: String, signature: Vec) -> bool { + fn verify(&self, data: &str, signature: &[u8]) -> bool { let key = PKey::from_rsa( Rsa::public_key_from_pem(self.public_key.as_ref()) .expect("Blog::verify: pem parsing error"), @@ -491,12 +486,12 @@ impl NewBlog { ) -> NewBlog { let (pub_key, priv_key) = sign::gen_keypair(); NewBlog { - actor_id: actor_id, - title: title, - summary: summary, + actor_id, + title, + summary, outbox_url: String::from(""), inbox_url: String::from(""), - instance_id: instance_id, + instance_id, ap_url: String::from(""), public_key: String::from_utf8(pub_key).expect("NewBlog::new_local: public key error"), private_key: Some( @@ -725,7 +720,7 @@ pub(crate) mod tests { ); assert_eq!( - Blog::find_local(conn, "SomeName".to_owned()).unwrap().id, + Blog::find_local(conn, "SomeName").unwrap().id, blog.id ); diff --git a/plume-models/src/comments.rs b/plume-models/src/comments.rs index a9d3488c..4a1fdcdd 100644 --- a/plume-models/src/comments.rs +++ b/plume-models/src/comments.rs @@ -46,7 +46,7 @@ impl Comment { insert!(comments, NewComment); get!(comments); list_by!(comments, list_by_post, post_id as i32); - find_by!(comments, find_by_ap_url, ap_url as String); + find_by!(comments, find_by_ap_url, ap_url as &str); pub fn get_author(&self, conn: &Connection) -> User { User::get(conn, self.author_id).expect("Comment::get_author: author error") @@ -68,7 +68,7 @@ impl Comment { .len() // TODO count in database? } - pub fn to_json(&self, conn: &Connection, others: &Vec) -> serde_json::Value { + pub fn to_json(&self, conn: &Connection, others: &[Comment]) -> serde_json::Value { let mut json = serde_json::to_value(self).expect("Comment::to_json: serialization error"); json["author"] = self.get_author(conn).to_json(conn); let mentions = Mention::list_for_comment(conn, self.id) @@ -76,7 +76,7 @@ impl Comment { .map(|m| { m.get_mentioned(conn) .map(|u| u.get_fqn(conn)) - .unwrap_or(String::new()) + .unwrap_or_default() }) .collect::>(); json["mentions"] = serde_json::to_value(mentions).expect("Comment::to_json: mention error"); @@ -106,53 +106,53 @@ impl Comment { format!("{}comment/{}", self.get_post(conn).ap_url, self.id) } - pub fn into_activity(&self, conn: &Connection) -> Note { + pub fn to_activity(&self, conn: &Connection) -> Note { let (html, mentions, _hashtags) = utils::md_to_html(self.content.get().as_ref()); - let author = User::get(conn, self.author_id).expect("Comment::into_activity: author error"); + let author = User::get(conn, self.author_id).expect("Comment::to_activity: author error"); let mut note = Note::default(); let to = vec![Id::new(PUBLIC_VISIBILTY.to_string())]; note.object_props - .set_id_string(self.ap_url.clone().unwrap_or(String::new())) - .expect("Comment::into_activity: id error"); + .set_id_string(self.ap_url.clone().unwrap_or_default()) + .expect("Comment::to_activity: id error"); note.object_props .set_summary_string(self.spoiler_text.clone()) - .expect("Comment::into_activity: summary error"); + .expect("Comment::to_activity: summary error"); note.object_props .set_content_string(html) - .expect("Comment::into_activity: content error"); + .expect("Comment::to_activity: content error"); note.object_props .set_in_reply_to_link(Id::new(self.in_response_to_id.map_or_else( || { Post::get(conn, self.post_id) - .expect("Comment::into_activity: post error") + .expect("Comment::to_activity: post error") .ap_url }, |id| { let comm = - Comment::get(conn, id).expect("Comment::into_activity: comment error"); - comm.ap_url.clone().unwrap_or(comm.compute_id(conn)) + Comment::get(conn, id).expect("Comment::to_activity: comment error"); + comm.ap_url.clone().unwrap_or_else(|| comm.compute_id(conn)) }, ))) - .expect("Comment::into_activity: in_reply_to error"); + .expect("Comment::to_activity: in_reply_to error"); note.object_props .set_published_string(chrono::Utc::now().to_rfc3339()) - .expect("Comment::into_activity: published error"); + .expect("Comment::to_activity: published error"); note.object_props .set_attributed_to_link(author.clone().into_id()) - .expect("Comment::into_activity: attributed_to error"); + .expect("Comment::to_activity: attributed_to error"); note.object_props .set_to_link_vec(to.clone()) - .expect("Comment::into_activity: to error"); + .expect("Comment::to_activity: to error"); note.object_props .set_tag_link_vec( mentions .into_iter() - .map(|m| Mention::build_activity(conn, m)) + .map(|m| Mention::build_activity(conn, &m)) .collect::>(), ) - .expect("Comment::into_activity: tag error"); + .expect("Comment::to_activity: tag error"); note } @@ -160,7 +160,7 @@ impl Comment { let author = User::get(conn, self.author_id).expect("Comment::create_activity: author error"); - let note = self.into_activity(conn); + let note = self.to_activity(conn); let mut act = Create::default(); act.create_props .set_actor_link(author.into_id()) @@ -196,11 +196,11 @@ impl FromActivity for Comment { .object_props .in_reply_to .clone() - .expect("Comment::from_activity: not an answer error") + .expect("Comment::from_activity: not an answer error"); + let previous_url = previous_url .as_str() - .expect("Comment::from_activity: in_reply_to parsing error") - .to_string(); - let previous_comment = Comment::find_by_ap_url(conn, previous_url.clone()); + .expect("Comment::from_activity: in_reply_to parsing error"); + let previous_comment = Comment::find_by_ap_url(conn, previous_url); let comm = Comment::insert( conn, @@ -214,7 +214,7 @@ impl FromActivity for Comment { spoiler_text: note .object_props .summary_string() - .unwrap_or(String::from("")), + .unwrap_or_default(), ap_url: note.object_props.id_string().ok(), in_response_to_id: previous_comment.clone().map(|c| c.id), post_id: previous_comment.map(|c| c.post_id).unwrap_or_else(|| { @@ -222,7 +222,7 @@ impl FromActivity for Comment { .expect("Comment::from_activity: post error") .id }), - author_id: User::from_url(conn, actor.clone().into()) + author_id: User::from_url(conn, actor.as_ref()) .expect("Comment::from_activity: author error") .id, sensitive: false, // "sensitive" is not a standard property, we need to think about how to support it with the activitypub crate @@ -231,7 +231,7 @@ impl FromActivity for Comment { // save mentions if let Some(serde_json::Value::Array(tags)) = note.object_props.tag.clone() { - for tag in tags.into_iter() { + for tag in tags { serde_json::from_value::(tag) .map(|m| { let author = &Post::get(conn, comm.post_id) @@ -242,7 +242,7 @@ impl FromActivity for Comment { .href_string() .expect("Comment::from_activity: no href error") != author.ap_url.clone(); - Mention::from_activity(conn, m, comm.id, false, not_author) + Mention::from_activity(conn, &m, comm.id, false, not_author) }) .ok(); } diff --git a/plume-models/src/follows.rs b/plume-models/src/follows.rs index 25c6e6a1..b7faad95 100644 --- a/plume-models/src/follows.rs +++ b/plume-models/src/follows.rs @@ -37,7 +37,7 @@ pub struct NewFollow { impl Follow { insert!(follows, NewFollow); get!(follows); - find_by!(follows, find_by_ap_url, ap_url as String); + find_by!(follows, find_by_ap_url, ap_url as &str); pub fn find(conn: &Connection, from: i32, to: i32) -> Option { follows::table @@ -47,28 +47,28 @@ impl Follow { .ok() } - pub fn into_activity(&self, conn: &Connection) -> FollowAct { + pub fn to_activity(&self, conn: &Connection) -> FollowAct { let user = User::get(conn, self.follower_id) - .expect("Follow::into_activity: actor not found error"); + .expect("Follow::to_activity: actor not found error"); let target = User::get(conn, self.following_id) - .expect("Follow::into_activity: target not found error"); + .expect("Follow::to_activity: target not found error"); let mut act = FollowAct::default(); act.follow_props .set_actor_link::(user.clone().into_id()) - .expect("Follow::into_activity: actor error"); + .expect("Follow::to_activity: actor error"); act.follow_props - .set_object_object(user.into_activity(&*conn)) - .expect("Follow::into_activity: object error"); + .set_object_object(user.to_activity(&*conn)) + .expect("Follow::to_activity: object error"); act.object_props .set_id_string(self.ap_url.clone()) - .expect("Follow::into_activity: id error"); + .expect("Follow::to_activity: id error"); act.object_props .set_to_link(target.clone().into_id()) - .expect("Follow::into_activity: target error"); + .expect("Follow::to_activity: target error"); act.object_props .set_cc_link_vec::(vec![]) - .expect("Follow::into_activity: cc error"); + .expect("Follow::to_activity: cc error"); act } @@ -94,7 +94,7 @@ impl Follow { ); let mut accept = Accept::default(); - let accept_id = ap_url(format!("{}/follow/{}/accept", BASE_URL.as_str(), res.id)); + let accept_id = ap_url(&format!("{}/follow/{}/accept", BASE_URL.as_str(), &res.id)); accept .object_props .set_id_string(accept_id) @@ -136,15 +136,14 @@ impl FromActivity for Follow { .expect("Follow::from_activity: actor not found error") }); let from = - User::from_url(conn, from_id).expect("Follow::from_activity: actor not found error"); + User::from_url(conn, &from_id).expect("Follow::from_activity: actor not found error"); match User::from_url( conn, follow .follow_props .object .as_str() - .expect("Follow::from_activity: target url parsing error") - .to_string(), + .expect("Follow::from_activity: target url parsing error"), ) { Some(user) => Follow::accept_follow(conn, &from, &user, follow, from.id, user.id), None => { @@ -154,8 +153,7 @@ impl FromActivity for Follow { .follow_props .object .as_str() - .expect("Follow::from_activity: target url parsing error") - .to_string(), + .expect("Follow::from_activity: target url parsing error"), ).expect("Follow::from_activity: target not found error"); Follow::accept_follow(conn, &from, &blog, follow, from.id, blog.id) } @@ -201,12 +199,12 @@ impl Deletable for Follow { .set_id_string(format!("{}/undo", self.ap_url)) .expect("Follow::delete: id error"); undo.undo_props - .set_object_object(self.into_activity(conn)) + .set_object_object(self.to_activity(conn)) .expect("Follow::delete: object error"); undo } - fn delete_id(id: String, actor_id: String, conn: &Connection) { + fn delete_id(id: &str, actor_id: &str, conn: &Connection) { if let Some(follow) = Follow::find_by_ap_url(conn, id) { if let Some(user) = User::find_by_ap_url(conn, actor_id) { if user.id == follow.follower_id { diff --git a/plume-models/src/follows.rs.orig b/plume-models/src/follows.rs.orig deleted file mode 100644 index c2c962cb..00000000 --- a/plume-models/src/follows.rs.orig +++ /dev/null @@ -1,235 +0,0 @@ -use activitypub::{ - activity::{Accept, Follow as FollowAct, Undo}, - actor::Person, - Actor, -}; -use diesel::{self, ExpressionMethods, QueryDsl, RunQueryDsl}; - -<<<<<<< HEAD -use plume_common::activity_pub::{broadcast, Id, IntoId, inbox::{FromActivity, Notify, WithInbox, Deletable}, sign::Signer}; -use {BASE_URL, ap_url, Connection}; -======= ->>>>>>> Run rustfmt and rename instanceTests to instance_tests -use blogs::Blog; -use notifications::*; -use plume_common::activity_pub::{ - broadcast, - inbox::{Deletable, FromActivity, Notify, WithInbox}, - sign::Signer, - Id, IntoId, -}; -use schema::follows; -use users::User; -use Connection; - -#[derive(Clone, Queryable, Identifiable, Associations)] -#[belongs_to(User, foreign_key = "following_id")] -pub struct Follow { - pub id: i32, - pub follower_id: i32, - pub following_id: i32, - pub ap_url: String, -} - -#[derive(Insertable)] -#[table_name = "follows"] -pub struct NewFollow { - pub follower_id: i32, - pub following_id: i32, - pub ap_url: String, -} - -impl Follow { - insert!(follows, NewFollow); - get!(follows); - find_by!(follows, find_by_ap_url, ap_url as String); - - pub fn find(conn: &Connection, from: i32, to: i32) -> Option { - follows::table - .filter(follows::follower_id.eq(from)) - .filter(follows::following_id.eq(to)) - .get_result(conn) - .ok() - } - - pub fn into_activity(&self, conn: &Connection) -> FollowAct { - let user = User::get(conn, self.follower_id) - .expect("Follow::into_activity: actor not found error"); - let target = User::get(conn, self.following_id) - .expect("Follow::into_activity: target not found error"); - - let mut act = FollowAct::default(); - act.follow_props - .set_actor_link::(user.clone().into_id()) - .expect("Follow::into_activity: actor error"); - act.follow_props - .set_object_object(user.into_activity(&*conn)) - .expect("Follow::into_activity: object error"); - act.object_props - .set_id_string(self.ap_url.clone()) - .expect("Follow::into_activity: id error"); - act.object_props - .set_to_link(target.clone().into_id()) - .expect("Follow::into_activity: target error"); - act.object_props - .set_cc_link_vec::(vec![]) - .expect("Follow::into_activity: cc error"); - act - } - - /// from -> The one sending the follow request - /// target -> The target of the request, responding with Accept - pub fn accept_follow( - conn: &Connection, - from: &B, - target: &A, - follow: FollowAct, - from_id: i32, - target_id: i32, - ) -> Follow { - let from_url: String = from.clone().into_id().into(); - let target_url: String = target.clone().into_id().into(); - let res = Follow::insert( - conn, - NewFollow { - follower_id: from_id, - following_id: target_id, - ap_url: format!("{}/follow/{}", from_url, target_url), - }, - ); - - let mut accept = Accept::default(); -<<<<<<< HEAD - let accept_id = ap_url(format!("{}/follow/{}/accept", BASE_URL.as_str(), res.id)); - accept.object_props.set_id_string(accept_id).expect("Follow::accept_follow: id error"); - accept.object_props.set_to_link(from.clone().into_id()).expect("Follow::accept_follow: to error"); - accept.object_props.set_cc_link_vec::(vec![]).expect("Follow::accept_follow: cc error"); - accept.accept_props.set_actor_link::(target.clone().into_id()).expect("Follow::accept_follow: actor error"); - accept.accept_props.set_object_object(follow).expect("Follow::accept_follow: object error"); -======= - let accept_id = format!( - "{}#accept", - follow.object_props.id_string().unwrap_or(String::new()) - ); - accept - .object_props - .set_id_string(accept_id) - .expect("Follow::accept_follow: id error"); - accept - .object_props - .set_to_link(from.clone().into_id()) - .expect("Follow::accept_follow: to error"); - accept - .object_props - .set_cc_link_vec::(vec![]) - .expect("Follow::accept_follow: cc error"); - accept - .accept_props - .set_actor_link::(target.clone().into_id()) - .expect("Follow::accept_follow: actor error"); - accept - .accept_props - .set_object_object(follow) - .expect("Follow::accept_follow: object error"); ->>>>>>> Run rustfmt and rename instanceTests to instance_tests - broadcast(&*target, accept, vec![from.clone()]); - res - } -} - -impl FromActivity for Follow { - fn from_activity(conn: &Connection, follow: FollowAct, _actor: Id) -> Follow { - let from_id = follow - .follow_props - .actor_link::() - .map(|l| l.into()) - .unwrap_or_else(|_| { - follow - .follow_props - .actor_object::() - .expect("Follow::from_activity: actor not found error") - .object_props - .id_string() - .expect("Follow::from_activity: actor not found error") - }); - let from = - User::from_url(conn, from_id).expect("Follow::from_activity: actor not found error"); - match User::from_url( - conn, - follow - .follow_props - .object - .as_str() - .expect("Follow::from_activity: target url parsing error") - .to_string(), - ) { - Some(user) => Follow::accept_follow(conn, &from, &user, follow, from.id, user.id), - None => { - let blog = Blog::from_url( - conn, - follow - .follow_props - .object - .as_str() - .expect("Follow::from_activity: target url parsing error") - .to_string(), - ).expect("Follow::from_activity: target not found error"); - Follow::accept_follow(conn, &from, &blog, follow, from.id, blog.id) - } - } - } -} - -impl Notify for Follow { - fn notify(&self, conn: &Connection) { - Notification::insert( - conn, - NewNotification { - kind: notification_kind::FOLLOW.to_string(), - object_id: self.id, - user_id: self.following_id, - }, - ); - } -} - -impl Deletable for Follow { - fn delete(&self, conn: &Connection) -> Undo { - diesel::delete(self) - .execute(conn) - .expect("Follow::delete: follow deletion error"); - - // delete associated notification if any - if let Some(notif) = Notification::find(conn, notification_kind::FOLLOW, self.id) { - diesel::delete(¬if) - .execute(conn) - .expect("Follow::delete: notification deletion error"); - } - - let mut undo = Undo::default(); - undo.undo_props - .set_actor_link( - User::get(conn, self.follower_id) - .expect("Follow::delete: actor error") - .into_id(), - ) - .expect("Follow::delete: actor error"); - undo.object_props - .set_id_string(format!("{}/undo", self.ap_url)) - .expect("Follow::delete: id error"); - undo.undo_props - .set_object_object(self.into_activity(conn)) - .expect("Follow::delete: object error"); - undo - } - - fn delete_id(id: String, actor_id: String, conn: &Connection) { - if let Some(follow) = Follow::find_by_ap_url(conn, id) { - if let Some(user) = User::find_by_ap_url(conn, actor_id) { - if user.id == follow.follower_id { - follow.delete(conn); - } - } - } - } -} diff --git a/plume-models/src/instance.rs b/plume-models/src/instance.rs index 538320fe..71f29528 100644 --- a/plume-models/src/instance.rs +++ b/plume-models/src/instance.rs @@ -74,7 +74,7 @@ impl Instance { insert!(instances, NewInstance); get!(instances); - find_by!(instances, find_by_domain, public_domain as String); + find_by!(instances, find_by_domain, public_domain as &str); pub fn toggle_block(&self, conn: &Connection) { diesel::update(self) @@ -84,13 +84,13 @@ impl Instance { } /// id: AP object id - pub fn is_blocked(conn: &Connection, id: String) -> bool { + pub fn is_blocked(conn: &Connection, id: &str) -> bool { for block in instances::table .filter(instances::blocked.eq(true)) .get_results::(conn) .expect("Instance::is_blocked: loading error") { - if id.starts_with(format!("https://{}/", block.public_domain).as_str()) { + if id.starts_with(&format!("https://{}/", block.public_domain)) { return true; } } @@ -99,12 +99,12 @@ impl Instance { } pub fn has_admin(&self, conn: &Connection) -> bool { - users::table + !users::table .filter(users::instance_id.eq(self.id)) .filter(users::is_admin.eq(true)) .load::(conn) .expect("Instance::has_admin: loading error") - .len() > 0 + .is_empty() } pub fn main_admin(&self, conn: &Connection) -> User { @@ -118,11 +118,11 @@ impl Instance { pub fn compute_box( &self, - prefix: &'static str, - name: String, - box_name: &'static str, + prefix: &str, + name: &str, + box_name: &str, ) -> String { - ap_url(format!( + ap_url(&format!( "{instance}/{prefix}/{name}/{box_name}", instance = self.public_domain, prefix = prefix, @@ -219,7 +219,7 @@ pub(crate) mod tests { .map(|inst| { ( inst.clone(), - Instance::find_by_domain(conn, inst.public_domain.clone()) + Instance::find_by_domain(conn, &inst.public_domain) .unwrap_or_else(|| Instance::insert(conn, inst)), ) }) @@ -332,12 +332,12 @@ pub(crate) mod tests { 0 ); assert_eq!( - Instance::is_blocked(conn, format!("https://{}/something", inst.public_domain)), + Instance::is_blocked(conn, &format!("https://{}/something", inst.public_domain)), inst.blocked ); assert_eq!( - Instance::is_blocked(conn, format!("https://{}a/something", inst.public_domain)), - Instance::find_by_domain(conn, format!("{}a", inst.public_domain)) + Instance::is_blocked(conn, &format!("https://{}a/something", inst.public_domain)), + Instance::find_by_domain(conn, &format!("{}a", inst.public_domain)) .map(|inst| inst.blocked) .unwrap_or(false) ); @@ -346,12 +346,12 @@ pub(crate) mod tests { let inst = Instance::get(conn, inst.id).unwrap(); assert_eq!(inst.blocked, blocked); assert_eq!( - Instance::is_blocked(conn, format!("https://{}/something", inst.public_domain)), + Instance::is_blocked(conn, &format!("https://{}/something", inst.public_domain)), inst.blocked ); assert_eq!( - Instance::is_blocked(conn, format!("https://{}a/something", inst.public_domain)), - Instance::find_by_domain(conn, format!("{}a", inst.public_domain)) + Instance::is_blocked(conn, &format!("https://{}a/something", inst.public_domain)), + Instance::find_by_domain(conn, &format!("{}a", inst.public_domain)) .map(|inst| inst.blocked) .unwrap_or(false) ); diff --git a/plume-models/src/lib.rs b/plume-models/src/lib.rs index 0979ebe3..2a7189b9 100644 --- a/plume-models/src/lib.rs +++ b/plume-models/src/lib.rs @@ -31,6 +31,11 @@ extern crate diesel_migrations; use std::env; +#[cfg(not(any(feature = "sqlite", feature = "postgres")))] +compile_error!("Either feature \"sqlite\" or \"postgres\" must be enabled for this crate."); +#[cfg(all(feature = "sqlite", feature = "postgres"))] +compile_error!("Either feature \"sqlite\" or \"postgres\" must be enabled for this crate."); + #[cfg(all(feature = "sqlite", not(feature = "postgres")))] pub type Connection = diesel::SqliteConnection; @@ -51,7 +56,7 @@ pub type Connection = diesel::PgConnection; /// Model::name_of_the_function(connection, String::new(), 0); /// ``` macro_rules! find_by { - ($table:ident, $fn:ident, $($col:ident as $type:ident),+) => { + ($table:ident, $fn:ident, $($col:ident as $type:ty),+) => { /// Try to find a $table with a given $col pub fn $fn(conn: &crate::Connection, $($col: $type),+) -> Option { $table::table @@ -77,7 +82,7 @@ macro_rules! find_by { /// Model::name_of_the_function(connection, String::new()); /// ``` macro_rules! list_by { - ($table:ident, $fn:ident, $($col:ident as $type:ident),+) => { + ($table:ident, $fn:ident, $($col:ident as $type:ty),+) => { /// Try to find a $table with a given $col pub fn $fn(conn: &crate::Connection, $($col: $type),+) -> Vec { $table::table @@ -200,9 +205,9 @@ macro_rules! last { } lazy_static! { - pub static ref BASE_URL: String = env::var("BASE_URL").unwrap_or(format!( + pub static ref BASE_URL: String = env::var("BASE_URL").unwrap_or_else(|_| format!( "127.0.0.1:{}", - env::var("ROCKET_PORT").unwrap_or(String::from("8000")) + env::var("ROCKET_PORT").unwrap_or_else(|_| String::from("8000")) )); pub static ref USE_HTTPS: bool = env::var("USE_HTTPS").map(|val| val == "1").unwrap_or(true); } @@ -215,16 +220,16 @@ static DB_NAME: &str = "plume_tests"; #[cfg(all(feature = "postgres", not(feature = "sqlite")))] lazy_static! { pub static ref DATABASE_URL: String = - env::var("DATABASE_URL").unwrap_or(format!("postgres://plume:plume@localhost/{}", DB_NAME)); + env::var("DATABASE_URL").unwrap_or_else(|_| format!("postgres://plume:plume@localhost/{}", DB_NAME)); } #[cfg(all(feature = "sqlite", not(feature = "postgres")))] lazy_static! { pub static ref DATABASE_URL: String = - env::var("DATABASE_URL").unwrap_or(format!("{}.sqlite", DB_NAME)); + env::var("DATABASE_URL").unwrap_or_else(|_| format!("{}.sqlite", DB_NAME)); } -pub fn ap_url(url: String) -> String { +pub fn ap_url(url: &str) -> String { let scheme = if *USE_HTTPS { "https" } else { "http" }; format!("{}://{}", scheme, url) } diff --git a/plume-models/src/likes.rs b/plume-models/src/likes.rs index a8c6bc2b..eb043b6e 100644 --- a/plume-models/src/likes.rs +++ b/plume-models/src/likes.rs @@ -32,11 +32,11 @@ pub struct NewLike { impl Like { insert!(likes, NewLike); get!(likes); - find_by!(likes, find_by_ap_url, ap_url as String); + find_by!(likes, find_by_ap_url, ap_url as &str); find_by!(likes, find_by_user_on_post, user_id as i32, post_id as i32); pub fn update_ap_url(&self, conn: &Connection) { - if self.ap_url.len() == 0 { + if self.ap_url.is_empty() { diesel::update(self) .set(likes::ap_url.eq(format!( "{}/like/{}", @@ -48,31 +48,31 @@ impl Like { } } - pub fn into_activity(&self, conn: &Connection) -> activity::Like { + pub fn to_activity(&self, conn: &Connection) -> activity::Like { let mut act = activity::Like::default(); act.like_props .set_actor_link( User::get(conn, self.user_id) - .expect("Like::into_activity: user error") + .expect("Like::to_activity: user error") .into_id(), ) - .expect("Like::into_activity: actor error"); + .expect("Like::to_activity: actor error"); act.like_props .set_object_link( Post::get(conn, self.post_id) - .expect("Like::into_activity: post error") + .expect("Like::to_activity: post error") .into_id(), ) - .expect("Like::into_activity: object error"); + .expect("Like::to_activity: object error"); act.object_props .set_to_link(Id::new(PUBLIC_VISIBILTY.to_string())) - .expect("Like::into_activity: to error"); + .expect("Like::to_activity: to error"); act.object_props .set_cc_link_vec::(vec![]) - .expect("Like::into_activity: cc error"); + .expect("Like::to_activity: cc error"); act.object_props .set_id_string(self.ap_url.clone()) - .expect("Like::into_activity: id error"); + .expect("Like::to_activity: id error"); act } @@ -85,23 +85,21 @@ impl FromActivity for Like { like.like_props .actor .as_str() - .expect("Like::from_activity: actor error") - .to_string(), + .expect("Like::from_activity: actor error"), ); let post = Post::find_by_ap_url( conn, like.like_props .object .as_str() - .expect("Like::from_activity: object error") - .to_string(), + .expect("Like::from_activity: object error"), ); let res = Like::insert( conn, NewLike { post_id: post.expect("Like::from_activity: post error").id, user_id: liker.expect("Like::from_activity: user error").id, - ap_url: like.object_props.id_string().unwrap_or(String::from("")), + ap_url: like.object_props.id_string().unwrap_or_default(), }, ); res.notify(conn); @@ -147,7 +145,7 @@ impl Deletable for Like { ) .expect("Like::delete: actor error"); act.undo_props - .set_object_object(self.into_activity(conn)) + .set_object_object(self.to_activity(conn)) .expect("Like::delete: object error"); act.object_props .set_id_string(format!("{}#delete", self.ap_url)) @@ -162,8 +160,8 @@ impl Deletable for Like { act } - fn delete_id(id: String, actor_id: String, conn: &Connection) { - if let Some(like) = Like::find_by_ap_url(conn, id.into()) { + fn delete_id(id: &str, actor_id: &str, conn: &Connection) { + if let Some(like) = Like::find_by_ap_url(conn, id) { if let Some(user) = User::find_by_ap_url(conn, actor_id) { if user.id == like.user_id { like.delete(conn); diff --git a/plume-models/src/medias.rs b/plume-models/src/medias.rs index f2caa18c..64f38bc1 100644 --- a/plume-models/src/medias.rs +++ b/plume-models/src/medias.rs @@ -110,9 +110,9 @@ impl Media { pub fn url(&self, conn: &Connection) -> String { if self.is_remote { - self.remote_url.clone().unwrap_or(String::new()) + self.remote_url.clone().unwrap_or_default() } else { - ap_url(format!( + ap_url(&format!( "{}/{}", Instance::get_local(conn) .expect("Media::url: local instance not found error") @@ -154,13 +154,13 @@ impl Media { } // TODO: merge with save_remote? - pub fn from_activity(conn: &Connection, image: Image) -> Option { + pub fn from_activity(conn: &Connection, image: &Image) -> Option { let remote_url = image.object_props.url_string().ok()?; let ext = remote_url .rsplit('.') .next() .map(|ext| ext.to_owned()) - .unwrap_or("png".to_owned()); + .unwrap_or_else(|| String::from("png")); let path = Path::new("static") .join("media") @@ -189,7 +189,7 @@ impl Media { .ok()? .into_iter() .next()? - .into(), + .as_ref(), )?.id, }, )) diff --git a/plume-models/src/mentions.rs b/plume-models/src/mentions.rs index 9620fb69..c424819e 100644 --- a/plume-models/src/mentions.rs +++ b/plume-models/src/mentions.rs @@ -30,7 +30,7 @@ pub struct NewMention { impl Mention { insert!(mentions, NewMention); get!(mentions); - find_by!(mentions, find_by_ap_url, ap_url as String); + find_by!(mentions, find_by_ap_url, ap_url as &str); list_by!(mentions, list_for_user, mentioned_id as i32); list_by!(mentions, list_for_post, post_id as i32); list_by!(mentions, list_for_comment, comment_id as i32); @@ -54,12 +54,12 @@ impl Mention { } } - pub fn build_activity(conn: &Connection, ment: String) -> link::Mention { - let user = User::find_by_fqn(conn, ment.clone()); + pub fn build_activity(conn: &Connection, ment: &str) -> link::Mention { + let user = User::find_by_fqn(conn, ment); let mut mention = link::Mention::default(); mention .link_props - .set_href_string(user.clone().map(|u| u.ap_url).unwrap_or(String::new())) + .set_href_string(user.clone().map(|u| u.ap_url).unwrap_or_default()) .expect("Mention::build_activity: href error"); mention .link_props @@ -73,13 +73,13 @@ impl Mention { let mut mention = link::Mention::default(); mention .link_props - .set_href_string(user.clone().map(|u| u.ap_url).unwrap_or(String::new())) + .set_href_string(user.clone().map(|u| u.ap_url).unwrap_or_default()) .expect("Mention::to_activity: href error"); mention .link_props .set_name_string( user.map(|u| format!("@{}", u.get_fqn(conn))) - .unwrap_or(String::new()), + .unwrap_or_default(), ) .expect("Mention::to_activity: mention error"); mention @@ -87,23 +87,23 @@ impl Mention { pub fn from_activity( conn: &Connection, - ment: link::Mention, + ment: &link::Mention, inside: i32, in_post: bool, notify: bool, ) -> Option { let ap_url = ment.link_props.href_string().ok()?; - let mentioned = User::find_by_ap_url(conn, ap_url)?; + let mentioned = User::find_by_ap_url(conn, &ap_url)?; if in_post { - Post::get(conn, inside.clone().into()).map(|post| { + Post::get(conn, inside).map(|post| { let res = Mention::insert( conn, NewMention { mentioned_id: mentioned.id, post_id: Some(post.id), comment_id: None, - ap_url: ment.link_props.href_string().unwrap_or(String::new()), + ap_url: ment.link_props.href_string().unwrap_or_default(), }, ); if notify { @@ -112,14 +112,14 @@ impl Mention { res }) } else { - Comment::get(conn, inside.into()).map(|comment| { + Comment::get(conn, inside).map(|comment| { let res = Mention::insert( conn, NewMention { mentioned_id: mentioned.id, post_id: None, comment_id: Some(comment.id), - ap_url: ment.link_props.href_string().unwrap_or(String::new()), + ap_url: ment.link_props.href_string().unwrap_or_default(), }, ); if notify { @@ -132,7 +132,9 @@ impl Mention { pub fn delete(&self, conn: &Connection) { //find related notifications and delete them - Notification::find(conn, notification_kind::MENTION, self.id).map(|n| n.delete(conn)); + if let Some(n) = Notification::find(conn, notification_kind::MENTION, self.id) { + n.delete(conn) + } diesel::delete(self) .execute(conn) .expect("Mention::delete: mention deletion error"); @@ -141,7 +143,7 @@ impl Mention { impl Notify for Mention { fn notify(&self, conn: &Connection) { - self.get_mentioned(conn).map(|m| { + if let Some(m) = self.get_mentioned(conn) { Notification::insert( conn, NewNotification { @@ -150,6 +152,6 @@ impl Notify for Mention { user_id: m.id, }, ); - }); + } } } diff --git a/plume-models/src/notifications.rs b/plume-models/src/notifications.rs index 8142b68e..fe7a00f7 100644 --- a/plume-models/src/notifications.rs +++ b/plume-models/src/notifications.rs @@ -13,11 +13,11 @@ use users::User; use Connection; pub mod notification_kind { - pub const COMMENT: &'static str = "COMMENT"; - pub const FOLLOW: &'static str = "FOLLOW"; - pub const LIKE: &'static str = "LIKE"; - pub const MENTION: &'static str = "MENTION"; - pub const RESHARE: &'static str = "RESHARE"; + pub const COMMENT: &str = "COMMENT"; + pub const FOLLOW: &str = "FOLLOW"; + pub const LIKE: &str = "LIKE"; + pub const MENTION: &str = "MENTION"; + pub const RESHARE: &str = "RESHARE"; } #[derive(Clone, Queryable, Identifiable, Serialize)] diff --git a/plume-models/src/posts.rs b/plume-models/src/posts.rs index 823281c7..773169d5 100644 --- a/plume-models/src/posts.rs +++ b/plume-models/src/posts.rs @@ -119,7 +119,7 @@ impl<'a> Provider<(&'a Connection, Option)> for Post { }) .collect() }) - .unwrap_or(vec![]) + .unwrap_or_default() } fn create( @@ -151,8 +151,8 @@ impl Post { insert!(posts, NewPost); get!(posts); update!(posts); - find_by!(posts, find_by_slug, slug as String, blog_id as i32); - find_by!(posts, find_by_ap_url, ap_url as String); + find_by!(posts, find_by_slug, slug as &str, blog_id as i32); + find_by!(posts, find_by_ap_url, ap_url as &str); pub fn list_by_tag(conn: &Connection, tag: String, (min, max): (i32, i32)) -> Vec { use schema::tags; @@ -372,7 +372,7 @@ impl Post { } pub fn update_ap_url(&self, conn: &Connection) -> Post { - if self.ap_url.len() == 0 { + if self.ap_url.is_empty() { diesel::update(self) .set(posts::ap_url.eq(self.compute_id(conn))) .execute(conn) @@ -389,16 +389,15 @@ impl Post { .into_iter() .map(|a| a.get_followers(conn)) .collect::>>(); - let to = followers.into_iter().fold(vec![], |mut acc, f| { + followers.into_iter().fold(vec![], |mut acc, f| { for x in f { acc.push(x.ap_url); } acc - }); - to + }) } - pub fn into_activity(&self, conn: &Connection) -> Article { + pub fn to_activity(&self, conn: &Connection) -> Article { let mut to = self.get_receivers_urls(conn); to.push(PUBLIC_VISIBILTY.to_string()); @@ -408,7 +407,7 @@ impl Post { .collect::>(); let mut tags_json = Tag::for_post(conn, self.id) .into_iter() - .map(|t| json!(t.into_activity(conn))) + .map(|t| json!(t.to_activity(conn))) .collect::>(); mentions_json.append(&mut tags_json); @@ -416,11 +415,11 @@ impl Post { article .object_props .set_name_string(self.title.clone()) - .expect("Post::into_activity: name error"); + .expect("Post::to_activity: name error"); article .object_props .set_id_string(self.ap_url.clone()) - .expect("Post::into_activity: id error"); + .expect("Post::to_activity: id error"); let mut authors = self .get_authors(conn) @@ -431,76 +430,76 @@ impl Post { article .object_props .set_attributed_to_link_vec::(authors) - .expect("Post::into_activity: attributedTo error"); + .expect("Post::to_activity: attributedTo error"); article .object_props .set_content_string(self.content.get().clone()) - .expect("Post::into_activity: content error"); + .expect("Post::to_activity: content error"); article .ap_object_props .set_source_object(Source { content: self.source.clone(), media_type: String::from("text/markdown"), }) - .expect("Post::into_activity: source error"); + .expect("Post::to_activity: source error"); article .object_props .set_published_utctime(Utc.from_utc_datetime(&self.creation_date)) - .expect("Post::into_activity: published error"); + .expect("Post::to_activity: published error"); article .object_props .set_summary_string(self.subtitle.clone()) - .expect("Post::into_activity: summary error"); + .expect("Post::to_activity: summary error"); article.object_props.tag = Some(json!(mentions_json)); if let Some(media_id) = self.cover_id { - let media = Media::get(conn, media_id).expect("Post::into_activity: get cover error"); + let media = Media::get(conn, media_id).expect("Post::to_activity: get cover error"); let mut cover = Image::default(); cover .object_props .set_url_string(media.url(conn)) - .expect("Post::into_activity: icon.url error"); + .expect("Post::to_activity: icon.url error"); if media.sensitive { cover .object_props - .set_summary_string(media.content_warning.unwrap_or(String::new())) - .expect("Post::into_activity: icon.summary error"); + .set_summary_string(media.content_warning.unwrap_or_default()) + .expect("Post::to_activity: icon.summary error"); } cover .object_props .set_content_string(media.alt_text) - .expect("Post::into_activity: icon.content error"); + .expect("Post::to_activity: icon.content error"); cover .object_props .set_attributed_to_link_vec(vec![ User::get(conn, media.owner_id) - .expect("Post::into_activity: media owner not found") + .expect("Post::to_activity: media owner not found") .into_id(), ]) - .expect("Post::into_activity: icon.attributedTo error"); + .expect("Post::to_activity: icon.attributedTo error"); article .object_props .set_icon_object(cover) - .expect("Post::into_activity: icon error"); + .expect("Post::to_activity: icon error"); } article .object_props .set_url_string(self.ap_url.clone()) - .expect("Post::into_activity: url error"); + .expect("Post::to_activity: url error"); article .object_props .set_to_link_vec::(to.into_iter().map(Id::new).collect()) - .expect("Post::into_activity: to error"); + .expect("Post::to_activity: to error"); article .object_props .set_cc_link_vec::(vec![]) - .expect("Post::into_activity: cc error"); + .expect("Post::to_activity: cc error"); article } pub fn create_activity(&self, conn: &Connection) -> Create { - let article = self.into_activity(conn); + let article = self.to_activity(conn); let mut act = Create::default(); act.object_props .set_id_string(format!("{}activity", self.ap_url)) @@ -531,7 +530,7 @@ impl Post { } pub fn update_activity(&self, conn: &Connection) -> Update { - let article = self.into_activity(conn); + let article = self.to_activity(conn); let mut act = Update::default(); act.object_props .set_id_string(format!("{}/update-{}", self.ap_url, Utc::now().timestamp())) @@ -561,12 +560,12 @@ impl Post { act } - pub fn handle_update(conn: &Connection, updated: Article) { + pub fn handle_update(conn: &Connection, updated: &Article) { let id = updated .object_props .id_string() .expect("Post::handle_update: id error"); - let mut post = Post::find_by_ap_url(conn, id).expect("Post::handle_update: finding error"); + let mut post = Post::find_by_ap_url(conn, &id).expect("Post::handle_update: finding error"); if let Ok(title) = updated.object_props.name_string() { post.slug = title.to_kebab_case(); @@ -598,7 +597,7 @@ impl Post { let mut mentions = vec![]; let mut tags = vec![]; let mut hashtags = vec![]; - for tag in mention_tags.into_iter() { + for tag in mention_tags { serde_json::from_value::(tag.clone()) .map(|m| mentions.push(m)) .ok(); @@ -632,7 +631,7 @@ impl Post { m.link_props .href_string() .ok() - .and_then(|ap_url| User::find_by_ap_url(conn, ap_url)) + .and_then(|ap_url| User::find_by_ap_url(conn, &ap_url)) .map(|u| u.id), m, ) @@ -651,9 +650,9 @@ impl Post { .iter() .map(|m| m.mentioned_id) .collect::>(); - for (m, id) in mentions.iter() { + for (m, id) in &mentions { if !old_user_mentioned.contains(&id) { - Mention::from_activity(&*conn, m.clone(), self.id, true, true); + Mention::from_activity(&*conn, &m, self.id, true, true); } } @@ -689,13 +688,13 @@ impl Post { }) .collect::>(); - for t in tags.into_iter() { + for t in tags { if !t .name_string() .map(|n| old_tags_name.contains(&n)) .unwrap_or(true) { - Tag::from_activity(conn, t, self.id, false); + Tag::from_activity(conn, &t, self.id, false); } } @@ -726,13 +725,13 @@ impl Post { }) .collect::>(); - for t in tags.into_iter() { + for t in tags { if !t .name_string() .map(|n| old_tags_name.contains(&n)) .unwrap_or(true) { - Tag::from_activity(conn, t, self.id, true); + Tag::from_activity(conn, &t, self.id, true); } } @@ -757,7 +756,7 @@ impl Post { } pub fn compute_id(&self, conn: &Connection) -> String { - ap_url(format!( + ap_url(&format!( "{}/~/{}/{}/", BASE_URL.as_str(), self.get_blog(conn).get_fqn(conn), @@ -770,7 +769,7 @@ impl FromActivity for Post { fn from_activity(conn: &Connection, article: Article, _actor: Id) -> Post { if let Some(post) = Post::find_by_ap_url( conn, - article.object_props.id_string().unwrap_or(String::new()), + &article.object_props.id_string().unwrap_or_default(), ) { post } else { @@ -781,12 +780,12 @@ impl FromActivity for Post { .into_iter() .fold((None, vec![]), |(blog, mut authors), link| { let url: String = link.into(); - match User::from_url(conn, url.clone()) { + match User::from_url(conn, &url) { Some(user) => { authors.push(user); (blog, authors) } - None => (blog.or_else(|| Blog::from_url(conn, url)), authors), + None => (blog.or_else(|| Blog::from_url(conn, &url)), authors), } }); @@ -794,7 +793,7 @@ impl FromActivity for Post { .object_props .icon_object::() .ok() - .and_then(|img| Media::from_activity(conn, img).map(|m| m.id)); + .and_then(|img| Media::from_activity(conn, &img).map(|m| m.id)); let title = article .object_props @@ -805,7 +804,7 @@ impl FromActivity for Post { NewPost { blog_id: blog.expect("Post::from_activity: blog not found error").id, slug: title.to_kebab_case(), - title: title, + title, content: SafeString::new( &article .object_props @@ -815,7 +814,7 @@ impl FromActivity for Post { published: true, license: String::from("CC-BY-SA"), // TODO // FIXME: This is wrong: with this logic, we may use the display URL as the AP ID. We need two different fields - ap_url: article.object_props.url_string().unwrap_or( + ap_url: article.object_props.url_string().unwrap_or_else(|_| article .object_props .id_string() @@ -841,7 +840,7 @@ impl FromActivity for Post { }, ); - for author in authors.into_iter() { + for author in authors { PostAuthor::insert( conn, NewPostAuthor { @@ -858,9 +857,9 @@ impl FromActivity for Post { .map(|s| s.to_camel_case()) .collect::>(); if let Some(serde_json::Value::Array(tags)) = article.object_props.tag.clone() { - for tag in tags.into_iter() { + for tag in tags { serde_json::from_value::(tag.clone()) - .map(|m| Mention::from_activity(conn, m, post.id, true, true)) + .map(|m| Mention::from_activity(conn, &m, post.id, true, true)) .ok(); serde_json::from_value::(tag.clone()) @@ -868,7 +867,7 @@ impl FromActivity for Post { let tag_name = t .name_string() .expect("Post::from_activity: tag name error"); - Tag::from_activity(conn, t, post.id, hashtags.remove(&tag_name)); + Tag::from_activity(conn, &t, post.id, hashtags.remove(&tag_name)); }) .ok(); } @@ -910,7 +909,7 @@ impl Deletable for Post { act } - fn delete_id(id: String, actor_id: String, conn: &Connection) { + fn delete_id(id: &str, actor_id: &str, conn: &Connection) { let actor = User::find_by_ap_url(conn, actor_id); let post = Post::find_by_ap_url(conn, id); let can_delete = actor diff --git a/plume-models/src/reshares.rs b/plume-models/src/reshares.rs index d3006f24..1517112e 100644 --- a/plume-models/src/reshares.rs +++ b/plume-models/src/reshares.rs @@ -32,7 +32,7 @@ pub struct NewReshare { impl Reshare { insert!(reshares, NewReshare); get!(reshares); - find_by!(reshares, find_by_ap_url, ap_url as String); + find_by!(reshares, find_by_ap_url, ap_url as &str); find_by!( reshares, find_by_user_on_post, @@ -41,7 +41,7 @@ impl Reshare { ); pub fn update_ap_url(&self, conn: &Connection) { - if self.ap_url.len() == 0 { + if self.ap_url.is_empty() { diesel::update(self) .set(reshares::ap_url.eq(format!( "{}/reshare/{}", @@ -74,31 +74,31 @@ impl Reshare { User::get(conn, self.user_id) } - pub fn into_activity(&self, conn: &Connection) -> Announce { + pub fn to_activity(&self, conn: &Connection) -> Announce { let mut act = Announce::default(); act.announce_props .set_actor_link( User::get(conn, self.user_id) - .expect("Reshare::into_activity: user error") + .expect("Reshare::to_activity: user error") .into_id(), ) - .expect("Reshare::into_activity: actor error"); + .expect("Reshare::to_activity: actor error"); act.announce_props .set_object_link( Post::get(conn, self.post_id) - .expect("Reshare::into_activity: post error") + .expect("Reshare::to_activity: post error") .into_id(), ) - .expect("Reshare::into_activity: object error"); + .expect("Reshare::to_activity: object error"); act.object_props .set_id_string(self.ap_url.clone()) - .expect("Reshare::into_activity: id error"); + .expect("Reshare::to_activity: id error"); act.object_props .set_to_link(Id::new(PUBLIC_VISIBILTY.to_string())) - .expect("Reshare::into_activity: to error"); + .expect("Reshare::to_activity: to error"); act.object_props .set_cc_link_vec::(vec![]) - .expect("Reshare::into_activity: cc error"); + .expect("Reshare::to_activity: cc error"); act } @@ -112,7 +112,7 @@ impl FromActivity for Reshare { .announce_props .actor_link::() .expect("Reshare::from_activity: actor error") - .into(), + .as_ref(), ); let post = Post::find_by_ap_url( conn, @@ -120,7 +120,7 @@ impl FromActivity for Reshare { .announce_props .object_link::() .expect("Reshare::from_activity: object error") - .into(), + .as_ref(), ); let reshare = Reshare::insert( conn, @@ -130,7 +130,7 @@ impl FromActivity for Reshare { ap_url: announce .object_props .id_string() - .unwrap_or(String::from("")), + .unwrap_or_default(), }, ); reshare.notify(conn); @@ -176,7 +176,7 @@ impl Deletable for Reshare { ) .expect("Reshare::delete: actor error"); act.undo_props - .set_object_object(self.into_activity(conn)) + .set_object_object(self.to_activity(conn)) .expect("Reshare::delete: object error"); act.object_props .set_id_string(format!("{}#delete", self.ap_url)) @@ -191,7 +191,7 @@ impl Deletable for Reshare { act } - fn delete_id(id: String, actor_id: String, conn: &Connection) { + fn delete_id(id: &str, actor_id: &str, conn: &Connection) { if let Some(reshare) = Reshare::find_by_ap_url(conn, id) { if let Some(actor) = User::find_by_ap_url(conn, actor_id) { if actor.id == reshare.user_id { diff --git a/plume-models/src/tags.rs b/plume-models/src/tags.rs index 5494dd43..986d9e3f 100644 --- a/plume-models/src/tags.rs +++ b/plume-models/src/tags.rs @@ -24,24 +24,24 @@ pub struct NewTag { impl Tag { insert!(tags, NewTag); get!(tags); - find_by!(tags, find_by_name, tag as String); + find_by!(tags, find_by_name, tag as &str); list_by!(tags, for_post, post_id as i32); - pub fn into_activity(&self, conn: &Connection) -> Hashtag { + pub fn to_activity(&self, conn: &Connection) -> Hashtag { let mut ht = Hashtag::default(); - ht.set_href_string(ap_url(format!( + ht.set_href_string(ap_url(&format!( "{}/tag/{}", Instance::get_local(conn) - .expect("Tag::into_activity: local instance not found error") + .expect("Tag::to_activity: local instance not found error") .public_domain, self.tag - ))).expect("Tag::into_activity: href error"); + ))).expect("Tag::to_activity: href error"); ht.set_name_string(self.tag.clone()) - .expect("Tag::into_activity: name error"); + .expect("Tag::to_activity: name error"); ht } - pub fn from_activity(conn: &Connection, tag: Hashtag, post: i32, is_hashtag: bool) -> Tag { + pub fn from_activity(conn: &Connection, tag: &Hashtag, post: i32, is_hashtag: bool) -> Tag { Tag::insert( conn, NewTag { @@ -54,15 +54,15 @@ impl Tag { pub fn build_activity(conn: &Connection, tag: String) -> Hashtag { let mut ht = Hashtag::default(); - ht.set_href_string(ap_url(format!( + ht.set_href_string(ap_url(&format!( "{}/tag/{}", Instance::get_local(conn) - .expect("Tag::into_activity: local instance not found error") + .expect("Tag::to_activity: local instance not found error") .public_domain, tag - ))).expect("Tag::into_activity: href error"); + ))).expect("Tag::to_activity: href error"); ht.set_name_string(tag) - .expect("Tag::into_activity: name error"); + .expect("Tag::to_activity: name error"); ht } diff --git a/plume-models/src/users.rs b/plume-models/src/users.rs index fc46612f..67a5e119 100644 --- a/plume-models/src/users.rs +++ b/plume-models/src/users.rs @@ -43,8 +43,6 @@ use safe_string::SafeString; use schema::users; use {ap_url, Connection, BASE_URL, USE_HTTPS}; -pub const AUTH_COOKIE: &'static str = "user_id"; - pub type CustomPerson = CustomObject; #[derive(Queryable, Identifiable, Serialize, Deserialize, Clone, Debug)] @@ -89,14 +87,15 @@ pub struct NewUser { pub avatar_id: Option, } -const USER_PREFIX: &'static str = "@"; +pub const AUTH_COOKIE: &str = "user_id"; +const USER_PREFIX: &str = "@"; impl User { insert!(users, NewUser); get!(users); - find_by!(users, find_by_email, email as String); - find_by!(users, find_by_name, username as String, instance_id as i32); - find_by!(users, find_by_ap_url, ap_url as String); + find_by!(users, find_by_email, email as &str); + find_by!(users, find_by_name, username as &str, instance_id as i32); + find_by!(users, find_by_ap_url, ap_url as &str); pub fn one_by_instance(conn: &Connection) -> Vec { users::table @@ -125,8 +124,7 @@ impl User { .count() .load(conn) .expect("User::delete: count author error") - .iter() - .next() + .first() .unwrap_or(&0) > &0; if !has_other_authors { Post::get(conn, post_id) @@ -178,28 +176,25 @@ impl User { .len() // TODO count in database? } - pub fn find_local(conn: &Connection, username: String) -> Option { + pub fn find_local(conn: &Connection, username: &str) -> Option { User::find_by_name(conn, username, Instance::local_id(conn)) } - pub fn find_by_fqn(conn: &Connection, fqn: String) -> Option { - if fqn.contains("@") { + pub fn find_by_fqn(conn: &Connection, fqn: &str) -> Option { + if fqn.contains('@') { // remote user match Instance::find_by_domain( conn, - String::from( - fqn.split("@") - .last() - .expect("User::find_by_fqn: host error"), - ), + fqn.split('@') + .last() + .expect("User::find_by_fqn: host error"), ) { Some(instance) => match User::find_by_name( conn, - String::from( - fqn.split("@") - .nth(0) - .expect("User::find_by_fqn: name error"), - ), + fqn.split('@') + .nth(0) + .expect("User::find_by_fqn: name error") + , instance.id, ) { Some(u) => Some(u), @@ -213,8 +208,8 @@ impl User { } } - fn fetch_from_webfinger(conn: &Connection, acct: String) -> Option { - match resolve(acct.clone(), *USE_HTTPS) { + fn fetch_from_webfinger(conn: &Connection, acct: &str) -> Option { + match resolve(acct.to_owned(), *USE_HTTPS) { Ok(wf) => wf .links .into_iter() @@ -222,7 +217,7 @@ impl User { .and_then(|l| { User::fetch_from_url( conn, - l.href + &l.href .expect("User::fetch_from_webginfer: href not found error"), ) }), @@ -233,9 +228,9 @@ impl User { } } - fn fetch(url: String) -> Option { + fn fetch(url: &str) -> Option { let req = Client::new() - .get(&url[..]) + .get(url) .header( ACCEPT, HeaderValue::from_str( @@ -270,29 +265,28 @@ impl User { } } - pub fn fetch_from_url(conn: &Connection, url: String) -> Option { - User::fetch(url.clone()).map(|json| { + pub fn fetch_from_url(conn: &Connection, url: &str) -> Option { + User::fetch(url).map(|json| { (User::from_activity( conn, - json, - Url::parse(url.as_ref()) + &json, + Url::parse(url) .expect("User::fetch_from_url: url error") .host_str() - .expect("User::fetch_from_url: host error") - .to_string(), + .expect("User::fetch_from_url: host error"), )) }) } - fn from_activity(conn: &Connection, acct: CustomPerson, inst: String) -> User { - let instance = match Instance::find_by_domain(conn, inst.clone()) { + fn from_activity(conn: &Connection, acct: &CustomPerson, inst: &str) -> User { + let instance = match Instance::find_by_domain(conn, inst) { Some(instance) => instance, None => { Instance::insert( conn, NewInstance { - name: inst.clone(), - public_domain: inst.clone(), + name: inst.to_owned(), + public_domain: inst.to_owned(), local: false, // We don't really care about all the following for remote instances long_description: SafeString::new(""), @@ -335,7 +329,7 @@ impl User { .object .object_props .summary_string() - .unwrap_or(String::new()), + .unwrap_or_default(), ), email: None, hashed_password: None, @@ -385,7 +379,7 @@ impl User { } pub fn refetch(&self, conn: &Connection) { - User::fetch(self.ap_url.clone()).map(|json| { + User::fetch(&self.ap_url.clone()).map(|json| { let avatar = Media::save_remote( conn, json.object @@ -425,7 +419,7 @@ impl User { .object .object_props .summary_string() - .unwrap_or(String::new()), + .unwrap_or_default(), )), users::followers_endpoint.eq(json .object @@ -440,13 +434,13 @@ impl User { }); } - pub fn hash_pass(pass: String) -> String { - bcrypt::hash(pass.as_str(), 10).expect("User::hash_pass: hashing error") + pub fn hash_pass(pass: &str) -> String { + bcrypt::hash(pass, 10).expect("User::hash_pass: hashing error") } - pub fn auth(&self, pass: String) -> bool { + pub fn auth(&self, pass: &str) -> bool { if let Ok(valid) = bcrypt::verify( - pass.as_str(), + pass, self.hashed_password .clone() .expect("User::auth: no password error") @@ -460,38 +454,38 @@ impl User { pub fn update_boxes(&self, conn: &Connection) { let instance = self.get_instance(conn); - if self.outbox_url.len() == 0 { + if self.outbox_url.is_empty() { diesel::update(self) .set(users::outbox_url.eq(instance.compute_box( USER_PREFIX, - self.username.clone(), + &self.username, "outbox", ))) .execute(conn) .expect("User::update_boxes: outbox update error"); } - if self.inbox_url.len() == 0 { + if self.inbox_url.is_empty() { diesel::update(self) .set(users::inbox_url.eq(instance.compute_box( USER_PREFIX, - self.username.clone(), + &self.username, "inbox", ))) .execute(conn) .expect("User::update_boxes: inbox update error"); } - if self.ap_url.len() == 0 { + if self.ap_url.is_empty() { diesel::update(self) - .set(users::ap_url.eq(instance.compute_box(USER_PREFIX, self.username.clone(), ""))) + .set(users::ap_url.eq(instance.compute_box(USER_PREFIX, &self.username, ""))) .execute(conn) .expect("User::update_boxes: ap_url update error"); } if self.shared_inbox_url.is_none() { diesel::update(self) - .set(users::shared_inbox_url.eq(ap_url(format!( + .set(users::shared_inbox_url.eq(ap_url(&format!( "{}/inbox", Instance::get_local(conn) .expect("User::update_boxes: local instance not found error") @@ -501,11 +495,11 @@ impl User { .expect("User::update_boxes: shared inbox update error"); } - if self.followers_endpoint.len() == 0 { + if self.followers_endpoint.is_empty() { diesel::update(self) .set(users::followers_endpoint.eq(instance.compute_box( USER_PREFIX, - self.username.clone(), + &self.username, "followers", ))) .execute(conn) @@ -660,52 +654,52 @@ impl User { pub fn is_followed_by(&self, conn: &Connection, other_id: i32) -> bool { use schema::follows; - follows::table + !follows::table .filter(follows::follower_id.eq(other_id)) .filter(follows::following_id.eq(self.id)) .load::(conn) .expect("User::is_followed_by: loading error") - .len() > 0 // TODO count in database? + .is_empty() // TODO count in database? } pub fn is_following(&self, conn: &Connection, other_id: i32) -> bool { use schema::follows; - follows::table + !follows::table .filter(follows::follower_id.eq(self.id)) .filter(follows::following_id.eq(other_id)) .load::(conn) .expect("User::is_following: loading error") - .len() > 0 // TODO count in database? + .is_empty() // TODO count in database? } pub fn has_liked(&self, conn: &Connection, post: &Post) -> bool { use schema::likes; - likes::table + !likes::table .filter(likes::post_id.eq(post.id)) .filter(likes::user_id.eq(self.id)) .load::(conn) .expect("User::has_liked: loading error") - .len() > 0 // TODO count in database? + .is_empty() // TODO count in database? } pub fn has_reshared(&self, conn: &Connection, post: &Post) -> bool { use schema::reshares; - reshares::table + !reshares::table .filter(reshares::post_id.eq(post.id)) .filter(reshares::user_id.eq(self.id)) .load::(conn) .expect("User::has_reshared: loading error") - .len() > 0 // TODO count in database? + .is_empty() // TODO count in database? } - pub fn is_author_in(&self, conn: &Connection, blog: Blog) -> bool { + pub fn is_author_in(&self, conn: &Connection, blog: &Blog) -> bool { use schema::blog_authors; - blog_authors::table + !blog_authors::table .filter(blog_authors::author_id.eq(self.id)) .filter(blog_authors::blog_id.eq(blog.id)) .load::(conn) .expect("User::is_author_in: loading error") - .len() > 0 // TODO count in database? + .is_empty() // TODO count in database? } pub fn get_keypair(&self) -> PKey { @@ -719,64 +713,64 @@ impl User { ).expect("User::get_keypair: private key deserialization error") } - pub fn into_activity(&self, conn: &Connection) -> CustomPerson { + pub fn to_activity(&self, conn: &Connection) -> CustomPerson { let mut actor = Person::default(); actor .object_props .set_id_string(self.ap_url.clone()) - .expect("User::into_activity: id error"); + .expect("User::to_activity: id error"); actor .object_props .set_name_string(self.display_name.clone()) - .expect("User::into_activity: name error"); + .expect("User::to_activity: name error"); actor .object_props .set_summary_string(self.summary.get().clone()) - .expect("User::into_activity: summary error"); + .expect("User::to_activity: summary error"); actor .object_props .set_url_string(self.ap_url.clone()) - .expect("User::into_activity: url error"); + .expect("User::to_activity: url error"); actor .ap_actor_props .set_inbox_string(self.inbox_url.clone()) - .expect("User::into_activity: inbox error"); + .expect("User::to_activity: inbox error"); actor .ap_actor_props .set_outbox_string(self.outbox_url.clone()) - .expect("User::into_activity: outbox error"); + .expect("User::to_activity: outbox error"); actor .ap_actor_props .set_preferred_username_string(self.username.clone()) - .expect("User::into_activity: preferredUsername error"); + .expect("User::to_activity: preferredUsername error"); actor .ap_actor_props .set_followers_string(self.followers_endpoint.clone()) - .expect("User::into_activity: followers error"); + .expect("User::to_activity: followers error"); let mut endpoints = Endpoint::default(); endpoints - .set_shared_inbox_string(ap_url(format!("{}/inbox/", BASE_URL.as_str()))) - .expect("User::into_activity: endpoints.sharedInbox error"); + .set_shared_inbox_string(ap_url(&format!("{}/inbox/", BASE_URL.as_str()))) + .expect("User::to_activity: endpoints.sharedInbox error"); actor .ap_actor_props .set_endpoints_endpoint(endpoints) - .expect("User::into_activity: endpoints error"); + .expect("User::to_activity: endpoints error"); let mut public_key = PublicKey::default(); public_key .set_id_string(format!("{}#main-key", self.ap_url)) - .expect("User::into_activity: publicKey.id error"); + .expect("User::to_activity: publicKey.id error"); public_key .set_owner_string(self.ap_url.clone()) - .expect("User::into_activity: publicKey.owner error"); + .expect("User::to_activity: publicKey.owner error"); public_key .set_public_key_pem_string(self.public_key.clone()) - .expect("User::into_activity: publicKey.publicKeyPem error"); + .expect("User::to_activity: publicKey.publicKeyPem error"); let mut ap_signature = ApSignature::default(); ap_signature .set_public_key_publickey(public_key) - .expect("User::into_activity: publicKey error"); + .expect("User::to_activity: publicKey error"); let mut avatar = Image::default(); avatar @@ -784,13 +778,13 @@ impl User { .set_url_string( self.avatar_id .and_then(|id| Media::get(conn, id).map(|m| m.url(conn))) - .unwrap_or(String::new()), + .unwrap_or_default(), ) - .expect("User::into_activity: icon.url error"); + .expect("User::to_activity: icon.url error"); actor .object_props .set_icon_object(avatar) - .expect("User::into_activity: icon error"); + .expect("User::to_activity: icon error"); CustomPerson::new(actor, ap_signature) } @@ -798,7 +792,7 @@ impl User { pub fn to_json(&self, conn: &Connection) -> serde_json::Value { let mut json = serde_json::to_value(self).expect("User::to_json: serializing error"); json["fqn"] = serde_json::Value::String(self.get_fqn(conn)); - json["name"] = if self.display_name.len() > 0 { + json["name"] = if !self.display_name.is_empty() { json!(self.display_name) } else { json!(self.get_fqn(conn)) @@ -806,7 +800,7 @@ impl User { json["avatar"] = json!( self.avatar_id .and_then(|id| Media::get(conn, id).map(|m| m.url(conn))) - .unwrap_or("/static/default-avatar.png".to_string()) + .unwrap_or_else(|| String::from("/static/default-avatar.png")) ); json } @@ -831,7 +825,7 @@ impl User { mime_type: Some(String::from("application/atom+xml")), href: Some(self.get_instance(conn).compute_box( USER_PREFIX, - self.username.clone(), + &self.username, "feed.atom", )), template: None, @@ -846,11 +840,11 @@ impl User { } } - pub fn from_url(conn: &Connection, url: String) -> Option { - User::find_by_ap_url(conn, url.clone()).or_else(|| { + pub fn from_url(conn: &Connection, url: &str) -> Option { + User::find_by_ap_url(conn, url).or_else(|| { // The requested user was not in the DB // We try to fetch it if it is remote - if Url::parse(url.as_ref()) + if Url::parse(&url) .expect("User::from_url: url error") .host_str() .expect("User::from_url: host error") != BASE_URL.as_str() @@ -916,7 +910,7 @@ impl Signer for User { format!("{}#main-key", self.ap_url) } - fn sign(&self, to_sign: String) -> Vec { + fn sign(&self, to_sign: &str) -> Vec { let key = self.get_keypair(); let mut signer = sign::Signer::new(MessageDigest::sha256(), &key) .expect("User::sign: initialization error"); @@ -928,7 +922,7 @@ impl Signer for User { .expect("User::sign: finalization error") } - fn verify(&self, data: String, signature: Vec) -> bool { + fn verify(&self, data: &str, signature: &[u8]) -> bool { let key = PKey::from_rsa( Rsa::public_key_from_pem(self.public_key.as_ref()) .expect("User::verify: pem parsing error"), @@ -951,7 +945,7 @@ impl NewUser { username: String, display_name: String, is_admin: bool, - summary: String, + summary: &str, email: String, password: String, ) -> User { @@ -959,12 +953,12 @@ impl NewUser { User::insert( conn, NewUser { - username: username, - display_name: display_name, + username, + display_name, outbox_url: String::from(""), inbox_url: String::from(""), - is_admin: is_admin, - summary: SafeString::new(&summary), + is_admin, + summary: SafeString::new(summary), email: Some(email), hashed_password: Some(password), instance_id: Instance::local_id(conn), @@ -998,7 +992,7 @@ pub(crate) mod tests { "admin".to_owned(), "The admin".to_owned(), true, - "Hello there, I'm the admin".to_owned(), + "Hello there, I'm the admin", "admin@example.com".to_owned(), "invalid_admin_password".to_owned(), ), @@ -1007,7 +1001,7 @@ pub(crate) mod tests { "user".to_owned(), "Some user".to_owned(), false, - "Hello there, I'm no one".to_owned(), + "Hello there, I'm no one", "user@example.com".to_owned(), "invalid_user_password".to_owned(), ), @@ -1016,7 +1010,7 @@ pub(crate) mod tests { "other".to_owned(), "Another user".to_owned(), false, - "Hello there, I'm someone else".to_owned(), + "Hello there, I'm someone else", "other@example.com".to_owned(), "invalid_other_password".to_owned(), ), @@ -1037,25 +1031,25 @@ pub(crate) mod tests { "test".to_owned(), "test user".to_owned(), false, - "Hello I'm a test".to_owned(), + "Hello I'm a test", "test@example.com".to_owned(), - User::hash_pass("test_password".to_owned()), + User::hash_pass("test_password"), ); test_user.update_boxes(conn); assert_eq!( test_user.id, - User::find_by_name(conn, "test".to_owned(), Instance::local_id(conn)) + User::find_by_name(conn, "test", Instance::local_id(conn)) .unwrap() .id ); assert_eq!( test_user.id, - User::find_by_fqn(conn, test_user.get_fqn(conn)).unwrap().id + User::find_by_fqn(conn, &test_user.get_fqn(conn)).unwrap().id ); assert_eq!( test_user.id, - User::find_by_email(conn, "test@example.com".to_owned()) + User::find_by_email(conn, "test@example.com") .unwrap() .id ); @@ -1063,7 +1057,7 @@ pub(crate) mod tests { test_user.id, User::find_by_ap_url( conn, - format!( + &format!( "https://{}/@/{}/", Instance::get_local(conn).unwrap().public_domain, "test" @@ -1138,14 +1132,14 @@ pub(crate) mod tests { "test".to_owned(), "test user".to_owned(), false, - "Hello I'm a test".to_owned(), + "Hello I'm a test", "test@example.com".to_owned(), - User::hash_pass("test_password".to_owned()), + User::hash_pass("test_password"), ); test_user.update_boxes(conn); - assert!(test_user.auth("test_password".to_owned())); - assert!(!test_user.auth("other_password".to_owned())); + assert!(test_user.auth("test_password")); + assert!(!test_user.auth("other_password")); Ok(()) }); diff --git a/src/api/mod.rs b/src/api/mod.rs index c0f4d092..530deb54 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -20,10 +20,10 @@ struct OAuthRequest { #[get("/oauth2?")] fn oauth(query: OAuthRequest, conn: DbConn) -> Json { - let app = App::find_by_client_id(&*conn, query.client_id).expect("OAuth request from unknown client"); + let app = App::find_by_client_id(&*conn, &query.client_id).expect("OAuth request from unknown client"); if app.client_secret == query.client_secret { - if let Some(user) = User::find_local(&*conn, query.username) { - if user.auth(query.password) { + if let Some(user) = User::find_local(&*conn, &query.username) { + if user.auth(&query.password) { let token = ApiToken::insert(&*conn, NewApiToken { app_id: app.id, user_id: user.id, @@ -42,7 +42,7 @@ fn oauth(query: OAuthRequest, conn: DbConn) -> Json { // Making fake password verification to avoid different // response times that would make it possible to know // if a username is registered or not. - User::get(&*conn, 1).unwrap().auth(query.password); + User::get(&*conn, 1).unwrap().auth(&query.password); Json(json!({ "error": "Invalid credentials" })) diff --git a/src/inbox.rs b/src/inbox.rs index d120b64d..3773b513 100644 --- a/src/inbox.rs +++ b/src/inbox.rs @@ -48,11 +48,11 @@ pub trait Inbox { "Delete" => { let act: Delete = serde_json::from_value(act.clone())?; Post::delete_id( - act.delete_props + &act.delete_props .object_object::()? .object_props .id_string()?, - actor_id.into(), + actor_id.as_ref(), conn, ); Ok(()) @@ -77,33 +77,33 @@ pub trait Inbox { { "Like" => { likes::Like::delete_id( - act.undo_props + &act.undo_props .object_object::()? .object_props .id_string()?, - actor_id.into(), + actor_id.as_ref(), conn, ); Ok(()) } "Announce" => { Reshare::delete_id( - act.undo_props + &act.undo_props .object_object::()? .object_props .id_string()?, - actor_id.into(), + actor_id.as_ref(), conn, ); Ok(()) } "Follow" => { Follow::delete_id( - act.undo_props + &act.undo_props .object_object::()? .object_props .id_string()?, - actor_id.into(), + actor_id.as_ref(), conn, ); Ok(()) @@ -113,7 +113,7 @@ pub trait Inbox { } "Update" => { let act: Update = serde_json::from_value(act.clone())?; - Post::handle_update(conn, act.update_props.object_object()?); + Post::handle_update(conn, &act.update_props.object_object()?); Ok(()) } _ => Err(InboxError::InvalidType)?, diff --git a/src/routes/blogs.rs b/src/routes/blogs.rs index a5212d45..96175d03 100644 --- a/src/routes/blogs.rs +++ b/src/routes/blogs.rs @@ -24,7 +24,7 @@ use routes::Page; #[get("/~/?", rank = 2)] fn paginated_details(name: String, conn: DbConn, user: Option, page: Page) -> Template { - may_fail!(user.map(|u| u.to_json(&*conn)), Blog::find_by_fqn(&*conn, name), "Requested blog couldn't be found", |blog| { + may_fail!(user.map(|u| u.to_json(&*conn)), Blog::find_by_fqn(&*conn, &name), "Requested blog couldn't be found", |blog| { let posts = Post::blog_page(&*conn, &blog, page.limits()); let articles = Post::get_for_blog(&*conn, &blog); let authors = &blog.list_authors(&*conn); @@ -32,7 +32,7 @@ fn paginated_details(name: String, conn: DbConn, user: Option, page: Page) Template::render("blogs/details", json!({ "blog": &blog.to_json(&*conn), "account": user.clone().map(|u| u.to_json(&*conn)), - "is_author": user.map(|x| x.is_author_in(&*conn, blog.clone())), + "is_author": user.map(|x| x.is_author_in(&*conn, &blog)), "posts": posts.into_iter().map(|p| p.to_json(&*conn)).collect::>(), "authors": authors.into_iter().map(|u| u.to_json(&*conn)).collect::>(), "n_authors": authors.len(), @@ -50,8 +50,8 @@ fn details(name: String, conn: DbConn, user: Option) -> Template { #[get("/~/", rank = 1)] fn activity_details(name: String, conn: DbConn, _ap: ApRequest) -> Option> { - let blog = Blog::find_local(&*conn, name)?; - Some(ActivityStream::new(blog.into_activity(&*conn))) + let blog = Blog::find_local(&*conn, &name)?; + Some(ActivityStream::new(blog.to_activity(&*conn))) } #[get("/blogs/new")] @@ -67,7 +67,7 @@ fn new(user: User, conn: DbConn) -> Template { fn new_auth() -> Flash{ utils::requires_login( "You need to be logged in order to create a new blog", - uri!(new).into() + uri!(new) ) } @@ -78,8 +78,8 @@ struct NewBlogForm { } fn valid_slug(title: &str) -> Result<(), ValidationError> { - let slug = utils::make_actor_id(title.to_string()); - if slug.len() == 0 { + let slug = utils::make_actor_id(title); + if slug.is_empty() { Err(ValidationError::new("empty_slug")) } else { Ok(()) @@ -89,13 +89,13 @@ fn valid_slug(title: &str) -> Result<(), ValidationError> { #[post("/blogs/new", data = "")] fn create(conn: DbConn, data: LenientForm, user: User) -> Result { let form = data.get(); - let slug = utils::make_actor_id(form.title.to_string()); + let slug = utils::make_actor_id(&form.title); let mut errors = match form.validate() { Ok(_) => ValidationErrors::new(), Err(e) => e }; - if let Some(_) = Blog::find_local(&*conn, slug.clone()) { + if Blog::find_local(&*conn, &slug).is_some() { errors.add("title", ValidationError { code: Cow::from("existing_slug"), message: Some(Cow::from("A blog with the same name already exists.")), @@ -131,8 +131,8 @@ fn create(conn: DbConn, data: LenientForm, user: User) -> Result/delete")] fn delete(conn: DbConn, name: String, user: Option) -> Result>{ - let blog = Blog::find_local(&*conn, name).ok_or(None)?; - if user.map(|u| u.is_author_in(&*conn, blog.clone())).unwrap_or(false) { + let blog = Blog::find_local(&*conn, &name).ok_or(None)?; + if user.map(|u| u.is_author_in(&*conn, &blog)).unwrap_or(false) { blog.delete(&conn); Ok(Redirect::to(uri!(super::instance::index))) } else { @@ -144,17 +144,17 @@ fn delete(conn: DbConn, name: String, user: Option) -> Result/outbox")] fn outbox(name: String, conn: DbConn) -> Option> { - let blog = Blog::find_local(&*conn, name)?; + let blog = Blog::find_local(&*conn, &name)?; Some(blog.outbox(&*conn)) } #[get("/~//atom.xml")] fn atom_feed(name: String, conn: DbConn) -> Option> { - let blog = Blog::find_by_fqn(&*conn, name.clone())?; + let blog = Blog::find_by_fqn(&*conn, &name)?; let feed = FeedBuilder::default() .title(blog.title.clone()) .id(Instance::get_local(&*conn).expect("blogs::atom_feed: local instance not found error") - .compute_box("~", name, "atom.xml")) + .compute_box("~", &name, "atom.xml")) .entries(Post::get_recents_for_blog(&*conn, &blog, 15) .into_iter() .map(|p| super::post_to_atom(p, &*conn)) diff --git a/src/routes/comments.rs b/src/routes/comments.rs index 73c40859..d7fd08ed 100644 --- a/src/routes/comments.rs +++ b/src/routes/comments.rs @@ -31,26 +31,26 @@ struct NewCommentForm { #[post("/~///comment", data = "")] fn create(blog_name: String, slug: String, data: LenientForm, user: User, conn: DbConn, worker: State>>) -> Result> { - let blog = Blog::find_by_fqn(&*conn, blog_name.clone()).ok_or(None)?; - let post = Post::find_by_slug(&*conn, slug.clone(), blog.id).ok_or(None)?; + let blog = Blog::find_by_fqn(&*conn, &blog_name).ok_or(None)?; + let post = Post::find_by_slug(&*conn, &slug, blog.id).ok_or(None)?; let form = data.get(); form.validate() .map(|_| { let (html, mentions, _hashtags) = utils::md_to_html(form.content.as_ref()); let comm = Comment::insert(&*conn, NewComment { content: SafeString::new(html.as_ref()), - in_response_to_id: form.responding_to.clone(), + in_response_to_id: form.responding_to, post_id: post.id, author_id: user.id, ap_url: None, - sensitive: form.warning.len() > 0, + sensitive: !form.warning.is_empty(), spoiler_text: form.warning.clone() }).update_ap_url(&*conn); let new_comment = comm.create_activity(&*conn); // save mentions for ment in mentions { - Mention::from_activity(&*conn, Mention::build_activity(&*conn, ment), post.id, true, true); + Mention::from_activity(&*conn, &Mention::build_activity(&*conn, &ment), post.id, true, true); } // federate @@ -76,7 +76,7 @@ fn create(blog_name: String, slug: String, data: LenientForm, us "has_reshared": user.has_reshared(&*conn, &post), "account": user.to_json(&*conn), "date": &post.creation_date.timestamp(), - "previous": form.responding_to.and_then(|r| Comment::get(&*conn, r)).map(|r| r.to_json(&*conn, &vec![])), + "previous": form.responding_to.and_then(|r| Comment::get(&*conn, r)).map(|r| r.to_json(&*conn, &[])), "user_fqn": user.get_fqn(&*conn), "comment_form": form, "comment_errors": errors, @@ -86,5 +86,5 @@ fn create(blog_name: String, slug: String, data: LenientForm, us #[get("/~/<_blog>/<_slug>/comment/")] fn activity_pub(_blog: String, _slug: String, id: i32, _ap: ApRequest, conn: DbConn) -> Option> { - Comment::get(&*conn, id).map(|c| ActivityStream::new(c.into_activity(&*conn))) + Comment::get(&*conn, id).map(|c| ActivityStream::new(c.to_activity(&*conn))) } diff --git a/src/routes/instance.rs b/src/routes/instance.rs index 2a07e464..c3dec53f 100644 --- a/src/routes/instance.rs +++ b/src/routes/instance.rs @@ -191,7 +191,9 @@ fn admin_users_paginated(admin: Admin, conn: DbConn, page: Page) -> Template { #[post("/admin/users//ban")] fn ban(_admin: Admin, conn: DbConn, id: i32) -> Redirect { - User::get(&*conn, id).map(|u| u.delete(&*conn)); + if let Some(u) = User::get(&*conn, id) { + u.delete(&*conn); + } Redirect::to(uri!(admin_users)) } @@ -203,14 +205,14 @@ fn shared_inbox(conn: DbConn, data: String, headers: Headers) -> Result//like")] fn create(blog: String, slug: String, user: User, conn: DbConn, worker: State>>) -> Option { - let b = Blog::find_by_fqn(&*conn, blog.clone())?; - let post = Post::find_by_slug(&*conn, slug.clone(), b.id)?; + let b = Blog::find_by_fqn(&*conn, &blog)?; + let post = Post::find_by_slug(&*conn, &slug, b.id)?; if !user.has_liked(&*conn, &post) { let like = likes::Like::insert(&*conn, likes::NewLike { @@ -26,7 +26,7 @@ fn create(blog: String, slug: String, user: User, conn: DbConn, worker: State Flash{ utils::requires_login( "You need to be logged in order to like a post", - uri!(create: blog = blog, slug = slug).into() + uri!(create: blog = blog, slug = slug) ) } diff --git a/src/routes/medias.rs b/src/routes/medias.rs index c2092e05..761c8d9a 100644 --- a/src/routes/medias.rs +++ b/src/routes/medias.rs @@ -37,7 +37,7 @@ fn upload(user: User, data: Data, ct: &ContentType, conn: DbConn) -> Result Result 0; + let has_cw = !read(&fields[&"cw".to_string()][0].data).is_empty(); let media = Media::insert(&*conn, NewMedia { file_path: dest, alt_text: read(&fields[&"alt".to_string()][0].data), diff --git a/src/routes/notifications.rs b/src/routes/notifications.rs index 6b71c775..ffdd7149 100644 --- a/src/routes/notifications.rs +++ b/src/routes/notifications.rs @@ -24,6 +24,6 @@ fn notifications(conn: DbConn, user: User) -> Template { fn notifications_auth() -> Flash{ utils::requires_login( "You need to be logged in order to see your notifications", - uri!(notifications).into() + uri!(notifications) ) } diff --git a/src/routes/posts.rs b/src/routes/posts.rs index ad8c4dea..07729a22 100644 --- a/src/routes/posts.rs +++ b/src/routes/posts.rs @@ -38,14 +38,14 @@ fn details(blog: String, slug: String, conn: DbConn, user: Option) -> Temp #[get("/~//?")] fn details_response(blog: String, slug: String, conn: DbConn, user: Option, query: Option) -> Template { - may_fail!(user.map(|u| u.to_json(&*conn)), Blog::find_by_fqn(&*conn, blog), "Couldn't find this blog", |blog| { - may_fail!(user.map(|u| u.to_json(&*conn)), Post::find_by_slug(&*conn, slug, blog.id), "Couldn't find this post", |post| { + may_fail!(user.map(|u| u.to_json(&*conn)), Blog::find_by_fqn(&*conn, &blog), "Couldn't find this blog", |blog| { + may_fail!(user.map(|u| u.to_json(&*conn)), Post::find_by_slug(&*conn, &slug, blog.id), "Couldn't find this post", |post| { if post.published || post.get_authors(&*conn).into_iter().any(|a| a.id == user.clone().map(|u| u.id).unwrap_or(0)) { let comments = Comment::list_by_post(&*conn, post.id); let comms = comments.clone(); let previous = query.and_then(|q| q.responding_to.map(|r| Comment::get(&*conn, r) - .expect("posts::details_reponse: Error retrieving previous comment").to_json(&*conn, &vec![]))); + .expect("posts::details_reponse: Error retrieving previous comment").to_json(&*conn, &[]))); Template::render("posts/details", json!({ "author": post.get_authors(&*conn)[0].to_json(&*conn), "article": post.to_json(&*conn), @@ -65,7 +65,7 @@ fn details_response(blog: String, slug: String, conn: DbConn, user: Option "default": { "warning": previous.map(|p| p["spoiler_text"].clone()) }, - "user_fqn": user.clone().map(|u| u.get_fqn(&*conn)).unwrap_or(String::new()), + "user_fqn": user.clone().map(|u| u.get_fqn(&*conn)).unwrap_or_default(), "is_author": user.clone().map(|u| post.get_authors(&*conn).into_iter().any(|a| u.id == a.id)).unwrap_or(false), "is_following": user.map(|u| u.is_following(&*conn, post.get_authors(&*conn)[0].id)).unwrap_or(false), "comment_form": null, @@ -82,10 +82,10 @@ fn details_response(blog: String, slug: String, conn: DbConn, user: Option #[get("/~//", rank = 3)] fn activity_details(blog: String, slug: String, conn: DbConn, _ap: ApRequest) -> Result, Option> { - let blog = Blog::find_by_fqn(&*conn, blog).ok_or(None)?; - let post = Post::find_by_slug(&*conn, slug, blog.id).ok_or(None)?; + let blog = Blog::find_by_fqn(&*conn, &blog).ok_or(None)?; + let post = Post::find_by_slug(&*conn, &slug, blog.id).ok_or(None)?; if post.published { - Ok(ActivityStream::new(post.into_activity(&*conn))) + Ok(ActivityStream::new(post.to_activity(&*conn))) } else { Err(Some(String::from("Not published yet."))) } @@ -95,15 +95,15 @@ fn activity_details(blog: String, slug: String, conn: DbConn, _ap: ApRequest) -> fn new_auth(blog: String) -> Flash { utils::requires_login( "You need to be logged in order to write a new post", - uri!(new: blog = blog).into() + uri!(new: blog = blog) ) } #[get("/~//new", rank = 1)] fn new(blog: String, user: User, conn: DbConn) -> Option