]> Untitled Git - lemmy.git/commitdiff
Split lemmy_utils into multiple files (#96)
authornutomic <nutomic@noreply.yerbamate.dev>
Mon, 14 Sep 2020 15:29:50 +0000 (15:29 +0000)
committerdessalines <dessalines@noreply.yerbamate.dev>
Mon, 14 Sep 2020 15:29:50 +0000 (15:29 +0000)
Update dependencies

Move send_local_notifs into lemmy_api_structs (ref #1115)

Split lemmy_utils into multiple files

Co-authored-by: Felix Ableitner <me@nutomic.com>
Reviewed-on: https://yerbamate.dev/LemmyNet/lemmy/pulls/96

57 files changed:
server/Cargo.lock
server/Cargo.toml
server/lemmy_api_structs/Cargo.toml
server/lemmy_api_structs/src/lib.rs
server/lemmy_db/Cargo.toml
server/lemmy_db/src/activity.rs
server/lemmy_db/src/category.rs
server/lemmy_db/src/comment_view.rs
server/lemmy_db/src/community_view.rs
server/lemmy_db/src/lib.rs
server/lemmy_db/src/moderator_views.rs
server/lemmy_db/src/post_view.rs
server/lemmy_db/src/private_message_view.rs
server/lemmy_db/src/schema.rs
server/lemmy_db/src/site_view.rs
server/lemmy_db/src/user.rs
server/lemmy_db/src/user_mention_view.rs
server/lemmy_db/src/user_view.rs
server/lemmy_rate_limit/Cargo.toml
server/lemmy_rate_limit/src/lib.rs
server/lemmy_utils/Cargo.toml
server/lemmy_utils/src/apub.rs [new file with mode: 0644]
server/lemmy_utils/src/email.rs [new file with mode: 0644]
server/lemmy_utils/src/lib.rs
server/lemmy_utils/src/test.rs [new file with mode: 0644]
server/lemmy_utils/src/utils.rs [new file with mode: 0644]
server/src/api/comment.rs
server/src/api/community.rs
server/src/api/mod.rs
server/src/api/post.rs
server/src/api/site.rs
server/src/api/user.rs
server/src/apub/activities.rs
server/src/apub/comment.rs
server/src/apub/community.rs
server/src/apub/fetcher.rs
server/src/apub/inbox/activities/create.rs
server/src/apub/inbox/activities/delete.rs
server/src/apub/inbox/activities/dislike.rs
server/src/apub/inbox/activities/like.rs
server/src/apub/inbox/activities/remove.rs
server/src/apub/inbox/activities/undo.rs
server/src/apub/inbox/activities/update.rs
server/src/apub/inbox/community_inbox.rs
server/src/apub/inbox/user_inbox.rs
server/src/apub/mod.rs
server/src/apub/post.rs
server/src/apub/private_message.rs
server/src/apub/user.rs
server/src/code_migrations.rs
server/src/lib.rs
server/src/main.rs
server/src/routes/feeds.rs
server/src/routes/nodeinfo.rs
server/src/routes/webfinger.rs
server/src/routes/websocket.rs
server/test.sh

index 0c50f464d507a8f540801a250f318959cbfe0409..388f8d0b41f3df3a85ca379d26d9a0cde5ddbf41 100644 (file)
@@ -139,12 +139,14 @@ dependencies = [
  "actix-utils 2.0.0",
  "base64 0.12.3",
  "bitflags 1.2.1",
+ "brotli2",
  "bytes",
  "cookie",
  "copyless",
  "derive_more",
  "either",
  "encoding_rs",
+ "flate2",
  "futures-channel",
  "futures-core",
  "futures-util",
@@ -698,6 +700,26 @@ dependencies = [
  "opaque-debug 0.3.0",
 ]
 
+[[package]]
+name = "brotli-sys"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4445dea95f4c2b41cde57cc9fee236ae4dbae88d8fcbdb4750fc1bb5d86aaecd"
+dependencies = [
+ "cc",
+ "libc",
+]
+
+[[package]]
+name = "brotli2"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0cb036c3eade309815c15ddbacec5b22c4d1f3983a774ab2eac2e3e9ea85568e"
+dependencies = [
+ "brotli-sys",
+ "libc",
+]
+
 [[package]]
 name = "buf-min"
 version = "0.1.1"
@@ -837,9 +859,9 @@ checksum = "0dbbb57365263e881e805dc77d94697c9118fd94d8da011240555aa7b23445bd"
 
 [[package]]
 name = "comrak"
-version = "0.7.0"
+version = "0.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e17058cc536cf290563e88787d7b9e6030ce4742943017cc2ffb71f88034021c"
+checksum = "0d325e4f2ffff52ca77d995bb675494d5364aa332499d5f7c7fbb28c25e671f6"
 dependencies = [
  "clap",
  "entities",
@@ -847,9 +869,11 @@ dependencies = [
  "pest",
  "pest_derive",
  "regex",
+ "shell-words",
  "twoway",
  "typed-arena",
  "unicode_categories",
+ "xdg",
 ]
 
 [[package]]
@@ -909,6 +933,15 @@ version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634"
 
+[[package]]
+name = "crc32fast"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
+dependencies = [
+ "cfg-if",
+]
+
 [[package]]
 name = "crossbeam-channel"
 version = "0.4.4"
@@ -1258,6 +1291,18 @@ dependencies = [
  "ascii_utils",
 ]
 
+[[package]]
+name = "flate2"
+version = "1.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "766d0e77a2c1502169d4a93ff3b8c15a71fd946cd0126309752104e5f3c46d94"
+dependencies = [
+ "cfg-if",
+ "crc32fast",
+ "libc",
+ "miniz_oxide",
+]
+
 [[package]]
 name = "fnv"
 version = "1.0.7"
@@ -1773,7 +1818,11 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 name = "lemmy_api_structs"
 version = "0.1.0"
 dependencies = [
+ "actix-web",
+ "diesel",
  "lemmy_db",
+ "lemmy_utils",
+ "log",
  "serde 1.0.115",
 ]
 
@@ -3057,6 +3106,12 @@ dependencies = [
  "opaque-debug 0.3.0",
 ]
 
+[[package]]
+name = "shell-words"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6fa3938c99da4914afedd13bf3d79bcb6c277d1b2c398d23257a304d9e1b074"
+
 [[package]]
 name = "signal-hook-registry"
 version = "1.2.1"
@@ -3186,15 +3241,15 @@ checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c"
 
 [[package]]
 name = "strum"
-version = "0.18.0"
+version = "0.19.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b"
+checksum = "3924a58d165da3b7b2922c667ab0673c7b5fd52b5c19ea3442747bcb3cd15abe"
 
 [[package]]
 name = "strum_macros"
-version = "0.18.0"
+version = "0.19.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c"
+checksum = "2d2ab682ecdcae7f5f45ae85cd7c1e6c8e68ea42c8a612d47fedf831c037146a"
 dependencies = [
  "heck",
  "proc-macro2",
@@ -3864,3 +3919,9 @@ dependencies = [
  "winapi 0.2.8",
  "winapi-build",
 ]
+
+[[package]]
+name = "xdg"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d089681aa106a86fade1b0128fb5daf07d5867a509ab036d99988dec80429a57"
index ec8a29d006f87fd3f2ac0fe0e97d7e2815ca31f7..721ce51e7ab952a5a34b07ff5dbf3aa29d3c984c 100644 (file)
@@ -22,7 +22,7 @@ lemmy_rate_limit = { path = "./lemmy_rate_limit" }
 diesel = "1.4.4"
 diesel_migrations = "1.4.0"
 dotenv = "0.15.0"
-activitystreams = "0.7.0-alpha.3"
+activitystreams = "0.7.0-alpha.4"
 activitystreams-ext = "0.1.0-alpha.2"
 bcrypt = "0.8.0"
 chrono = { version = "0.4.7", features = ["serde"] }
@@ -37,8 +37,8 @@ awc = { version = "2.0.0", default-features = false }
 log = "0.4.0"
 env_logger = "0.7.1"
 rand = "0.7.3"
-strum = "0.18.0"
-strum_macros = "0.18.0"
+strum = "0.19.2"
+strum_macros = "0.19.2"
 jsonwebtoken = "7.0.1"
 lazy_static = "1.3.0"
 rss = "1.9.0"
@@ -53,7 +53,7 @@ futures = "0.3.5"
 itertools = "0.9.0"
 uuid = { version = "0.8", features = ["serde", "v4"] }
 sha2 = "0.9"
-async-trait = "0.1.36"
+async-trait = "0.1.40"
 captcha = "0.0.7"
 anyhow = "1.0.32"
 thiserror = "1.0.20"
index 3778422bec742403f5abbbd46a0c0f4d92f78087..b442f697d5b6bfc175d7d5cc3315cd71bcde931a 100644 (file)
@@ -10,4 +10,8 @@ path = "src/lib.rs"
 
 [dependencies]
 lemmy_db = { path = "../lemmy_db" }
+lemmy_utils = { path = "../lemmy_utils" }
 serde = { version = "1.0.105", features = ["derive"] }
+log = "0.4.0"
+diesel = "1.4.4"
+actix-web = { version = "3.0.0-beta.3", features = ["rustls"] }
index b3576a0d629421cb4deb1097babe73b11eb054bf..e94a286f770bbfbcb6133a99f8db5b0e0355407c 100644 (file)
@@ -1,7 +1,159 @@
 extern crate serde;
+extern crate log;
+extern crate diesel;
+extern crate actix_web;
 
 pub mod comment;
 pub mod community;
 pub mod post;
 pub mod site;
 pub mod user;
+
+use lemmy_db::comment::Comment;
+use lemmy_db::user::User_;
+use lemmy_db::post::Post;
+use lemmy_db::user_mention::{UserMentionForm, UserMention};
+use log::error;
+use lemmy_db::{Crud, DbPool};
+use lemmy_utils::utils::MentionData;
+use lemmy_utils::settings::Settings;
+use lemmy_utils::email::send_email;
+use diesel::PgConnection;
+use lemmy_utils::LemmyError;
+
+pub async fn blocking<F, T>(pool: &DbPool, f: F) -> Result<T, LemmyError>
+  where
+    F: FnOnce(&diesel::PgConnection) -> T + Send + 'static,
+    T: Send + 'static,
+{
+  let pool = pool.clone();
+  let res = actix_web::web::block(move || {
+    let conn = pool.get()?;
+    let res = (f)(&conn);
+    Ok(res) as Result<_, LemmyError>
+  })
+    .await?;
+
+  Ok(res)
+}
+
+pub async fn send_local_notifs(
+  mentions: Vec<MentionData>,
+  comment: Comment,
+  user: &User_,
+  post: Post,
+  pool: &DbPool,
+  do_send_email: bool,
+) -> Result<Vec<i32>, LemmyError> {
+  let user2 = user.clone();
+  let ids = blocking(pool, move |conn| {
+    do_send_local_notifs(conn, &mentions, &comment, &user2, &post, do_send_email)
+  })
+    .await?;
+
+  Ok(ids)
+}
+
+fn do_send_local_notifs(
+  conn: &PgConnection,
+  mentions: &[MentionData],
+  comment: &Comment,
+  user: &User_,
+  post: &Post,
+  do_send_email: bool,
+) -> Vec<i32> {
+  let mut recipient_ids = Vec::new();
+  let hostname = &format!("https://{}", Settings::get().hostname);
+
+  // Send the local mentions
+  for mention in mentions
+    .iter()
+    .filter(|m| m.is_local() && m.name.ne(&user.name))
+    .collect::<Vec<&MentionData>>()
+  {
+    if let Ok(mention_user) = User_::read_from_name(&conn, &mention.name) {
+      // TODO
+      // At some point, make it so you can't tag the parent creator either
+      // This can cause two notifications, one for reply and the other for mention
+      recipient_ids.push(mention_user.id);
+
+      let user_mention_form = UserMentionForm {
+        recipient_id: mention_user.id,
+        comment_id: comment.id,
+        read: None,
+      };
+
+      // Allow this to fail softly, since comment edits might re-update or replace it
+      // Let the uniqueness handle this fail
+      match UserMention::create(&conn, &user_mention_form) {
+        Ok(_mention) => (),
+        Err(_e) => error!("{}", &_e),
+      };
+
+      // Send an email to those users that have notifications on
+      if do_send_email && mention_user.send_notifications_to_email {
+        if let Some(mention_email) = mention_user.email {
+          let subject = &format!("{} - Mentioned by {}", Settings::get().hostname, user.name,);
+          let html = &format!(
+            "<h1>User Mention</h1><br><div>{} - {}</div><br><a href={}/inbox>inbox</a>",
+            user.name, comment.content, hostname
+          );
+          match send_email(subject, &mention_email, &mention_user.name, html) {
+            Ok(_o) => _o,
+            Err(e) => error!("{}", e),
+          };
+        }
+      }
+    }
+  }
+
+  // Send notifs to the parent commenter / poster
+  match comment.parent_id {
+    Some(parent_id) => {
+      if let Ok(parent_comment) = Comment::read(&conn, parent_id) {
+        if parent_comment.creator_id != user.id {
+          if let Ok(parent_user) = User_::read(&conn, parent_comment.creator_id) {
+            recipient_ids.push(parent_user.id);
+
+            if do_send_email && parent_user.send_notifications_to_email {
+              if let Some(comment_reply_email) = parent_user.email {
+                let subject = &format!("{} - Reply from {}", Settings::get().hostname, user.name,);
+                let html = &format!(
+                  "<h1>Comment Reply</h1><br><div>{} - {}</div><br><a href={}/inbox>inbox</a>",
+                  user.name, comment.content, hostname
+                );
+                match send_email(subject, &comment_reply_email, &parent_user.name, html) {
+                  Ok(_o) => _o,
+                  Err(e) => error!("{}", e),
+                };
+              }
+            }
+          }
+        }
+      }
+    }
+    // Its a post
+    None => {
+      if post.creator_id != user.id {
+        if let Ok(parent_user) = User_::read(&conn, post.creator_id) {
+          recipient_ids.push(parent_user.id);
+
+          if do_send_email && parent_user.send_notifications_to_email {
+            if let Some(post_reply_email) = parent_user.email {
+              let subject = &format!("{} - Reply from {}", Settings::get().hostname, user.name,);
+              let html = &format!(
+                "<h1>Post Reply</h1><br><div>{} - {}</div><br><a href={}/inbox>inbox</a>",
+                user.name, comment.content, hostname
+              );
+              match send_email(subject, &post_reply_email, &parent_user.name, html) {
+                Ok(_o) => _o,
+                Err(e) => error!("{}", e),
+              };
+            }
+          }
+        }
+      }
+    }
+  };
+  recipient_ids
+}
index 36d9d9a7793692f7c89bf726e8126b8c630c990f..1ae42a8bd27aec9450349d15ca9d684789242bf4 100644 (file)
@@ -12,11 +12,11 @@ diesel = { version = "1.4.4", features = ["postgres","chrono","r2d2","64-column-
 chrono = { version = "0.4.7", features = ["serde"] }
 serde = { version = "1.0.105", features = ["derive"] }
 serde_json = { version = "1.0.52", features = ["preserve_order"]}
-strum = "0.18.0"
-strum_macros = "0.18.0"
+strum = "0.19.2"
+strum_macros = "0.19.2"
 log = "0.4.0"
 sha2 = "0.9"
-bcrypt = "0.8.0"
+bcrypt = "0.8.2"
 url = { version = "2.1.1", features = ["serde"] }
 lazy_static = "1.3.0"
 regex = "1.3.5"
index 6a5beb3bb7c9a4f767260f65895c68b2c28f44af..79b185fb74fa225aaf259faac255854a7cfcdd5b 100644 (file)
@@ -1,7 +1,7 @@
 use crate::{schema::activity, Crud};
 use diesel::{dsl::*, result::Error, *};
 use log::debug;
-use serde::{Serialize};
+use serde::Serialize;
 use serde_json::Value;
 use std::{
   fmt::Debug,
index c4165c22f1c3fb36a540805fbd860791416a0065..36beb9ff638b1a2070d9af70ecb7f4a2c2c6c6d3 100644 (file)
@@ -3,7 +3,7 @@ use crate::{
   Crud,
 };
 use diesel::{dsl::*, result::Error, *};
-use serde::{Serialize};
+use serde::Serialize;
 
 #[derive(Queryable, Identifiable, PartialEq, Debug, Serialize)]
 #[table_name = "category"]
index d7e5c08d0b8c723246246b07e6c43e6884355a99..cb121cf88138d5486b54efa8467a329354c9370d 100644 (file)
@@ -84,9 +84,7 @@ table! {
   }
 }
 
-#[derive(
-  Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone,
-)]
+#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone)]
 #[table_name = "comment_fast_view"]
 pub struct CommentView {
   pub id: i32,
index 1ecca0a1f9b830e7dc815ac7a795a86c082527f0..a6355504d06dad78311c18798b6b72c3aa4c3f59 100644 (file)
@@ -123,9 +123,7 @@ table! {
   }
 }
 
-#[derive(
-  Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone,
-)]
+#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone)]
 #[table_name = "community_fast_view"]
 pub struct CommunityView {
   pub id: i32,
index ed6e1dfb9f70a191845302bfc892f234986ff107..fc660208dcae8af3e73e5916ae738be9ccd4b534 100644 (file)
@@ -40,6 +40,8 @@ pub mod user_mention;
 pub mod user_mention_view;
 pub mod user_view;
 
+pub type DbPool = diesel::r2d2::Pool<diesel::r2d2::ConnectionManager<diesel::PgConnection>>;
+
 pub trait Crud<T> {
   fn create(conn: &PgConnection, form: &T) -> Result<Self, Error>
   where
index 7054a05a05b04dd15ad977063b8e0dadd9a8e2cb..efa949a4af10ebce247f466e522906c313c9dcd7 100644 (file)
@@ -1,6 +1,6 @@
 use crate::limit_and_offset;
 use diesel::{result::Error, *};
-use serde::{Serialize};
+use serde::Serialize;
 
 table! {
   mod_remove_post_view (id) {
@@ -17,9 +17,7 @@ table! {
   }
 }
 
-#[derive(
-  Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone,
-)]
+#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone)]
 #[table_name = "mod_remove_post_view"]
 pub struct ModRemovePostView {
   pub id: i32,
@@ -77,9 +75,7 @@ table! {
   }
 }
 
-#[derive(
-  Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone,
-)]
+#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone)]
 #[table_name = "mod_lock_post_view"]
 pub struct ModLockPostView {
   pub id: i32,
@@ -136,9 +132,7 @@ table! {
   }
 }
 
-#[derive(
-  Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone,
-)]
+#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone)]
 #[table_name = "mod_sticky_post_view"]
 pub struct ModStickyPostView {
   pub id: i32,
@@ -200,9 +194,7 @@ table! {
   }
 }
 
-#[derive(
-  Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone,
-)]
+#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone)]
 #[table_name = "mod_remove_comment_view"]
 pub struct ModRemoveCommentView {
   pub id: i32,
@@ -264,9 +256,7 @@ table! {
   }
 }
 
-#[derive(
-  Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone,
-)]
+#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone)]
 #[table_name = "mod_remove_community_view"]
 pub struct ModRemoveCommunityView {
   pub id: i32,
@@ -320,9 +310,7 @@ table! {
   }
 }
 
-#[derive(
-  Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone,
-)]
+#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone)]
 #[table_name = "mod_ban_from_community_view"]
 pub struct ModBanFromCommunityView {
   pub id: i32,
@@ -381,9 +369,7 @@ table! {
   }
 }
 
-#[derive(
-  Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone,
-)]
+#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone)]
 #[table_name = "mod_ban_view"]
 pub struct ModBanView {
   pub id: i32,
@@ -435,9 +421,7 @@ table! {
   }
 }
 
-#[derive(
-  Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone,
-)]
+#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone)]
 #[table_name = "mod_add_community_view"]
 pub struct ModAddCommunityView {
   pub id: i32,
@@ -492,9 +476,7 @@ table! {
   }
 }
 
-#[derive(
-  Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone,
-)]
+#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone)]
 #[table_name = "mod_add_view"]
 pub struct ModAddView {
   pub id: i32,
index 3d3afb7094efa8327bd1fd0063f4cdabe7dde70e..e88a80e306445c70c19004af875106bf59458af9 100644 (file)
@@ -1,7 +1,7 @@
 use super::post_view::post_fast_view::BoxedQuery;
 use crate::{fuzzy_search, limit_and_offset, ListingType, MaybeOptional, SortType};
 use diesel::{dsl::*, pg::Pg, result::Error, *};
-use serde::{Serialize};
+use serde::Serialize;
 
 // The faked schema since diesel doesn't do views
 table! {
@@ -106,9 +106,7 @@ table! {
   }
 }
 
-#[derive(
-  Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone,
-)]
+#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone)]
 #[table_name = "post_fast_view"]
 pub struct PostView {
   pub id: i32,
index 39fe66efa9028d82b6c99d21524542547294e267..68f7df42c3679b17bcf350820b1b87c8d71a60d2 100644 (file)
@@ -1,6 +1,6 @@
 use crate::{limit_and_offset, MaybeOptional};
 use diesel::{pg::Pg, result::Error, *};
-use serde::{Serialize};
+use serde::Serialize;
 
 // The faked schema since diesel doesn't do views
 table! {
@@ -28,9 +28,7 @@ table! {
   }
 }
 
-#[derive(
-  Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone,
-)]
+#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone)]
 #[table_name = "private_message_view"]
 pub struct PrivateMessageView {
   pub id: i32,
index c446edd9f27e72f2add810f181ef57b093a0c36d..a189dbced4fa00d9bac8ff5cf8223db5efe14004 100644 (file)
@@ -523,36 +523,36 @@ joinable!(user_mention -> comment (comment_id));
 joinable!(user_mention -> user_ (recipient_id));
 
 allow_tables_to_appear_in_same_query!(
-  activity,
-  category,
-  comment,
-  comment_aggregates_fast,
-  comment_like,
-  comment_saved,
-  community,
-  community_aggregates_fast,
-  community_follower,
-  community_moderator,
-  community_user_ban,
-  mod_add,
-  mod_add_community,
-  mod_ban,
-  mod_ban_from_community,
-  mod_lock_post,
-  mod_remove_comment,
-  mod_remove_community,
-  mod_remove_post,
-  mod_sticky_post,
-  password_reset_request,
-  post,
-  post_aggregates_fast,
-  post_like,
-  post_read,
-  post_saved,
-  private_message,
-  site,
-  user_,
-  user_ban,
-  user_fast,
-  user_mention,
+    activity,
+    category,
+    comment,
+    comment_aggregates_fast,
+    comment_like,
+    comment_saved,
+    community,
+    community_aggregates_fast,
+    community_follower,
+    community_moderator,
+    community_user_ban,
+    mod_add,
+    mod_add_community,
+    mod_ban,
+    mod_ban_from_community,
+    mod_lock_post,
+    mod_remove_comment,
+    mod_remove_community,
+    mod_remove_post,
+    mod_sticky_post,
+    password_reset_request,
+    post,
+    post_aggregates_fast,
+    post_like,
+    post_read,
+    post_saved,
+    private_message,
+    site,
+    user_,
+    user_ban,
+    user_fast,
+    user_mention,
 );
index 0edfd2b7090591dc662713cc85206cbe32def00e..fd15ac7781a1d64849a7b86d80f453e58047bdfe 100644 (file)
@@ -1,5 +1,5 @@
 use diesel::{result::Error, *};
-use serde::{Serialize};
+use serde::Serialize;
 
 table! {
   site_view (id) {
@@ -24,9 +24,7 @@ table! {
   }
 }
 
-#[derive(
-  Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone,
-)]
+#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone)]
 #[table_name = "site_view"]
 pub struct SiteView {
   pub id: i32,
index 247b5b360583aeb10e2ef5778a9661462de26abc..986701c4387be6b655abea066ca84000d8bf5271 100644 (file)
@@ -6,7 +6,7 @@ use crate::{
 };
 use bcrypt::{hash, DEFAULT_COST};
 use diesel::{dsl::*, result::Error, *};
-use serde::{Serialize};
+use serde::Serialize;
 
 #[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize)]
 #[table_name = "user_"]
index c35ad3613b64ae5b123a185a63c69f557894ffc0..d1ce5ebd08d4649833effaf87e660a5cf1d912ed 100644 (file)
@@ -1,6 +1,6 @@
 use crate::{limit_and_offset, MaybeOptional, SortType};
 use diesel::{dsl::*, pg::Pg, result::Error, *};
-use serde::{Serialize};
+use serde::Serialize;
 
 // The faked schema since diesel doesn't do views
 table! {
@@ -83,9 +83,7 @@ table! {
   }
 }
 
-#[derive(
-  Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone,
-)]
+#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone)]
 #[table_name = "user_mention_fast_view"]
 pub struct UserMentionView {
   pub id: i32,
index a4f6f47aef2d03726ca9201d8d6490b60e4dd42b..b0c28d31c3284bbbfa5cd1d9d9b298afc8f2da33 100644 (file)
@@ -1,7 +1,7 @@
 use super::user_view::user_fast::BoxedQuery;
 use crate::{fuzzy_search, limit_and_offset, MaybeOptional, SortType};
 use diesel::{dsl::*, pg::Pg, result::Error, *};
-use serde::{Serialize};
+use serde::Serialize;
 
 table! {
   user_view (id) {
@@ -51,9 +51,7 @@ table! {
   }
 }
 
-#[derive(
-  Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone,
-)]
+#[derive(Queryable, Identifiable, PartialEq, Debug, Serialize, QueryableByName, Clone)]
 #[table_name = "user_fast"]
 pub struct UserView {
   pub id: i32,
index dc86523ff339fa82f4addf5e893dcb5236c50e36..c5daaf7cd2183f151ccaedd629466b9121946ea4 100644 (file)
@@ -11,8 +11,8 @@ path = "src/lib.rs"
 [dependencies]
 lemmy_utils = { path = "../lemmy_utils" }
 tokio = "0.2.21"
-strum = "0.18.0"
-strum_macros = "0.18.0"
+strum = "0.19.2"
+strum_macros = "0.19.2"
 futures = "0.3.5"
 actix-web = { version = "3.0.0", default-features = false, features = ["rustls"] }
 log = "0.4.0"
index 260f7e2cb117b3be9f24f8f304d71a411e297025..8f962bbe615454971e81e9f762602853de16fe04 100644 (file)
@@ -8,8 +8,8 @@ extern crate tokio;
 use actix_web::dev::{Service, ServiceRequest, ServiceResponse, Transform};
 use futures::future::{ok, Ready};
 use lemmy_utils::{
-  get_ip,
   settings::{RateLimitConfig, Settings},
+  utils::get_ip,
   LemmyError,
 };
 use rate_limiter::{RateLimitType, RateLimiter};
index be6cb65352fc87ed6add4507aef12c515d8040a1..58d0893e0e373662d520adedf71a4b674bf5b9a0 100644 (file)
@@ -12,16 +12,16 @@ path = "src/lib.rs"
 [dependencies]
 regex = "1.3.5"
 config = { version = "0.10.1", default-features = false, features = ["hjson"] }
-chrono = { version = "0.4.7", features = ["serde"] }
+chrono = { version = "0.4.15", features = ["serde"] }
 lettre = "0.9.3"
 lettre_email = "0.9.4"
 log = "0.4.0"
 itertools = "0.9.0"
 rand = "0.7.3"
-serde = { version = "1.0.105", features = ["derive"] }
+serde = { version = "1.0.115", features = ["derive"] }
 serde_json = { version = "1.0.52", features = ["preserve_order"]}
 thiserror = "1.0.20"
-comrak = "0.7"
+comrak = "0.8.2"
 lazy_static = "1.3.0"
 openssl = "0.10"
 url = { version = "2.1.1", features = ["serde"] }
diff --git a/server/lemmy_utils/src/apub.rs b/server/lemmy_utils/src/apub.rs
new file mode 100644 (file)
index 0000000..08e7a44
--- /dev/null
@@ -0,0 +1,64 @@
+use crate::settings::Settings;
+use openssl::{pkey::PKey, rsa::Rsa};
+use std::io::{Error, ErrorKind};
+use url::Url;
+
+pub struct Keypair {
+  pub private_key: String,
+  pub public_key: String,
+}
+
+/// Generate the asymmetric keypair for ActivityPub HTTP signatures.
+pub fn generate_actor_keypair() -> Result<Keypair, Error> {
+  let rsa = Rsa::generate(2048)?;
+  let pkey = PKey::from_rsa(rsa)?;
+  let public_key = pkey.public_key_to_pem()?;
+  let private_key = pkey.private_key_to_pem_pkcs8()?;
+  let key_to_string = |key| match String::from_utf8(key) {
+    Ok(s) => Ok(s),
+    Err(e) => Err(Error::new(
+      ErrorKind::Other,
+      format!("Failed converting key to string: {}", e),
+    )),
+  };
+  Ok(Keypair {
+    private_key: key_to_string(private_key)?,
+    public_key: key_to_string(public_key)?,
+  })
+}
+
+pub enum EndpointType {
+  Community,
+  User,
+  Post,
+  Comment,
+  PrivateMessage,
+}
+
+pub fn get_apub_protocol_string() -> &'static str {
+  if Settings::get().federation.tls_enabled {
+    "https"
+  } else {
+    "http"
+  }
+}
+
+/// Generates the ActivityPub ID for a given object type and ID.
+pub fn make_apub_endpoint(endpoint_type: EndpointType, name: &str) -> Url {
+  let point = match endpoint_type {
+    EndpointType::Community => "c",
+    EndpointType::User => "u",
+    EndpointType::Post => "post",
+    EndpointType::Comment => "comment",
+    EndpointType::PrivateMessage => "private_message",
+  };
+
+  Url::parse(&format!(
+    "{}://{}/{}/{}",
+    get_apub_protocol_string(),
+    Settings::get().hostname,
+    point,
+    name
+  ))
+  .unwrap()
+}
diff --git a/server/lemmy_utils/src/email.rs b/server/lemmy_utils/src/email.rs
new file mode 100644 (file)
index 0000000..43b880e
--- /dev/null
@@ -0,0 +1,55 @@
+use crate::settings::Settings;
+use lettre::{
+  smtp::{
+    authentication::{Credentials, Mechanism},
+    extension::ClientId,
+    ConnectionReuseParameters,
+  },
+  ClientSecurity,
+  SmtpClient,
+  Transport,
+};
+use lettre_email::Email;
+
+pub fn send_email(
+  subject: &str,
+  to_email: &str,
+  to_username: &str,
+  html: &str,
+) -> Result<(), String> {
+  let email_config = Settings::get().email.ok_or("no_email_setup")?;
+
+  let email = Email::builder()
+    .to((to_email, to_username))
+    .from(email_config.smtp_from_address.to_owned())
+    .subject(subject)
+    .html(html)
+    .build()
+    .unwrap();
+
+  let mailer = if email_config.use_tls {
+    SmtpClient::new_simple(&email_config.smtp_server).unwrap()
+  } else {
+    SmtpClient::new(&email_config.smtp_server, ClientSecurity::None).unwrap()
+  }
+  .hello_name(ClientId::Domain(Settings::get().hostname))
+  .smtp_utf8(true)
+  .authentication_mechanism(Mechanism::Plain)
+  .connection_reuse(ConnectionReuseParameters::ReuseUnlimited);
+  let mailer = if let (Some(login), Some(password)) =
+    (&email_config.smtp_login, &email_config.smtp_password)
+  {
+    mailer.credentials(Credentials::new(login.to_owned(), password.to_owned()))
+  } else {
+    mailer
+  };
+
+  let mut transport = mailer.transport();
+  let result = transport.send(email.into());
+  transport.close();
+
+  match result {
+    Ok(_) => Ok(()),
+    Err(e) => Err(e.to_string()),
+  }
+}
index d282182829b7b1bbb7f75b29c50e59a32f0ff231..9cc1fe025c498550881aa4c636327c2c116ab067 100644 (file)
@@ -12,29 +12,16 @@ extern crate serde_json;
 extern crate thiserror;
 extern crate url;
 
+pub mod apub;
+pub mod email;
 pub mod settings;
+#[cfg(test)]
+mod test;
+pub mod utils;
 
 use crate::settings::Settings;
-use actix_web::dev::ConnectionInfo;
-use chrono::{DateTime, FixedOffset, Local, NaiveDateTime};
-use itertools::Itertools;
-use lettre::{
-  smtp::{
-    authentication::{Credentials, Mechanism},
-    extension::ClientId,
-    ConnectionReuseParameters,
-  },
-  ClientSecurity,
-  SmtpClient,
-  Transport,
-};
-use lettre_email::Email;
-use openssl::{pkey::PKey, rsa::Rsa};
-use rand::{distributions::Alphanumeric, thread_rng, Rng};
-use regex::{Regex, RegexBuilder};
-use std::io::{Error, ErrorKind};
+use regex::Regex;
 use thiserror::Error;
-use url::Url;
 
 pub type ConnectionId = usize;
 pub type PostId = i32;
@@ -90,236 +77,7 @@ impl std::fmt::Display for LemmyError {
 
 impl actix_web::error::ResponseError for LemmyError {}
 
-pub fn naive_from_unix(time: i64) -> NaiveDateTime {
-  NaiveDateTime::from_timestamp(time, 0)
-}
-
-pub fn convert_datetime(datetime: NaiveDateTime) -> DateTime<FixedOffset> {
-  let now = Local::now();
-  DateTime::<FixedOffset>::from_utc(datetime, *now.offset())
-}
-
-pub fn remove_slurs(test: &str) -> String {
-  SLUR_REGEX.replace_all(test, "*removed*").to_string()
-}
-
-pub fn slur_check(test: &str) -> Result<(), Vec<&str>> {
-  let mut matches: Vec<&str> = SLUR_REGEX.find_iter(test).map(|mat| mat.as_str()).collect();
-
-  // Unique
-  matches.sort_unstable();
-  matches.dedup();
-
-  if matches.is_empty() {
-    Ok(())
-  } else {
-    Err(matches)
-  }
-}
-
-pub fn slurs_vec_to_str(slurs: Vec<&str>) -> String {
-  let start = "No slurs - ";
-  let combined = &slurs.join(", ");
-  [start, combined].concat()
-}
-
-pub fn generate_random_string() -> String {
-  thread_rng().sample_iter(&Alphanumeric).take(30).collect()
-}
-
-pub fn send_email(
-  subject: &str,
-  to_email: &str,
-  to_username: &str,
-  html: &str,
-) -> Result<(), String> {
-  let email_config = Settings::get().email.ok_or("no_email_setup")?;
-
-  let email = Email::builder()
-    .to((to_email, to_username))
-    .from(email_config.smtp_from_address.to_owned())
-    .subject(subject)
-    .html(html)
-    .build()
-    .unwrap();
-
-  let mailer = if email_config.use_tls {
-    SmtpClient::new_simple(&email_config.smtp_server).unwrap()
-  } else {
-    SmtpClient::new(&email_config.smtp_server, ClientSecurity::None).unwrap()
-  }
-  .hello_name(ClientId::Domain(Settings::get().hostname))
-  .smtp_utf8(true)
-  .authentication_mechanism(Mechanism::Plain)
-  .connection_reuse(ConnectionReuseParameters::ReuseUnlimited);
-  let mailer = if let (Some(login), Some(password)) =
-    (&email_config.smtp_login, &email_config.smtp_password)
-  {
-    mailer.credentials(Credentials::new(login.to_owned(), password.to_owned()))
-  } else {
-    mailer
-  };
-
-  let mut transport = mailer.transport();
-  let result = transport.send(email.into());
-  transport.close();
-
-  match result {
-    Ok(_) => Ok(()),
-    Err(e) => Err(e.to_string()),
-  }
-}
-
-pub fn markdown_to_html(text: &str) -> String {
-  comrak::markdown_to_html(text, &comrak::ComrakOptions::default())
-}
-
-// TODO nothing is done with community / group webfingers yet, so just ignore those for now
-#[derive(Clone, PartialEq, Eq, Hash)]
-pub struct MentionData {
-  pub name: String,
-  pub domain: String,
-}
-
-impl MentionData {
-  pub fn is_local(&self) -> bool {
-    Settings::get().hostname.eq(&self.domain)
-  }
-  pub fn full_name(&self) -> String {
-    format!("@{}@{}", &self.name, &self.domain)
-  }
-}
-
-pub fn scrape_text_for_mentions(text: &str) -> Vec<MentionData> {
-  let mut out: Vec<MentionData> = Vec::new();
-  for caps in MENTIONS_REGEX.captures_iter(text) {
-    out.push(MentionData {
-      name: caps["name"].to_string(),
-      domain: caps["domain"].to_string(),
-    });
-  }
-  out.into_iter().unique().collect()
-}
-
-pub fn is_valid_username(name: &str) -> bool {
-  VALID_USERNAME_REGEX.is_match(name)
-}
-
-// Can't do a regex here, reverse lookarounds not supported
-pub fn is_valid_preferred_username(preferred_username: &str) -> bool {
-  !preferred_username.starts_with('@')
-    && preferred_username.len() >= 3
-    && preferred_username.len() <= 20
-}
-
-pub fn is_valid_community_name(name: &str) -> bool {
-  VALID_COMMUNITY_NAME_REGEX.is_match(name)
-}
-
-pub fn is_valid_post_title(title: &str) -> bool {
-  VALID_POST_TITLE_REGEX.is_match(title)
-}
-
-#[cfg(test)]
-mod tests {
-  use crate::{
-    is_valid_community_name,
-    is_valid_post_title,
-    is_valid_preferred_username,
-    is_valid_username,
-    remove_slurs,
-    scrape_text_for_mentions,
-    slur_check,
-    slurs_vec_to_str,
-  };
-
-  #[test]
-  fn test_mentions_regex() {
-    let text = "Just read a great blog post by [@tedu@honk.teduangst.com](/u/test). And another by !test_community@fish.teduangst.com . Another [@lemmy@lemmy-alpha:8540](/u/fish)";
-    let mentions = scrape_text_for_mentions(text);
-
-    assert_eq!(mentions[0].name, "tedu".to_string());
-    assert_eq!(mentions[0].domain, "honk.teduangst.com".to_string());
-    assert_eq!(mentions[1].domain, "lemmy-alpha:8540".to_string());
-  }
-
-  #[test]
-  fn test_valid_register_username() {
-    assert!(is_valid_username("Hello_98"));
-    assert!(is_valid_username("ten"));
-    assert!(!is_valid_username("Hello-98"));
-    assert!(!is_valid_username("a"));
-    assert!(!is_valid_username(""));
-  }
-
-  #[test]
-  fn test_valid_preferred_username() {
-    assert!(is_valid_preferred_username("hello @there"));
-    assert!(!is_valid_preferred_username("@hello there"));
-  }
-
-  #[test]
-  fn test_valid_community_name() {
-    assert!(is_valid_community_name("example"));
-    assert!(is_valid_community_name("example_community"));
-    assert!(!is_valid_community_name("Example"));
-    assert!(!is_valid_community_name("Ex"));
-    assert!(!is_valid_community_name(""));
-  }
-
-  #[test]
-  fn test_valid_post_title() {
-    assert!(is_valid_post_title("Post Title"));
-    assert!(is_valid_post_title("   POST TITLE ðŸ˜ƒðŸ˜ƒðŸ˜ƒðŸ˜ƒðŸ˜ƒ"));
-    assert!(!is_valid_post_title("\n \n \n \n                  ")); // tabs/spaces/newlines
-  }
-
-  #[test]
-  fn test_slur_filter() {
-    let test =
-      "coons test dindu ladyboy tranny retardeds. Capitalized Niggerz. This is a bunch of other safe text.";
-    let slur_free = "No slurs here";
-    assert_eq!(
-      remove_slurs(&test),
-      "*removed* test *removed* *removed* *removed* *removed*. Capitalized *removed*. This is a bunch of other safe text."
-        .to_string()
-    );
-
-    let has_slurs_vec = vec![
-      "Niggerz",
-      "coons",
-      "dindu",
-      "ladyboy",
-      "retardeds",
-      "tranny",
-    ];
-    let has_slurs_err_str = "No slurs - Niggerz, coons, dindu, ladyboy, retardeds, tranny";
-
-    assert_eq!(slur_check(test), Err(has_slurs_vec));
-    assert_eq!(slur_check(slur_free), Ok(()));
-    if let Err(slur_vec) = slur_check(test) {
-      assert_eq!(&slurs_vec_to_str(slur_vec), has_slurs_err_str);
-    }
-  }
-
-  // These helped with testing
-  // #[test]
-  // fn test_send_email() {
-  //  let result =  send_email("not a subject", "test_email@gmail.com", "ur user", "<h1>HI there</h1>");
-  //   assert!(result.is_ok());
-  // }
-}
-
 lazy_static! {
-  static ref EMAIL_REGEX: Regex = Regex::new(r"^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$").unwrap();
-  static ref SLUR_REGEX: Regex = RegexBuilder::new(r"(fag(g|got|tard)?|maricos?|cock\s?sucker(s|ing)?|\bn(i|1)g(\b|g?(a|er)?(s|z)?)\b|dindu(s?)|mudslime?s?|kikes?|mongoloids?|towel\s*heads?|\bspi(c|k)s?\b|\bchinks?|niglets?|beaners?|\bnips?\b|\bcoons?\b|jungle\s*bunn(y|ies?)|jigg?aboo?s?|\bpakis?\b|rag\s*heads?|gooks?|cunts?|bitch(es|ing|y)?|puss(y|ies?)|twats?|feminazis?|whor(es?|ing)|\bslut(s|t?y)?|\btr(a|@)nn?(y|ies?)|ladyboy(s?)|\b(b|re|r)tard(ed)?s?)").case_insensitive(true).build().unwrap();
-  static ref USERNAME_MATCHES_REGEX: Regex = Regex::new(r"/u/[a-zA-Z][0-9a-zA-Z_]*").unwrap();
-  // TODO keep this old one, it didn't work with port well tho
-  // static ref MENTIONS_REGEX: Regex = Regex::new(r"@(?P<name>[\w.]+)@(?P<domain>[a-zA-Z0-9._-]+\.[a-zA-Z0-9_-]+)").unwrap();
-  static ref MENTIONS_REGEX: Regex = Regex::new(r"@(?P<name>[\w.]+)@(?P<domain>[a-zA-Z0-9._:-]+)").unwrap();
-  static ref VALID_USERNAME_REGEX: Regex = Regex::new(r"^[a-zA-Z0-9_]{3,20}$").unwrap();
-  static ref VALID_COMMUNITY_NAME_REGEX: Regex = Regex::new(r"^[a-z0-9_]{3,20}$").unwrap();
-  static ref VALID_POST_TITLE_REGEX: Regex = Regex::new(r".*\S.*").unwrap();
   pub static ref WEBFINGER_COMMUNITY_REGEX: Regex = Regex::new(&format!(
     "^group:([a-z0-9_]{{3, 20}})@{}$",
     Settings::get().hostname
@@ -333,73 +91,3 @@ lazy_static! {
   pub static ref CACHE_CONTROL_REGEX: Regex =
     Regex::new("^((text|image)/.+|application/javascript)$").unwrap();
 }
-
-pub struct Keypair {
-  pub private_key: String,
-  pub public_key: String,
-}
-
-/// Generate the asymmetric keypair for ActivityPub HTTP signatures.
-pub fn generate_actor_keypair() -> Result<Keypair, Error> {
-  let rsa = Rsa::generate(2048)?;
-  let pkey = PKey::from_rsa(rsa)?;
-  let public_key = pkey.public_key_to_pem()?;
-  let private_key = pkey.private_key_to_pem_pkcs8()?;
-  let key_to_string = |key| match String::from_utf8(key) {
-    Ok(s) => Ok(s),
-    Err(e) => Err(Error::new(
-      ErrorKind::Other,
-      format!("Failed converting key to string: {}", e),
-    )),
-  };
-  Ok(Keypair {
-    private_key: key_to_string(private_key)?,
-    public_key: key_to_string(public_key)?,
-  })
-}
-
-pub enum EndpointType {
-  Community,
-  User,
-  Post,
-  Comment,
-  PrivateMessage,
-}
-
-pub fn get_apub_protocol_string() -> &'static str {
-  if Settings::get().federation.tls_enabled {
-    "https"
-  } else {
-    "http"
-  }
-}
-
-/// Generates the ActivityPub ID for a given object type and ID.
-pub fn make_apub_endpoint(endpoint_type: EndpointType, name: &str) -> Url {
-  let point = match endpoint_type {
-    EndpointType::Community => "c",
-    EndpointType::User => "u",
-    EndpointType::Post => "post",
-    EndpointType::Comment => "comment",
-    EndpointType::PrivateMessage => "private_message",
-  };
-
-  Url::parse(&format!(
-    "{}://{}/{}/{}",
-    get_apub_protocol_string(),
-    Settings::get().hostname,
-    point,
-    name
-  ))
-  .unwrap()
-}
-
-pub fn get_ip(conn_info: &ConnectionInfo) -> String {
-  conn_info
-    .realip_remote_addr()
-    .unwrap_or("127.0.0.1:12345")
-    .split(':')
-    .next()
-    .unwrap_or("127.0.0.1")
-    .to_string()
-}
diff --git a/server/lemmy_utils/src/test.rs b/server/lemmy_utils/src/test.rs
new file mode 100644 (file)
index 0000000..fdca384
--- /dev/null
@@ -0,0 +1,86 @@
+use crate::utils::{
+  is_valid_community_name,
+  is_valid_post_title,
+  is_valid_preferred_username,
+  is_valid_username,
+  remove_slurs,
+  scrape_text_for_mentions,
+  slur_check,
+  slurs_vec_to_str,
+};
+
+#[test]
+fn test_mentions_regex() {
+  let text = "Just read a great blog post by [@tedu@honk.teduangst.com](/u/test). And another by !test_community@fish.teduangst.com . Another [@lemmy@lemmy-alpha:8540](/u/fish)";
+  let mentions = scrape_text_for_mentions(text);
+
+  assert_eq!(mentions[0].name, "tedu".to_string());
+  assert_eq!(mentions[0].domain, "honk.teduangst.com".to_string());
+  assert_eq!(mentions[1].domain, "lemmy-alpha:8540".to_string());
+}
+
+#[test]
+fn test_valid_register_username() {
+  assert!(is_valid_username("Hello_98"));
+  assert!(is_valid_username("ten"));
+  assert!(!is_valid_username("Hello-98"));
+  assert!(!is_valid_username("a"));
+  assert!(!is_valid_username(""));
+}
+
+#[test]
+fn test_valid_preferred_username() {
+  assert!(is_valid_preferred_username("hello @there"));
+  assert!(!is_valid_preferred_username("@hello there"));
+}
+
+#[test]
+fn test_valid_community_name() {
+  assert!(is_valid_community_name("example"));
+  assert!(is_valid_community_name("example_community"));
+  assert!(!is_valid_community_name("Example"));
+  assert!(!is_valid_community_name("Ex"));
+  assert!(!is_valid_community_name(""));
+}
+
+#[test]
+fn test_valid_post_title() {
+  assert!(is_valid_post_title("Post Title"));
+  assert!(is_valid_post_title("   POST TITLE ðŸ˜ƒðŸ˜ƒðŸ˜ƒðŸ˜ƒðŸ˜ƒ"));
+  assert!(!is_valid_post_title("\n \n \n \n                    ")); // tabs/spaces/newlines
+}
+
+#[test]
+fn test_slur_filter() {
+  let test =
+      "coons test dindu ladyboy tranny retardeds. Capitalized Niggerz. This is a bunch of other safe text.";
+  let slur_free = "No slurs here";
+  assert_eq!(
+      remove_slurs(&test),
+      "*removed* test *removed* *removed* *removed* *removed*. Capitalized *removed*. This is a bunch of other safe text."
+        .to_string()
+    );
+
+  let has_slurs_vec = vec![
+    "Niggerz",
+    "coons",
+    "dindu",
+    "ladyboy",
+    "retardeds",
+    "tranny",
+  ];
+  let has_slurs_err_str = "No slurs - Niggerz, coons, dindu, ladyboy, retardeds, tranny";
+
+  assert_eq!(slur_check(test), Err(has_slurs_vec));
+  assert_eq!(slur_check(slur_free), Ok(()));
+  if let Err(slur_vec) = slur_check(test) {
+    assert_eq!(&slurs_vec_to_str(slur_vec), has_slurs_err_str);
+  }
+}
+
+// These helped with testing
+// #[test]
+// fn test_send_email() {
+//  let result =  send_email("not a subject", "test_email@gmail.com", "ur user", "<h1>HI there</h1>");
+//   assert!(result.is_ok());
+// }
diff --git a/server/lemmy_utils/src/utils.rs b/server/lemmy_utils/src/utils.rs
new file mode 100644 (file)
index 0000000..87aad57
--- /dev/null
@@ -0,0 +1,130 @@
+use crate::{settings::Settings, APIError};
+use actix_web::dev::ConnectionInfo;
+use chrono::{DateTime, FixedOffset, Local, NaiveDateTime};
+use itertools::Itertools;
+use rand::{distributions::Alphanumeric, thread_rng, Rng};
+use regex::{Regex, RegexBuilder};
+
+lazy_static! {
+static ref EMAIL_REGEX: Regex = Regex::new(r"^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$").unwrap();
+static ref SLUR_REGEX: Regex = RegexBuilder::new(r"(fag(g|got|tard)?|maricos?|cock\s?sucker(s|ing)?|\bn(i|1)g(\b|g?(a|er)?(s|z)?)\b|dindu(s?)|mudslime?s?|kikes?|mongoloids?|towel\s*heads?|\bspi(c|k)s?\b|\bchinks?|niglets?|beaners?|\bnips?\b|\bcoons?\b|jungle\s*bunn(y|ies?)|jigg?aboo?s?|\bpakis?\b|rag\s*heads?|gooks?|cunts?|bitch(es|ing|y)?|puss(y|ies?)|twats?|feminazis?|whor(es?|ing)|\bslut(s|t?y)?|\btr(a|@)nn?(y|ies?)|ladyboy(s?)|\b(b|re|r)tard(ed)?s?)").case_insensitive(true).build().unwrap();
+static ref USERNAME_MATCHES_REGEX: Regex = Regex::new(r"/u/[a-zA-Z][0-9a-zA-Z_]*").unwrap();
+// TODO keep this old one, it didn't work with port well tho
+// static ref MENTIONS_REGEX: Regex = Regex::new(r"@(?P<name>[\w.]+)@(?P<domain>[a-zA-Z0-9._-]+\.[a-zA-Z0-9_-]+)").unwrap();
+static ref MENTIONS_REGEX: Regex = Regex::new(r"@(?P<name>[\w.]+)@(?P<domain>[a-zA-Z0-9._:-]+)").unwrap();
+static ref VALID_USERNAME_REGEX: Regex = Regex::new(r"^[a-zA-Z0-9_]{3,20}$").unwrap();
+static ref VALID_COMMUNITY_NAME_REGEX: Regex = Regex::new(r"^[a-z0-9_]{3,20}$").unwrap();
+static ref VALID_POST_TITLE_REGEX: Regex = Regex::new(r".*\S.*").unwrap();
+}
+
+pub fn naive_from_unix(time: i64) -> NaiveDateTime {
+  NaiveDateTime::from_timestamp(time, 0)
+}
+
+pub fn convert_datetime(datetime: NaiveDateTime) -> DateTime<FixedOffset> {
+  let now = Local::now();
+  DateTime::<FixedOffset>::from_utc(datetime, *now.offset())
+}
+
+pub fn remove_slurs(test: &str) -> String {
+  SLUR_REGEX.replace_all(test, "*removed*").to_string()
+}
+
+pub(crate) fn slur_check(test: &str) -> Result<(), Vec<&str>> {
+  let mut matches: Vec<&str> = SLUR_REGEX.find_iter(test).map(|mat| mat.as_str()).collect();
+
+  // Unique
+  matches.sort_unstable();
+  matches.dedup();
+
+  if matches.is_empty() {
+    Ok(())
+  } else {
+    Err(matches)
+  }
+}
+
+pub fn check_slurs(text: &str) -> Result<(), APIError> {
+  if let Err(slurs) = slur_check(text) {
+    Err(APIError::err(&slurs_vec_to_str(slurs)))
+  } else {
+    Ok(())
+  }
+}
+
+pub fn check_slurs_opt(text: &Option<String>) -> Result<(), APIError> {
+  match text {
+    Some(t) => check_slurs(t),
+    None => Ok(()),
+  }
+}
+
+pub(crate) fn slurs_vec_to_str(slurs: Vec<&str>) -> String {
+  let start = "No slurs - ";
+  let combined = &slurs.join(", ");
+  [start, combined].concat()
+}
+
+pub fn generate_random_string() -> String {
+  thread_rng().sample_iter(&Alphanumeric).take(30).collect()
+}
+
+pub fn markdown_to_html(text: &str) -> String {
+  comrak::markdown_to_html(text, &comrak::ComrakOptions::default())
+}
+
+// TODO nothing is done with community / group webfingers yet, so just ignore those for now
+#[derive(Clone, PartialEq, Eq, Hash)]
+pub struct MentionData {
+  pub name: String,
+  pub domain: String,
+}
+
+impl MentionData {
+  pub fn is_local(&self) -> bool {
+    Settings::get().hostname.eq(&self.domain)
+  }
+  pub fn full_name(&self) -> String {
+    format!("@{}@{}", &self.name, &self.domain)
+  }
+}
+
+pub fn scrape_text_for_mentions(text: &str) -> Vec<MentionData> {
+  let mut out: Vec<MentionData> = Vec::new();
+  for caps in MENTIONS_REGEX.captures_iter(text) {
+    out.push(MentionData {
+      name: caps["name"].to_string(),
+      domain: caps["domain"].to_string(),
+    });
+  }
+  out.into_iter().unique().collect()
+}
+
+pub fn is_valid_username(name: &str) -> bool {
+  VALID_USERNAME_REGEX.is_match(name)
+}
+
+// Can't do a regex here, reverse lookarounds not supported
+pub fn is_valid_preferred_username(preferred_username: &str) -> bool {
+  !preferred_username.starts_with('@')
+    && preferred_username.len() >= 3
+    && preferred_username.len() <= 20
+}
+
+pub fn is_valid_community_name(name: &str) -> bool {
+  VALID_COMMUNITY_NAME_REGEX.is_match(name)
+}
+
+pub fn is_valid_post_title(title: &str) -> bool {
+  VALID_POST_TITLE_REGEX.is_match(title)
+}
+
+pub fn get_ip(conn_info: &ConnectionInfo) -> String {
+  conn_info
+    .realip_remote_addr()
+    .unwrap_or("127.0.0.1:12345")
+    .split(':')
+    .next()
+    .unwrap_or("127.0.0.1")
+    .to_string()
+}
index f0e56810e0a5cbb4f195a58073cbcc3f725ace38..dd1970393187a99dd9f3646e87ebfb653f38d9d4 100644 (file)
@@ -8,16 +8,14 @@ use crate::{
     Perform,
   },
   apub::{ApubLikeableType, ApubObjectType},
-  blocking,
   websocket::{
     messages::{JoinCommunityRoom, SendComment},
     UserOperation,
   },
-  DbPool,
   LemmyContext,
 };
 use actix_web::web::Data;
-use lemmy_api_structs::comment::*;
+use lemmy_api_structs::{blocking, comment::*, send_local_notifs};
 use lemmy_db::{
   comment::*,
   comment_view::*,
@@ -25,7 +23,6 @@ use lemmy_db::{
   post::*,
   site_view::*,
   user::*,
-  user_mention::*,
   Crud,
   Likeable,
   ListingType,
@@ -33,18 +30,12 @@ use lemmy_db::{
   SortType,
 };
 use lemmy_utils::{
-  make_apub_endpoint,
-  remove_slurs,
-  scrape_text_for_mentions,
-  send_email,
-  settings::Settings,
+  apub::{make_apub_endpoint, EndpointType},
+  utils::{remove_slurs, scrape_text_for_mentions},
   APIError,
   ConnectionId,
-  EndpointType,
   LemmyError,
-  MentionData,
 };
-use log::error;
 use std::str::FromStr;
 
 #[async_trait::async_trait(?Send)]
@@ -707,124 +698,3 @@ impl Perform for GetComments {
     Ok(GetCommentsResponse { comments })
   }
 }
-
-pub async fn send_local_notifs(
-  mentions: Vec<MentionData>,
-  comment: Comment,
-  user: &User_,
-  post: Post,
-  pool: &DbPool,
-  do_send_email: bool,
-) -> Result<Vec<i32>, LemmyError> {
-  let user2 = user.clone();
-  let ids = blocking(pool, move |conn| {
-    do_send_local_notifs(conn, &mentions, &comment, &user2, &post, do_send_email)
-  })
-  .await?;
-
-  Ok(ids)
-}
-
-fn do_send_local_notifs(
-  conn: &diesel::PgConnection,
-  mentions: &[MentionData],
-  comment: &Comment,
-  user: &User_,
-  post: &Post,
-  do_send_email: bool,
-) -> Vec<i32> {
-  let mut recipient_ids = Vec::new();
-  let hostname = &format!("https://{}", Settings::get().hostname);
-
-  // Send the local mentions
-  for mention in mentions
-    .iter()
-    .filter(|m| m.is_local() && m.name.ne(&user.name))
-    .collect::<Vec<&MentionData>>()
-  {
-    if let Ok(mention_user) = User_::read_from_name(&conn, &mention.name) {
-      // TODO
-      // At some point, make it so you can't tag the parent creator either
-      // This can cause two notifications, one for reply and the other for mention
-      recipient_ids.push(mention_user.id);
-
-      let user_mention_form = UserMentionForm {
-        recipient_id: mention_user.id,
-        comment_id: comment.id,
-        read: None,
-      };
-
-      // Allow this to fail softly, since comment edits might re-update or replace it
-      // Let the uniqueness handle this fail
-      match UserMention::create(&conn, &user_mention_form) {
-        Ok(_mention) => (),
-        Err(_e) => error!("{}", &_e),
-      };
-
-      // Send an email to those users that have notifications on
-      if do_send_email && mention_user.send_notifications_to_email {
-        if let Some(mention_email) = mention_user.email {
-          let subject = &format!("{} - Mentioned by {}", Settings::get().hostname, user.name,);
-          let html = &format!(
-            "<h1>User Mention</h1><br><div>{} - {}</div><br><a href={}/inbox>inbox</a>",
-            user.name, comment.content, hostname
-          );
-          match send_email(subject, &mention_email, &mention_user.name, html) {
-            Ok(_o) => _o,
-            Err(e) => error!("{}", e),
-          };
-        }
-      }
-    }
-  }
-
-  // Send notifs to the parent commenter / poster
-  match comment.parent_id {
-    Some(parent_id) => {
-      if let Ok(parent_comment) = Comment::read(&conn, parent_id) {
-        if parent_comment.creator_id != user.id {
-          if let Ok(parent_user) = User_::read(&conn, parent_comment.creator_id) {
-            recipient_ids.push(parent_user.id);
-
-            if do_send_email && parent_user.send_notifications_to_email {
-              if let Some(comment_reply_email) = parent_user.email {
-                let subject = &format!("{} - Reply from {}", Settings::get().hostname, user.name,);
-                let html = &format!(
-                  "<h1>Comment Reply</h1><br><div>{} - {}</div><br><a href={}/inbox>inbox</a>",
-                  user.name, comment.content, hostname
-                );
-                match send_email(subject, &comment_reply_email, &parent_user.name, html) {
-                  Ok(_o) => _o,
-                  Err(e) => error!("{}", e),
-                };
-              }
-            }
-          }
-        }
-      }
-    }
-    // Its a post
-    None => {
-      if post.creator_id != user.id {
-        if let Ok(parent_user) = User_::read(&conn, post.creator_id) {
-          recipient_ids.push(parent_user.id);
-
-          if do_send_email && parent_user.send_notifications_to_email {
-            if let Some(post_reply_email) = parent_user.email {
-              let subject = &format!("{} - Reply from {}", Settings::get().hostname, user.name,);
-              let html = &format!(
-                "<h1>Post Reply</h1><br><div>{} - {}</div><br><a href={}/inbox>inbox</a>",
-                user.name, comment.content, hostname
-              );
-              match send_email(subject, &post_reply_email, &parent_user.name, html) {
-                Ok(_o) => _o,
-                Err(e) => error!("{}", e),
-              };
-            }
-          }
-        }
-      }
-    }
-  };
-  recipient_ids
-}
index 6fb67b330c81a9c3f5f8af62a5e553901ee2257c..8486861c4b38fb4d20a3aa3a355276b62997a8d1 100644 (file)
@@ -1,15 +1,6 @@
 use crate::{
-  api::{
-    check_slurs,
-    check_slurs_opt,
-    get_user_from_jwt,
-    get_user_from_jwt_opt,
-    is_admin,
-    is_mod_or_admin,
-    Perform,
-  },
+  api::{get_user_from_jwt, get_user_from_jwt_opt, is_admin, is_mod_or_admin, Perform},
   apub::ActorType,
-  blocking,
   websocket::{
     messages::{GetCommunityUsersOnline, JoinCommunityRoom, SendCommunityRoomMessage},
     UserOperation,
@@ -18,7 +9,7 @@ use crate::{
 };
 use actix_web::web::Data;
 use anyhow::Context;
-use lemmy_api_structs::community::*;
+use lemmy_api_structs::{blocking, community::*};
 use lemmy_db::{
   comment::Comment,
   comment_view::CommentQueryBuilder,
@@ -37,14 +28,11 @@ use lemmy_db::{
   SortType,
 };
 use lemmy_utils::{
-  generate_actor_keypair,
-  is_valid_community_name,
+  apub::{generate_actor_keypair, make_apub_endpoint, EndpointType},
   location_info,
-  make_apub_endpoint,
-  naive_from_unix,
+  utils::{check_slurs, check_slurs_opt, is_valid_community_name, naive_from_unix},
   APIError,
   ConnectionId,
-  EndpointType,
   LemmyError,
 };
 use std::str::FromStr;
index a1b8c188d606c1ec8afcf3a8f5c6001c65abd88a..1aff5d1069aec3a0d6938a89390dbb409b1cab8f 100644 (file)
@@ -1,5 +1,6 @@
-use crate::{api::claims::Claims, blocking, DbPool, LemmyContext};
+use crate::{api::claims::Claims, DbPool, LemmyContext};
 use actix_web::web::Data;
+use lemmy_api_structs::blocking;
 use lemmy_db::{
   community::Community,
   community_view::CommunityUserBanView,
@@ -7,7 +8,7 @@ use lemmy_db::{
   user::User_,
   Crud,
 };
-use lemmy_utils::{slur_check, slurs_vec_to_str, APIError, ConnectionId, LemmyError};
+use lemmy_utils::{APIError, ConnectionId, LemmyError};
 
 pub mod claims;
 pub mod comment;
@@ -83,19 +84,6 @@ pub(in crate::api) async fn get_user_from_jwt_opt(
   }
 }
 
-pub(in crate) fn check_slurs(text: &str) -> Result<(), APIError> {
-  if let Err(slurs) = slur_check(text) {
-    Err(APIError::err(&slurs_vec_to_str(slurs)))
-  } else {
-    Ok(())
-  }
-}
-pub(in crate) fn check_slurs_opt(text: &Option<String>) -> Result<(), APIError> {
-  match text {
-    Some(t) => check_slurs(t),
-    None => Ok(()),
-  }
-}
 pub(in crate::api) async fn check_community_ban(
   user_id: i32,
   community_id: i32,
index 9e1e97d511f45d5e1ed76240b89143482a23415c..a1801d0f2adb2ba2d9749349fa7b4466ddf690b2 100644 (file)
@@ -1,15 +1,6 @@
 use crate::{
-  api::{
-    check_community_ban,
-    check_slurs,
-    check_slurs_opt,
-    get_user_from_jwt,
-    get_user_from_jwt_opt,
-    is_mod_or_admin,
-    Perform,
-  },
+  api::{check_community_ban, get_user_from_jwt, get_user_from_jwt_opt, is_mod_or_admin, Perform},
   apub::{ApubLikeableType, ApubObjectType},
-  blocking,
   fetch_iframely_and_pictrs_data,
   websocket::{
     messages::{GetPostUsersOnline, JoinCommunityRoom, JoinPostRoom, SendPost},
@@ -18,7 +9,7 @@ use crate::{
   LemmyContext,
 };
 use actix_web::web::Data;
-use lemmy_api_structs::post::*;
+use lemmy_api_structs::{blocking, post::*};
 use lemmy_db::{
   comment_view::*,
   community_view::*,
@@ -34,11 +25,10 @@ use lemmy_db::{
   SortType,
 };
 use lemmy_utils::{
-  is_valid_post_title,
-  make_apub_endpoint,
+  apub::{make_apub_endpoint, EndpointType},
+  utils::{check_slurs, check_slurs_opt, is_valid_post_title},
   APIError,
   ConnectionId,
-  EndpointType,
   LemmyError,
 };
 use std::str::FromStr;
index 8bcc4b77a393364a7c999ad20a96d00f4e556642..727078e273d57ee7a5c6035a0b2ca4374adf0196 100644 (file)
@@ -1,14 +1,6 @@
 use crate::{
-  api::{
-    check_slurs,
-    check_slurs_opt,
-    get_user_from_jwt,
-    get_user_from_jwt_opt,
-    is_admin,
-    Perform,
-  },
+  api::{get_user_from_jwt, get_user_from_jwt_opt, is_admin, Perform},
   apub::fetcher::search_by_apub_id,
-  blocking,
   version,
   websocket::{
     messages::{GetUsersOnline, SendAllMessage},
@@ -18,7 +10,7 @@ use crate::{
 };
 use actix_web::web::Data;
 use anyhow::Context;
-use lemmy_api_structs::{site::*, user::Register};
+use lemmy_api_structs::{blocking, site::*, user::Register};
 use lemmy_db::{
   category::*,
   comment_view::*,
@@ -35,7 +27,14 @@ use lemmy_db::{
   SearchType,
   SortType,
 };
-use lemmy_utils::{location_info, settings::Settings, APIError, ConnectionId, LemmyError};
+use lemmy_utils::{
+  location_info,
+  settings::Settings,
+  utils::{check_slurs, check_slurs_opt},
+  APIError,
+  ConnectionId,
+  LemmyError,
+};
 use log::{debug, info};
 use std::str::FromStr;
 
index 1a71b3aa08d08c0f80d50ef84933081f1474bda7..778a225fafadbff65bf3c453e80501a3ab5f9a10 100644 (file)
@@ -1,7 +1,6 @@
 use crate::{
-  api::{check_slurs, claims::Claims, get_user_from_jwt, get_user_from_jwt_opt, is_admin, Perform},
+  api::{claims::Claims, get_user_from_jwt, get_user_from_jwt_opt, is_admin, Perform},
   apub::ApubObjectType,
-  blocking,
   captcha_espeak_wav_base64,
   websocket::{
     messages::{CaptchaItem, CheckCaptcha, JoinUserRoom, SendAllMessage, SendUserRoomMessage},
@@ -14,7 +13,7 @@ use anyhow::Context;
 use bcrypt::verify;
 use captcha::{gen, Difficulty};
 use chrono::Duration;
-use lemmy_api_structs::user::*;
+use lemmy_api_structs::{blocking, user::*};
 use lemmy_db::{
   comment::*,
   comment_view::*,
@@ -41,19 +40,20 @@ use lemmy_db::{
   SortType,
 };
 use lemmy_utils::{
-  generate_actor_keypair,
-  generate_random_string,
-  is_valid_preferred_username,
-  is_valid_username,
+  apub::{generate_actor_keypair, make_apub_endpoint, EndpointType},
+  email::send_email,
   location_info,
-  make_apub_endpoint,
-  naive_from_unix,
-  remove_slurs,
-  send_email,
   settings::Settings,
+  utils::{
+    check_slurs,
+    generate_random_string,
+    is_valid_preferred_username,
+    is_valid_username,
+    naive_from_unix,
+    remove_slurs,
+  },
   APIError,
   ConnectionId,
-  EndpointType,
   LemmyError,
 };
 use log::error;
index 0ba8f8735710e5a5cecd9dc9d2d6a1957e9dbbf9..dc18926937c33443156cb8d4e2e8399570b9e9fe 100644 (file)
@@ -7,7 +7,7 @@ use activitystreams::{
   object::AsObject,
 };
 use lemmy_db::{community::Community, user::User_};
-use lemmy_utils::{get_apub_protocol_string, settings::Settings, LemmyError};
+use lemmy_utils::{apub::get_apub_protocol_string, settings::Settings, LemmyError};
 use serde::{export::fmt::Debug, Serialize};
 use url::{ParseError, Url};
 use uuid::Uuid;
index 8c416369f446c5df0ecf4f5e1dc26615f1866f8f..78fe6f8abbf21e7101ebbf9dd972471334528f4f 100644 (file)
@@ -17,7 +17,6 @@ use crate::{
     FromApub,
     ToApub,
   },
-  blocking,
   DbPool,
   LemmyContext,
 };
@@ -41,6 +40,7 @@ use activitystreams::{
 use actix_web::{body::Body, web, web::Path, HttpResponse};
 use anyhow::Context;
 use itertools::Itertools;
+use lemmy_api_structs::blocking;
 use lemmy_db::{
   comment::{Comment, CommentForm},
   community::Community,
@@ -49,12 +49,9 @@ use lemmy_db::{
   Crud,
 };
 use lemmy_utils::{
-  convert_datetime,
   location_info,
-  remove_slurs,
-  scrape_text_for_mentions,
+  utils::{convert_datetime, remove_slurs, scrape_text_for_mentions, MentionData},
   LemmyError,
-  MentionData,
 };
 use log::debug;
 use serde::Deserialize;
index 8d9b4dc1c8a344029b585940cbf2e3dd7f496340..89819f4531becb588f700493e35f5d39ea04354a 100644 (file)
@@ -1,5 +1,4 @@
 use crate::{
-  api::{check_slurs, check_slurs_opt},
   apub::{
     activities::generate_activity_id,
     activity_queue::send_activity,
@@ -15,7 +14,6 @@ use crate::{
     GroupExt,
     ToApub,
   },
-  blocking,
   DbPool,
   LemmyContext,
 };
@@ -40,6 +38,7 @@ use activitystreams_ext::Ext2;
 use actix_web::{body::Body, web, HttpResponse};
 use anyhow::Context;
 use itertools::Itertools;
+use lemmy_api_structs::blocking;
 use lemmy_db::{
   community::{Community, CommunityForm},
   community_view::{CommunityFollowerView, CommunityModeratorView},
@@ -47,7 +46,12 @@ use lemmy_db::{
   post::Post,
   user::User_,
 };
-use lemmy_utils::{convert_datetime, get_apub_protocol_string, location_info, LemmyError};
+use lemmy_utils::{
+  apub::get_apub_protocol_string,
+  location_info,
+  utils::{check_slurs, check_slurs_opt, convert_datetime},
+  LemmyError,
+};
 use serde::Deserialize;
 use url::Url;
 
index d45165777833c2601b93b2000dd1631c1051026e..4891a970516b246b9605d6436701bc19d3874d8d 100644 (file)
@@ -8,7 +8,6 @@ use crate::{
     PersonExt,
     APUB_JSON_CONTENT_TYPE,
   },
-  blocking,
   request::{retry, RecvError},
   LemmyContext,
 };
@@ -16,7 +15,7 @@ use activitystreams::{base::BaseExt, collection::OrderedCollection, object::Note
 use anyhow::{anyhow, Context};
 use chrono::NaiveDateTime;
 use diesel::result::Error::NotFound;
-use lemmy_api_structs::site::SearchResponse;
+use lemmy_api_structs::{blocking, site::SearchResponse};
 use lemmy_db::{
   comment::{Comment, CommentForm},
   comment_view::CommentView,
@@ -31,7 +30,7 @@ use lemmy_db::{
   Joinable,
   SearchType,
 };
-use lemmy_utils::{get_apub_protocol_string, location_info, LemmyError};
+use lemmy_utils::{apub::get_apub_protocol_string, location_info, LemmyError};
 use log::debug;
 use reqwest::Client;
 use serde::Deserialize;
index a391520476e34701f55e21c6bd5702b8a77cba54..66286ce17df8e5f2125958223810d582c9939bc7 100644 (file)
@@ -1,5 +1,4 @@
 use crate::{
-  api::comment::send_local_notifs,
   apub::{
     inbox::shared_inbox::{
       announce_if_community_is_local,
@@ -10,7 +9,6 @@ use crate::{
     FromApub,
     PageExt,
   },
-  blocking,
   websocket::{
     messages::{SendComment, SendPost},
     UserOperation,
@@ -20,14 +18,19 @@ use crate::{
 use activitystreams::{activity::Create, base::AnyBase, object::Note, prelude::*};
 use actix_web::HttpResponse;
 use anyhow::Context;
-use lemmy_api_structs::{comment::CommentResponse, post::PostResponse};
+use lemmy_api_structs::{
+  blocking,
+  comment::CommentResponse,
+  post::PostResponse,
+  send_local_notifs,
+};
 use lemmy_db::{
   comment::{Comment, CommentForm},
   comment_view::CommentView,
   post::{Post, PostForm},
   post_view::PostView,
 };
-use lemmy_utils::{location_info, scrape_text_for_mentions, LemmyError};
+use lemmy_utils::{location_info, utils::scrape_text_for_mentions, LemmyError};
 
 pub async fn receive_create(
   activity: AnyBase,
index 70bf376160e8715531dbe193f5c92f740e5d3fe7..4adc7c33c15eedb9586104f69facd3f0c0659bc4 100644 (file)
@@ -11,7 +11,6 @@ use crate::{
     GroupExt,
     PageExt,
   },
-  blocking,
   websocket::{
     messages::{SendComment, SendCommunityRoomMessage, SendPost},
     UserOperation,
@@ -22,6 +21,7 @@ use activitystreams::{activity::Delete, base::AnyBase, object::Note, prelude::*}
 use actix_web::HttpResponse;
 use anyhow::Context;
 use lemmy_api_structs::{
+  blocking,
   comment::CommentResponse,
   community::CommunityResponse,
   post::PostResponse,
index 599389b18dfe7ffaab8e25a76bc467caec911a36..9b63e82d81103bbd1d834012e6b0b9b1c504ba16 100644 (file)
@@ -9,7 +9,6 @@ use crate::{
     FromApub,
     PageExt,
   },
-  blocking,
   websocket::{
     messages::{SendComment, SendPost},
     UserOperation,
@@ -19,7 +18,7 @@ use crate::{
 use activitystreams::{activity::Dislike, base::AnyBase, object::Note, prelude::*};
 use actix_web::HttpResponse;
 use anyhow::Context;
-use lemmy_api_structs::{comment::CommentResponse, post::PostResponse};
+use lemmy_api_structs::{blocking, comment::CommentResponse, post::PostResponse};
 use lemmy_db::{
   comment::{CommentForm, CommentLike, CommentLikeForm},
   comment_view::CommentView,
index 2cb95521e7b7dca72ae6005bbf7fd42113975b48..e6f865b932e64faac15702a71f5d2da09e63ffb5 100644 (file)
@@ -9,7 +9,6 @@ use crate::{
     FromApub,
     PageExt,
   },
-  blocking,
   websocket::{
     messages::{SendComment, SendPost},
     UserOperation,
@@ -19,7 +18,7 @@ use crate::{
 use activitystreams::{activity::Like, base::AnyBase, object::Note, prelude::*};
 use actix_web::HttpResponse;
 use anyhow::Context;
-use lemmy_api_structs::{comment::CommentResponse, post::PostResponse};
+use lemmy_api_structs::{blocking, comment::CommentResponse, post::PostResponse};
 use lemmy_db::{
   comment::{CommentForm, CommentLike, CommentLikeForm},
   comment_view::CommentView,
index 846842d4e6314b6ec0fff4fc2ff87e07bb3cb3bf..011f57b9506663198e1b3053ce30b91d93bb842d 100644 (file)
@@ -12,7 +12,6 @@ use crate::{
     GroupExt,
     PageExt,
   },
-  blocking,
   websocket::{
     messages::{SendComment, SendCommunityRoomMessage, SendPost},
     UserOperation,
@@ -23,6 +22,7 @@ use activitystreams::{activity::Remove, base::AnyBase, object::Note, prelude::*}
 use actix_web::HttpResponse;
 use anyhow::{anyhow, Context};
 use lemmy_api_structs::{
+  blocking,
   comment::CommentResponse,
   community::CommunityResponse,
   post::PostResponse,
index 0b695d32eeb12792312256e511504e6a4860e1bc..bf2073860e49239eeb582fcfe1de1f36fb74af28 100644 (file)
@@ -11,7 +11,6 @@ use crate::{
     GroupExt,
     PageExt,
   },
-  blocking,
   websocket::{
     messages::{SendComment, SendCommunityRoomMessage, SendPost},
     UserOperation,
@@ -27,6 +26,7 @@ use activitystreams::{
 use actix_web::HttpResponse;
 use anyhow::{anyhow, Context};
 use lemmy_api_structs::{
+  blocking,
   comment::CommentResponse,
   community::CommunityResponse,
   post::PostResponse,
index eb1b67f1d25c25c931a22e727a3db264cd13c729..f078e67aadd3737b68853dc70aa76e756472dccc 100644 (file)
@@ -1,5 +1,4 @@
 use crate::{
-  api::comment::send_local_notifs,
   apub::{
     fetcher::{get_or_fetch_and_insert_comment, get_or_fetch_and_insert_post},
     inbox::shared_inbox::{
@@ -11,7 +10,6 @@ use crate::{
     FromApub,
     PageExt,
   },
-  blocking,
   websocket::{
     messages::{SendComment, SendPost},
     UserOperation,
@@ -21,7 +19,12 @@ use crate::{
 use activitystreams::{activity::Update, base::AnyBase, object::Note, prelude::*};
 use actix_web::HttpResponse;
 use anyhow::Context;
-use lemmy_api_structs::{comment::CommentResponse, post::PostResponse};
+use lemmy_api_structs::{
+  blocking,
+  comment::CommentResponse,
+  post::PostResponse,
+  send_local_notifs,
+};
 use lemmy_db::{
   comment::{Comment, CommentForm},
   comment_view::CommentView,
@@ -29,7 +32,7 @@ use lemmy_db::{
   post_view::PostView,
   Crud,
 };
-use lemmy_utils::{location_info, scrape_text_for_mentions, LemmyError};
+use lemmy_utils::{location_info, utils::scrape_text_for_mentions, LemmyError};
 
 pub async fn receive_update(
   activity: AnyBase,
index 0631f93913b72b2e80c6bd93469b334e484dc882..b27e6b6a90f521c15ecc384d3c12a435093d5cf9 100644 (file)
@@ -6,7 +6,6 @@ use crate::{
     insert_activity,
     ActorType,
   },
-  blocking,
   LemmyContext,
 };
 use activitystreams::{
@@ -16,6 +15,7 @@ use activitystreams::{
 };
 use actix_web::{web, HttpRequest, HttpResponse};
 use anyhow::{anyhow, Context};
+use lemmy_api_structs::blocking;
 use lemmy_db::{
   community::{Community, CommunityFollower, CommunityFollowerForm},
   user::User_,
index 7ea95833e8c20b44d070756de87e5a1936dd9f3e..ccc4d105a4f1ab3be9866e01cc8c880ba2df054d 100644 (file)
@@ -6,7 +6,6 @@ use crate::{
     insert_activity,
     FromApub,
   },
-  blocking,
   websocket::{messages::SendUserRoomMessage, UserOperation},
   LemmyContext,
 };
@@ -18,7 +17,7 @@ use activitystreams::{
 };
 use actix_web::{web, HttpRequest, HttpResponse};
 use anyhow::Context;
-use lemmy_api_structs::user::PrivateMessageResponse;
+use lemmy_api_structs::{blocking, user::PrivateMessageResponse};
 use lemmy_db::{
   community::{CommunityFollower, CommunityFollowerForm},
   naive_now,
index b3b161c7db0aee5f477cdfd9fa4f67a4028b6973..e9184c33a5bf2f8ad81630e5ae87c39e8c6b2a1d 100644 (file)
@@ -15,7 +15,6 @@ use crate::{
     page_extension::PageExtension,
     signatures::{PublicKey, PublicKeyExtension},
   },
-  blocking,
   request::{retry, RecvError},
   routes::webfinger::WebFingerResponse,
   DbPool,
@@ -33,14 +32,14 @@ use activitystreams_ext::{Ext1, Ext2};
 use actix_web::{body::Body, HttpResponse};
 use anyhow::{anyhow, Context};
 use chrono::NaiveDateTime;
+use lemmy_api_structs::blocking;
 use lemmy_db::{activity::do_insert_activity, user::User_};
 use lemmy_utils::{
-  convert_datetime,
-  get_apub_protocol_string,
+  apub::get_apub_protocol_string,
   location_info,
   settings::Settings,
+  utils::{convert_datetime, MentionData},
   LemmyError,
-  MentionData,
 };
 use log::debug;
 use reqwest::Client;
index a54b8f6a357617e78ecabd79eb5f5ac61eb1c7b9..86ac3e60056a7da52cf2e358c804b607abe12d1b 100644 (file)
@@ -1,5 +1,4 @@
 use crate::{
-  api::check_slurs,
   apub::{
     activities::{generate_activity_id, send_activity_to_community},
     check_actor_domain,
@@ -15,7 +14,6 @@ use crate::{
     PageExt,
     ToApub,
   },
-  blocking,
   DbPool,
   LemmyContext,
 };
@@ -37,13 +35,18 @@ use activitystreams::{
 use activitystreams_ext::Ext1;
 use actix_web::{body::Body, web, HttpResponse};
 use anyhow::Context;
+use lemmy_api_structs::blocking;
 use lemmy_db::{
   community::Community,
   post::{Post, PostForm},
   user::User_,
   Crud,
 };
-use lemmy_utils::{convert_datetime, location_info, remove_slurs, LemmyError};
+use lemmy_utils::{
+  location_info,
+  utils::{check_slurs, convert_datetime, remove_slurs},
+  LemmyError,
+};
 use serde::Deserialize;
 use url::Url;
 
index 5563aef361b46db79e435d6ea69be35610d403bd..6ae30a3f493528c6ad7d8e14d86ca653ad56d96f 100644 (file)
@@ -12,7 +12,6 @@ use crate::{
     FromApub,
     ToApub,
   },
-  blocking,
   DbPool,
   LemmyContext,
 };
@@ -28,12 +27,13 @@ use activitystreams::{
   prelude::*,
 };
 use anyhow::Context;
+use lemmy_api_structs::blocking;
 use lemmy_db::{
   private_message::{PrivateMessage, PrivateMessageForm},
   user::User_,
   Crud,
 };
-use lemmy_utils::{convert_datetime, location_info, LemmyError};
+use lemmy_utils::{location_info, utils::convert_datetime, LemmyError};
 use url::Url;
 
 #[async_trait::async_trait(?Send)]
index 5522a34137ab6b56dd5cdf95d32676b9ec25bcec..54daadb968e530dd3b4727b8f427f509ada7bba2 100644 (file)
@@ -1,5 +1,4 @@
 use crate::{
-  api::{check_slurs, check_slurs_opt},
   apub::{
     activities::generate_activity_id,
     activity_queue::send_activity,
@@ -12,7 +11,6 @@ use crate::{
     PersonExt,
     ToApub,
   },
-  blocking,
   DbPool,
   LemmyContext,
 };
@@ -29,11 +27,16 @@ use activitystreams::{
 use activitystreams_ext::Ext1;
 use actix_web::{body::Body, web, HttpResponse};
 use anyhow::Context;
+use lemmy_api_structs::blocking;
 use lemmy_db::{
   naive_now,
   user::{UserForm, User_},
 };
-use lemmy_utils::{convert_datetime, location_info, LemmyError};
+use lemmy_utils::{
+  location_info,
+  utils::{check_slurs, check_slurs_opt, convert_datetime},
+  LemmyError,
+};
 use serde::Deserialize;
 use url::Url;
 
index e59aa88c796495e18e763d5fb9b31849c5f50fa0..47d046696130c9052e248c128c13b5dc5befc39b 100644 (file)
@@ -13,11 +13,8 @@ use lemmy_db::{
   Crud,
 };
 use lemmy_utils::{
-  generate_actor_keypair,
-  get_apub_protocol_string,
-  make_apub_endpoint,
+  apub::{generate_actor_keypair, get_apub_protocol_string, make_apub_endpoint, EndpointType},
   settings::Settings,
-  EndpointType,
   LemmyError,
 };
 use log::info;
index d811d908a0f08b9223d78c895d57f757e30ef0c7..11b8df7cb618b1eeced54d14ed3e7d7fe5789671 100644 (file)
@@ -36,15 +36,14 @@ use crate::{
 use actix::Addr;
 use anyhow::anyhow;
 use background_jobs::QueueHandle;
-use lemmy_utils::{get_apub_protocol_string, settings::Settings, LemmyError};
+use lemmy_db::DbPool;
+use lemmy_utils::{apub::get_apub_protocol_string, settings::Settings, LemmyError};
 use log::error;
 use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
 use reqwest::Client;
 use serde::Deserialize;
 use std::process::Command;
 
-pub type DbPool = diesel::r2d2::Pool<diesel::r2d2::ConnectionManager<diesel::PgConnection>>;
-
 pub struct LemmyContext {
   pub pool: DbPool,
   pub chat_server: Addr<ChatServer>,
@@ -224,22 +223,6 @@ pub async fn is_image_content_type(client: &Client, test: &str) -> Result<(), Le
   }
 }
 
-pub async fn blocking<F, T>(pool: &DbPool, f: F) -> Result<T, LemmyError>
-where
-  F: FnOnce(&diesel::PgConnection) -> T + Send + 'static,
-  T: Send + 'static,
-{
-  let pool = pool.clone();
-  let res = actix_web::web::block(move || {
-    let conn = pool.get()?;
-    let res = (f)(&conn);
-    Ok(res) as Result<_, LemmyError>
-  })
-  .await?;
-
-  Ok(res)
-}
-
 pub fn captcha_espeak_wav_base64(captcha: &str) -> Result<String, LemmyError> {
   let mut built_text = String::new();
 
index 688e1aa1f462da56c4904999af834088d788f963..8445a68ba15ec46cfb03724012c87918c07f7419 100644 (file)
@@ -16,11 +16,11 @@ use diesel::{
   PgConnection,
 };
 use lazy_static::lazy_static;
+use lemmy_api_structs::blocking;
 use lemmy_db::get_database_url_from_env;
 use lemmy_rate_limit::{rate_limiter::RateLimiter, RateLimit};
 use lemmy_server::{
   apub::activity_queue::create_activity_queue,
-  blocking,
   code_migrations::run_advanced_migrations,
   routes::*,
   websocket::chat_server::ChatServer,
index 317c10307d2188b3aea871b1aa133aa951f65ce1..1d86414906217beff7117b12308591332947eeb1 100644 (file)
@@ -1,8 +1,9 @@
-use crate::{api::claims::Claims, blocking, LemmyContext};
+use crate::{api::claims::Claims, LemmyContext};
 use actix_web::{error::ErrorBadRequest, *};
 use anyhow::anyhow;
 use chrono::{DateTime, NaiveDateTime, Utc};
 use diesel::PgConnection;
+use lemmy_api_structs::blocking;
 use lemmy_db::{
   comment_view::{ReplyQueryBuilder, ReplyView},
   community::Community,
@@ -13,7 +14,7 @@ use lemmy_db::{
   ListingType,
   SortType,
 };
-use lemmy_utils::{markdown_to_html, settings::Settings, LemmyError};
+use lemmy_utils::{settings::Settings, utils::markdown_to_html, LemmyError};
 use rss::{CategoryBuilder, ChannelBuilder, GuidBuilder, Item, ItemBuilder};
 use serde::Deserialize;
 use std::str::FromStr;
index 1390b21ec6ab1c20b1e90b94f6b7a51c4ded28ed..2273fae544aedb25808819b159835b2ae03724a8 100644 (file)
@@ -1,8 +1,9 @@
-use crate::{blocking, version, LemmyContext};
+use crate::{version, LemmyContext};
 use actix_web::{body::Body, error::ErrorBadRequest, *};
 use anyhow::anyhow;
+use lemmy_api_structs::blocking;
 use lemmy_db::site_view::SiteView;
-use lemmy_utils::{get_apub_protocol_string, settings::Settings, LemmyError};
+use lemmy_utils::{apub::get_apub_protocol_string, settings::Settings, LemmyError};
 use serde::{Deserialize, Serialize};
 use url::Url;
 
index 22861434c6a90dc77436929769a618eebc40d1a3..458fa0f378208e5ba10db26cbdda2df42799831e 100644 (file)
@@ -1,6 +1,7 @@
-use crate::{blocking, LemmyContext};
+use crate::LemmyContext;
 use actix_web::{error::ErrorBadRequest, web::Query, *};
 use anyhow::anyhow;
+use lemmy_api_structs::blocking;
 use lemmy_db::{community::Community, user::User_};
 use lemmy_utils::{
   settings::Settings,
index 465974c00f8789dab8d038bf81bc697474f9729f..540af34faa36c704a2e316f76145c4c7d4362b42 100644 (file)
@@ -8,7 +8,7 @@ use crate::{
 use actix::prelude::*;
 use actix_web::*;
 use actix_web_actors::ws;
-use lemmy_utils::get_ip;
+use lemmy_utils::utils::get_ip;
 use log::{debug, error, info};
 use std::time::{Duration, Instant};
 
index 9a8e445b6eb99405d6abe6ce140cdd3cf46c2de3..beb499bdffb2a68b2755356b79082cb860715b39 100755 (executable)
@@ -2,4 +2,4 @@
 export DATABASE_URL=postgres://lemmy:password@localhost:5432/lemmy
 diesel migration run
 export LEMMY_DATABASE_URL=postgres://lemmy:password@localhost:5432/lemmy
-RUST_TEST_THREADS=1 cargo test --workspace
+RUST_TEST_THREADS=1 cargo test --workspace --no-fail-fast