commands:
- /root/.cargo/bin/cargo fmt -- --check
+ - name: check lemmy_api_common with minimal deps
+ image: clux/muslrust:1.56.0
+ commands:
+ - cargo check -p lemmy_api_common
+
- name: cargo clippy
image: clux/muslrust:1.56.0
commands:
name = "lemmy_api_common"
version = "0.16.3"
dependencies = [
+ "actix-rt",
"actix-web",
"chrono",
"diesel",
+ "encoding",
"lemmy_db_schema",
"lemmy_db_views",
"lemmy_db_views_actor",
"lemmy_db_views_moderator",
"lemmy_utils",
+ "percent-encoding",
+ "reqwest",
+ "reqwest-middleware",
"rosetta-i18n",
"serde",
"tracing",
"url",
+ "webpage",
]
[[package]]
name = "lemmy_utils"
version = "0.16.3"
dependencies = [
- "actix-rt",
"actix-web",
"anyhow",
"chrono",
"deser-hjson",
"diesel",
"doku",
- "encoding",
"futures",
"html2text",
"http",
"once_cell",
"openssl",
"parking_lot 0.12.0",
- "percent-encoding",
"rand 0.8.5",
"regex",
- "reqwest",
"reqwest-middleware",
"rosetta-build",
"rosetta-i18n",
"smart-default",
"strum",
"strum_macros",
- "thiserror",
"tracing",
"tracing-error",
"url",
"uuid",
- "webpage",
]
[[package]]
lemmy_apub = { version = "=0.16.3", path = "../apub" }
lemmy_apub_lib = { version = "=0.16.3", path = "../apub_lib" }
lemmy_utils = { version = "=0.16.3", path = "../utils" }
-lemmy_db_schema = { version = "=0.16.3", path = "../db_schema" }
-lemmy_db_views = { version = "=0.16.3", path = "../db_views" }
-lemmy_db_views_moderator = { version = "=0.16.3", path = "../db_views_moderator" }
-lemmy_db_views_actor = { version = "=0.16.3", path = "../db_views_actor" }
-lemmy_api_common = { version = "=0.16.3", path = "../api_common" }
+lemmy_db_schema = { version = "=0.16.3", path = "../db_schema", features = ["full"] }
+lemmy_db_views = { version = "=0.16.3", path = "../db_views", features = ["full"] }
+lemmy_db_views_moderator = { version = "=0.16.3", path = "../db_views_moderator", features = ["full"] }
+lemmy_db_views_actor = { version = "=0.16.3", path = "../db_views_actor", features = ["full"] }
+lemmy_api_common = { version = "=0.16.3", path = "../api_common", features = ["full"] }
lemmy_websocket = { version = "=0.16.3", path = "../websocket" }
diesel = "1.4.8"
bcrypt = "0.12.1"
-chrono = { version = "0.4.19", features = ["serde"] }
+chrono = { version = "0.4.19", features = ["serde"], default-features = false }
serde_json = { version = "1.0.79", features = ["preserve_order"] }
serde = { version = "1.0.136", features = ["derive"] }
actix-web = { version = "4.0.1", default-features = false }
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- check_community_ban,
- check_downvotes_enabled,
comment::{CommentResponse, CreateCommentLike},
- get_local_user_view_from_jwt,
+ utils::{blocking, check_community_ban, check_downvotes_enabled, get_local_user_view_from_jwt},
};
use lemmy_apub::{
fetcher::post_or_comment::PostOrComment,
source::comment::{CommentLike, CommentLikeForm},
traits::Likeable,
};
-use lemmy_db_views::{comment_view::CommentView, local_user_view::LocalUserView};
+use lemmy_db_views::structs::{CommentView, LocalUserView};
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::{send::send_comment_ws_message, LemmyContext, UserOperation};
use std::convert::TryInto;
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
comment::{CommentResponse, MarkCommentAsRead},
- get_local_user_view_from_jwt,
+ utils::{blocking, get_local_user_view_from_jwt},
};
use lemmy_db_schema::source::comment::Comment;
-use lemmy_db_views::comment_view::CommentView;
+use lemmy_db_views::structs::CommentView;
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext;
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
comment::{CommentResponse, SaveComment},
- get_local_user_view_from_jwt,
+ utils::{blocking, get_local_user_view_from_jwt},
};
use lemmy_db_schema::{
source::comment::{CommentSaved, CommentSavedForm},
traits::Saveable,
};
-use lemmy_db_views::comment_view::CommentView;
+use lemmy_db_views::structs::CommentView;
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext;
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- check_community_ban,
comment::{CommentReportResponse, CreateCommentReport},
- get_local_user_view_from_jwt,
+ utils::{blocking, check_community_ban, get_local_user_view_from_jwt},
};
use lemmy_apub::protocol::activities::community::report::Report;
use lemmy_apub_lib::object_id::ObjectId;
source::comment_report::{CommentReport, CommentReportForm},
traits::Reportable,
};
-use lemmy_db_views::{comment_report_view::CommentReportView, comment_view::CommentView};
+use lemmy_db_views::structs::{CommentReportView, CommentView};
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::{messages::SendModRoomMessage, LemmyContext, UserOperation};
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
comment::{ListCommentReports, ListCommentReportsResponse},
- get_local_user_view_from_jwt,
+ utils::{blocking, get_local_user_view_from_jwt},
};
use lemmy_db_views::comment_report_view::CommentReportQueryBuilder;
use lemmy_utils::{ConnectionId, LemmyError};
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
comment::{CommentReportResponse, ResolveCommentReport},
- get_local_user_view_from_jwt,
- is_mod_or_admin,
+ utils::{blocking, get_local_user_view_from_jwt, is_mod_or_admin},
};
use lemmy_db_schema::{source::comment_report::CommentReport, traits::Reportable};
-use lemmy_db_views::comment_report_view::CommentReportView;
+use lemmy_db_views::structs::CommentReportView;
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::{messages::SendModRoomMessage, LemmyContext, UserOperation};
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
community::{AddModToCommunity, AddModToCommunityResponse},
- get_local_user_view_from_jwt,
- is_mod_or_admin,
+ utils::{blocking, get_local_user_view_from_jwt, is_mod_or_admin},
};
use lemmy_apub::{
objects::{community::ApubCommunity, person::ApubPerson},
},
traits::{Crud, Joinable},
};
-use lemmy_db_views_actor::community_moderator_view::CommunityModeratorView;
+use lemmy_db_views_actor::structs::CommunityModeratorView;
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::{messages::SendCommunityRoomMessage, LemmyContext, UserOperation};
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
community::{BanFromCommunity, BanFromCommunityResponse},
- get_local_user_view_from_jwt,
- is_mod_or_admin,
- remove_user_data_in_community,
+ utils::{blocking, get_local_user_view_from_jwt, is_mod_or_admin, remove_user_data_in_community},
};
use lemmy_apub::{
activities::block::SiteOrCommunity,
},
traits::{Bannable, Crud, Followable},
};
-use lemmy_db_views_actor::person_view::PersonViewSafe;
+use lemmy_db_views_actor::structs::PersonViewSafe;
use lemmy_utils::{utils::naive_from_unix, ConnectionId, LemmyError};
use lemmy_websocket::{messages::SendCommunityRoomMessage, LemmyContext, UserOperation};
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
community::{BlockCommunity, BlockCommunityResponse},
- get_local_user_view_from_jwt,
+ utils::{blocking, get_local_user_view_from_jwt},
};
use lemmy_apub::protocol::activities::following::undo_follow::UndoFollowCommunity;
use lemmy_db_schema::{
},
traits::{Blockable, Crud, Followable},
};
-use lemmy_db_views_actor::community_view::CommunityView;
+use lemmy_db_views_actor::structs::CommunityView;
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext;
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- check_community_ban,
- check_community_deleted_or_removed,
community::{CommunityResponse, FollowCommunity},
- get_local_user_view_from_jwt,
+ utils::{
+ blocking,
+ check_community_ban,
+ check_community_deleted_or_removed,
+ get_local_user_view_from_jwt,
+ },
};
use lemmy_apub::{
objects::community::ApubCommunity,
source::community::{Community, CommunityFollower, CommunityFollowerForm},
traits::{Crud, Followable},
};
-use lemmy_db_views_actor::community_view::CommunityView;
+use lemmy_db_views_actor::structs::CommunityView;
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext;
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
community::{CommunityResponse, HideCommunity},
- get_local_user_view_from_jwt,
- is_admin,
+ utils::{blocking, get_local_user_view_from_jwt, is_admin},
};
use lemmy_apub::protocol::activities::community::update::UpdateCommunity;
use lemmy_db_schema::{
- naive_now,
source::{
community::{Community, CommunityForm},
moderator::{ModHideCommunity, ModHideCommunityForm},
},
traits::Crud,
+ utils::naive_now,
};
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::{send::send_community_ws_message, LemmyContext, UserOperationCrud};
use actix_web::web::Data;
use anyhow::Context;
use lemmy_api_common::{
- blocking,
community::{GetCommunityResponse, TransferCommunity},
- get_local_user_view_from_jwt,
+ utils::{blocking, get_local_user_view_from_jwt},
};
use lemmy_db_schema::{
source::{
},
traits::{Crud, Joinable},
};
-use lemmy_db_views_actor::{
- community_moderator_view::CommunityModeratorView,
- community_view::CommunityView,
- person_view::PersonViewSafe,
-};
+use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView, PersonViewSafe};
use lemmy_utils::{location_info, ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext;
#[cfg(test)]
mod tests {
- use lemmy_api_common::check_validator_time;
+ use lemmy_api_common::utils::check_validator_time;
use lemmy_db_schema::{
- establish_unpooled_connection,
source::{
local_user::{LocalUser, LocalUserForm},
person::{Person, PersonForm},
secret::Secret,
},
traits::Crud,
+ utils::establish_unpooled_connection,
};
use lemmy_utils::{claims::Claims, settings::structs::Settings};
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- get_local_user_view_from_jwt,
- is_admin,
person::{AddAdmin, AddAdminResponse},
+ utils::{blocking, get_local_user_view_from_jwt, is_admin},
};
use lemmy_db_schema::{
source::{
},
traits::Crud,
};
-use lemmy_db_views_actor::person_view::PersonViewSafe;
+use lemmy_db_views_actor::structs::PersonViewSafe;
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::{messages::SendAllMessage, LemmyContext, UserOperation};
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- get_local_user_view_from_jwt,
- is_admin,
person::{BanPerson, BanPersonResponse},
- remove_user_data,
+ utils::{blocking, get_local_user_view_from_jwt, is_admin, remove_user_data},
};
use lemmy_apub::{
activities::block::SiteOrCommunity,
},
traits::Crud,
};
-use lemmy_db_views_actor::person_view::PersonViewSafe;
+use lemmy_db_views_actor::structs::PersonViewSafe;
use lemmy_utils::{utils::naive_from_unix, ConnectionId, LemmyError};
use lemmy_websocket::{messages::SendAllMessage, LemmyContext, UserOperation};
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- get_local_user_view_from_jwt,
person::{BlockPerson, BlockPersonResponse},
+ utils::{blocking, get_local_user_view_from_jwt},
};
use lemmy_db_schema::{
source::person_block::{PersonBlock, PersonBlockForm},
traits::Blockable,
};
-use lemmy_db_views_actor::person_view::PersonViewSafe;
+use lemmy_db_views_actor::structs::PersonViewSafe;
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext;
use actix_web::web::Data;
use bcrypt::verify;
use lemmy_api_common::{
- blocking,
- get_local_user_view_from_jwt,
- password_length_check,
person::{ChangePassword, LoginResponse},
+ utils::{blocking, get_local_user_view_from_jwt, password_length_check},
};
use lemmy_db_schema::source::local_user::LocalUser;
use lemmy_utils::{claims::Claims, ConnectionId, LemmyError};
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- password_length_check,
person::{LoginResponse, PasswordChangeAfterReset},
+ utils::{blocking, password_length_check},
};
use lemmy_db_schema::source::{
local_user::LocalUser,
use captcha::{gen, Difficulty};
use chrono::Duration;
use lemmy_api_common::person::{CaptchaResponse, GetCaptcha, GetCaptchaResponse};
-use lemmy_db_schema::naive_now;
+use lemmy_db_schema::utils::naive_now;
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::{messages::CaptchaItem, LemmyContext};
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- get_local_user_view_from_jwt,
- is_admin,
person::{BannedPersonsResponse, GetBannedPersons},
+ utils::{blocking, get_local_user_view_from_jwt, is_admin},
};
-use lemmy_db_views_actor::person_view::PersonViewSafe;
+use lemmy_db_views_actor::structs::PersonViewSafe;
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext;
use actix_web::web::Data;
use bcrypt::verify;
use lemmy_api_common::{
- blocking,
- check_registration_application,
person::{Login, LoginResponse},
+ utils::{blocking, check_registration_application},
};
use lemmy_db_schema::source::site::Site;
-use lemmy_db_views::local_user_view::LocalUserView;
+use lemmy_db_views::structs::LocalUserView;
use lemmy_utils::{claims::Claims, ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext;
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- get_local_user_view_from_jwt,
person::{GetPersonMentions, GetPersonMentionsResponse},
+ utils::{blocking, get_local_user_view_from_jwt},
};
-use lemmy_db_schema::{from_opt_str_to_opt_enum, SortType};
+use lemmy_db_schema::utils::{from_opt_str_to_opt_enum, SortType};
use lemmy_db_views_actor::person_mention_view::PersonMentionQueryBuilder;
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext;
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- get_local_user_view_from_jwt,
person::{GetReplies, GetRepliesResponse},
+ utils::{blocking, get_local_user_view_from_jwt},
};
-use lemmy_db_schema::{from_opt_str_to_opt_enum, SortType};
+use lemmy_db_schema::utils::{from_opt_str_to_opt_enum, SortType};
use lemmy_db_views::comment_view::CommentQueryBuilder;
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext;
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- get_local_user_view_from_jwt,
person::{GetRepliesResponse, MarkAllAsRead},
+ utils::{blocking, get_local_user_view_from_jwt},
};
use lemmy_db_schema::source::{
comment::Comment,
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- get_local_user_view_from_jwt,
person::{MarkPersonMentionAsRead, PersonMentionResponse},
+ utils::{blocking, get_local_user_view_from_jwt},
};
use lemmy_db_schema::{source::person_mention::PersonMention, traits::Crud};
-use lemmy_db_views_actor::person_mention_view::PersonMentionView;
+use lemmy_db_views_actor::structs::PersonMentionView;
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext;
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- get_local_user_view_from_jwt,
person::{GetUnreadCount, GetUnreadCountResponse},
+ utils::{blocking, get_local_user_view_from_jwt},
};
-use lemmy_db_views::{comment_view::CommentView, private_message_view::PrivateMessageView};
-use lemmy_db_views_actor::person_mention_view::PersonMentionView;
+use lemmy_db_views::structs::{CommentView, PrivateMessageView};
+use lemmy_db_views_actor::structs::PersonMentionView;
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext;
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- get_local_user_view_from_jwt,
person::{GetReportCount, GetReportCountResponse},
+ utils::{blocking, get_local_user_view_from_jwt},
};
-use lemmy_db_views::{comment_report_view::CommentReportView, post_report_view::PostReportView};
+use lemmy_db_views::structs::{CommentReportView, PostReportView};
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext;
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
person::{PasswordReset, PasswordResetResponse},
- send_password_reset_email,
+ utils::{blocking, send_password_reset_email},
};
-use lemmy_db_views::local_user_view::LocalUserView;
+use lemmy_db_views::structs::LocalUserView;
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext;
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- check_image_has_local_domain,
- get_local_user_view_from_jwt,
person::{LoginResponse, SaveUserSettings},
- send_verification_email,
+ utils::{
+ blocking,
+ check_image_has_local_domain,
+ get_local_user_view_from_jwt,
+ send_verification_email,
+ },
};
use lemmy_db_schema::{
- diesel_option_overwrite,
- diesel_option_overwrite_to_url,
- naive_now,
source::{
local_user::{LocalUser, LocalUserForm},
person::{Person, PersonForm},
site::Site,
},
traits::Crud,
+ utils::{diesel_option_overwrite, diesel_option_overwrite_to_url, naive_now},
};
use lemmy_utils::{
claims::Claims,
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
person::{VerifyEmail, VerifyEmailResponse},
- send_email_verification_success,
+ utils::{blocking, send_email_verification_success},
};
use lemmy_db_schema::{
source::{
},
traits::Crud,
};
-use lemmy_db_views::local_user_view::LocalUserView;
+use lemmy_db_views::structs::LocalUserView;
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
use crate::Perform;
use actix_web::web::Data;
-use lemmy_api_common::post::{GetSiteMetadata, GetSiteMetadataResponse};
-use lemmy_utils::{request::fetch_site_metadata, ConnectionId, LemmyError};
+use lemmy_api_common::{
+ post::{GetSiteMetadata, GetSiteMetadataResponse},
+ request::fetch_site_metadata,
+};
+use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext;
#[async_trait::async_trait(?Send)]
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- check_community_ban,
- check_community_deleted_or_removed,
- check_downvotes_enabled,
- get_local_user_view_from_jwt,
- mark_post_as_read,
post::{CreatePostLike, PostResponse},
+ utils::{
+ blocking,
+ check_community_ban,
+ check_community_deleted_or_removed,
+ check_downvotes_enabled,
+ get_local_user_view_from_jwt,
+ mark_post_as_read,
+ },
};
use lemmy_apub::{
fetcher::post_or_comment::PostOrComment,
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- check_community_ban,
- check_community_deleted_or_removed,
- get_local_user_view_from_jwt,
- is_mod_or_admin,
post::{LockPost, PostResponse},
+ utils::{
+ blocking,
+ check_community_ban,
+ check_community_deleted_or_removed,
+ get_local_user_view_from_jwt,
+ is_mod_or_admin,
+ },
};
use lemmy_apub::{
objects::post::ApubPost,
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- get_local_user_view_from_jwt,
- mark_post_as_read,
- mark_post_as_unread,
post::{MarkPostAsRead, PostResponse},
+ utils::{blocking, get_local_user_view_from_jwt, mark_post_as_read, mark_post_as_unread},
};
-use lemmy_db_views::post_view::PostView;
+use lemmy_db_views::structs::PostView;
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext;
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- get_local_user_view_from_jwt,
- mark_post_as_read,
post::{PostResponse, SavePost},
+ utils::{blocking, get_local_user_view_from_jwt, mark_post_as_read},
};
use lemmy_db_schema::{
source::post::{PostSaved, PostSavedForm},
traits::Saveable,
};
-use lemmy_db_views::post_view::PostView;
+use lemmy_db_views::structs::PostView;
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext;
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- check_community_ban,
- check_community_deleted_or_removed,
- get_local_user_view_from_jwt,
- is_mod_or_admin,
post::{PostResponse, StickyPost},
+ utils::{
+ blocking,
+ check_community_ban,
+ check_community_deleted_or_removed,
+ get_local_user_view_from_jwt,
+ is_mod_or_admin,
+ },
};
use lemmy_apub::{
objects::post::ApubPost,
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- check_community_ban,
- get_local_user_view_from_jwt,
post::{CreatePostReport, PostReportResponse},
+ utils::{blocking, check_community_ban, get_local_user_view_from_jwt},
};
use lemmy_apub::protocol::activities::community::report::Report;
use lemmy_apub_lib::object_id::ObjectId;
source::post_report::{PostReport, PostReportForm},
traits::Reportable,
};
-use lemmy_db_views::{post_report_view::PostReportView, post_view::PostView};
+use lemmy_db_views::structs::{PostReportView, PostView};
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::{messages::SendModRoomMessage, LemmyContext, UserOperation};
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- get_local_user_view_from_jwt,
post::{ListPostReports, ListPostReportsResponse},
+ utils::{blocking, get_local_user_view_from_jwt},
};
use lemmy_db_views::post_report_view::PostReportQueryBuilder;
use lemmy_utils::{ConnectionId, LemmyError};
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- get_local_user_view_from_jwt,
- is_mod_or_admin,
post::{PostReportResponse, ResolvePostReport},
+ utils::{blocking, get_local_user_view_from_jwt, is_mod_or_admin},
};
use lemmy_db_schema::{source::post_report::PostReport, traits::Reportable};
-use lemmy_db_views::post_report_view::PostReportView;
+use lemmy_db_views::structs::PostReportView;
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::{messages::SendModRoomMessage, LemmyContext, UserOperation};
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- get_local_user_view_from_jwt,
person::{MarkPrivateMessageAsRead, PrivateMessageResponse},
+ utils::{blocking, get_local_user_view_from_jwt},
};
use lemmy_db_schema::{source::private_message::PrivateMessage, traits::Crud};
use lemmy_utils::{ConnectionId, LemmyError};
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- get_local_user_view_from_jwt,
- is_admin,
site::{GetSiteConfig, GetSiteConfigResponse},
+ utils::{get_local_user_view_from_jwt, is_admin},
};
use lemmy_utils::{settings::structs::Settings, ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext;
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- get_local_user_view_from_jwt,
- is_admin,
site::{GetSiteConfigResponse, SaveSiteConfig},
+ utils::{get_local_user_view_from_jwt, is_admin},
};
use lemmy_utils::{settings::structs::Settings, ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext;
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- build_federated_instances,
- get_local_user_view_from_jwt,
- is_admin,
site::{GetSiteResponse, LeaveAdmin},
+ utils::{blocking, build_federated_instances, get_local_user_view_from_jwt, is_admin},
};
use lemmy_db_schema::{
source::{
},
traits::Crud,
};
-use lemmy_db_views::site_view::SiteView;
-use lemmy_db_views_actor::person_view::PersonViewSafe;
+use lemmy_db_views::structs::SiteView;
+use lemmy_db_views_actor::structs::PersonViewSafe;
use lemmy_utils::{version, ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext;
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- check_private_instance,
- get_local_user_view_from_jwt_opt,
site::{GetModlog, GetModlogResponse},
+ utils::{blocking, check_private_instance, get_local_user_view_from_jwt_opt},
};
-use lemmy_db_views_moderator::{
- mod_add_community_view::ModAddCommunityView,
- mod_add_view::ModAddView,
- mod_ban_from_community_view::ModBanFromCommunityView,
- mod_ban_view::ModBanView,
- mod_hide_community_view::ModHideCommunityView,
- mod_lock_post_view::ModLockPostView,
- mod_remove_comment_view::ModRemoveCommentView,
- mod_remove_community_view::ModRemoveCommunityView,
- mod_remove_post_view::ModRemovePostView,
- mod_sticky_post_view::ModStickyPostView,
- mod_transfer_community_view::ModTransferCommunityView,
+use lemmy_db_views_moderator::structs::{
+ ModAddCommunityView,
+ ModAddView,
+ ModBanFromCommunityView,
+ ModBanView,
+ ModHideCommunityView,
+ ModLockPostView,
+ ModRemoveCommentView,
+ ModRemoveCommunityView,
+ ModRemovePostView,
+ ModStickyPostView,
+ ModTransferCommunityView,
};
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext;
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- get_local_user_view_from_jwt,
- is_admin,
- send_application_approved_email,
- site::*,
+ site::{ApproveRegistrationApplication, RegistrationApplicationResponse},
+ utils::{blocking, get_local_user_view_from_jwt, is_admin, send_application_approved_email},
};
use lemmy_db_schema::{
- diesel_option_overwrite,
source::{
local_user::{LocalUser, LocalUserForm},
registration_application::{RegistrationApplication, RegistrationApplicationForm},
},
traits::Crud,
+ utils::diesel_option_overwrite,
};
-use lemmy_db_views::{
- local_user_view::LocalUserView,
- registration_application_view::RegistrationApplicationView,
-};
+use lemmy_db_views::structs::{LocalUserView, RegistrationApplicationView};
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext;
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- get_local_user_view_from_jwt,
- is_admin,
site::{ListRegistrationApplications, ListRegistrationApplicationsResponse},
+ utils::{blocking, get_local_user_view_from_jwt, is_admin},
};
use lemmy_db_schema::source::site::Site;
use lemmy_db_views::registration_application_view::RegistrationApplicationQueryBuilder;
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- get_local_user_view_from_jwt,
- is_admin,
site::{GetUnreadRegistrationApplicationCount, GetUnreadRegistrationApplicationCountResponse},
+ utils::{blocking, get_local_user_view_from_jwt, is_admin},
};
use lemmy_db_schema::source::site::Site;
-use lemmy_db_views::registration_application_view::RegistrationApplicationView;
+use lemmy_db_views::structs::RegistrationApplicationView;
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext;
use actix_web::web::Data;
use diesel::NotFound;
use lemmy_api_common::{
- blocking,
- check_private_instance,
- get_local_user_view_from_jwt_opt,
site::{ResolveObject, ResolveObjectResponse},
+ utils::{blocking, check_private_instance, get_local_user_view_from_jwt_opt},
};
use lemmy_apub::fetcher::search::{search_by_apub_id, SearchableObjects};
-use lemmy_db_schema::{newtypes::PersonId, DbPool};
-use lemmy_db_views::{comment_view::CommentView, post_view::PostView};
-use lemmy_db_views_actor::{community_view::CommunityView, person_view::PersonViewSafe};
+use lemmy_db_schema::{newtypes::PersonId, utils::DbPool};
+use lemmy_db_views::structs::{CommentView, PostView};
+use lemmy_db_views_actor::structs::{CommunityView, PersonViewSafe};
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext;
use crate::Perform;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- check_private_instance,
- get_local_user_view_from_jwt_opt,
site::{Search, SearchResponse},
+ utils::{blocking, check_private_instance, get_local_user_view_from_jwt_opt},
};
use lemmy_apub::{fetcher::resolve_actor_identifier, objects::community::ApubCommunity};
use lemmy_db_schema::{
- from_opt_str_to_opt_enum,
source::community::Community,
traits::DeleteableOrRemoveable,
- ListingType,
- SearchType,
- SortType,
+ utils::{from_opt_str_to_opt_enum, ListingType, SearchType, SortType},
};
use lemmy_db_views::{comment_view::CommentQueryBuilder, post_view::PostQueryBuilder};
use lemmy_db_views_actor::{
use crate::Perform;
use actix_web::web::Data;
-use lemmy_api_common::{get_local_user_view_from_jwt, websocket::*};
+use lemmy_api_common::{utils::get_local_user_view_from_jwt, websocket::*};
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::{
messages::{JoinCommunityRoom, JoinModRoom, JoinPostRoom, JoinUserRoom},
path = "src/lib.rs"
doctest = false
+[features]
+full = ["diesel", "tracing", "rosetta-i18n", "chrono", "actix-web", "lemmy_utils",
+ "lemmy_db_views/full", "lemmy_db_views_actor/full", "lemmy_db_views_moderator/full",
+ "percent-encoding", "encoding", "reqwest-middleware", "webpage"]
+
[dependencies]
lemmy_db_views = { version = "=0.16.3", path = "../db_views" }
lemmy_db_views_moderator = { version = "=0.16.3", path = "../db_views_moderator" }
lemmy_db_views_actor = { version = "=0.16.3", path = "../db_views_actor" }
-lemmy_db_schema = { version = "=0.16.3", path = "../db_schema" }
-lemmy_utils = { version = "=0.16.3", path = "../utils" }
+lemmy_db_schema = { version = "=0.16.3", path = "../db_schema", default-features = false }
+lemmy_utils = { version = "=0.16.3", path = "../utils", optional = true }
serde = { version = "1.0.136", features = ["derive"] }
-diesel = "1.4.8"
-actix-web = { version = "4.0.1", default-features = false, features = ["cookies"] }
-chrono = { version = "0.4.19", features = ["serde"] }
-tracing = "0.1.32"
url = "2.2.2"
-rosetta-i18n = "0.1.2"
+actix-web = { version = "4.0.1", default-features = false, features = ["cookies"], optional = true }
+chrono = { version = "0.4.19", features = ["serde"], optional = true }
+diesel = { version = "1.4.8", optional = true }
+tracing = { version = "0.1.32", optional = true }
+rosetta-i18n = { version = "0.1.2", optional = true }
+percent-encoding = { version = "2.1.0", optional = true }
+encoding = { version = "0.2.33", optional = true }
+reqwest-middleware = { version = "0.1.5", optional = true }
+webpage = { version = "1.4.0", default-features = false, features = ["serde"], optional = true }
+
+[dev-dependencies]
+actix-rt = { version = "2.7.0", default-features = false }
+reqwest = { version = "0.11.10", features = ["json"] }
+use crate::sensitive::Sensitive;
use lemmy_db_schema::newtypes::{CommentId, CommentReportId, CommunityId, LocalUserId, PostId};
-use lemmy_db_views::{comment_report_view::CommentReportView, comment_view::CommentView};
-use lemmy_utils::Sensitive;
+use lemmy_db_views::structs::{CommentReportView, CommentView};
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
+use crate::sensitive::Sensitive;
use lemmy_db_schema::{
newtypes::{CommunityId, PersonId},
source::site::Site,
};
-use lemmy_db_views_actor::{
- community_moderator_view::CommunityModeratorView,
- community_view::CommunityView,
- person_view::PersonViewSafe,
-};
-use lemmy_utils::Sensitive;
+use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView, PersonViewSafe};
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
pub mod community;
pub mod person;
pub mod post;
+#[cfg(feature = "full")]
+pub mod request;
+mod sensitive;
pub mod site;
+#[cfg(feature = "full")]
+pub mod utils;
pub mod websocket;
-
-use crate::site::FederatedInstances;
-use lemmy_db_schema::{
- newtypes::{CommunityId, DbUrl, LocalUserId, PersonId, PostId},
- source::{
- comment::Comment,
- community::Community,
- email_verification::{EmailVerification, EmailVerificationForm},
- password_reset_request::PasswordResetRequest,
- person::Person,
- person_block::PersonBlock,
- post::{Post, PostRead, PostReadForm},
- registration_application::RegistrationApplication,
- secret::Secret,
- site::Site,
- },
- traits::{Crud, Readable},
- DbPool,
-};
-use lemmy_db_views::{
- comment_view::CommentQueryBuilder,
- local_user_view::{LocalUserSettingsView, LocalUserView},
-};
-use lemmy_db_views_actor::{
- community_moderator_view::CommunityModeratorView,
- community_person_ban_view::CommunityPersonBanView,
- community_view::CommunityView,
-};
-use lemmy_utils::{
- claims::Claims,
- email::{send_email, translations::Lang},
- settings::structs::Settings,
- utils::generate_random_string,
- LemmyError,
- Sensitive,
-};
-use rosetta_i18n::{Language, LanguageId};
-use tracing::warn;
-
-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 blocking_span = tracing::info_span!("blocking operation");
- let res = actix_web::web::block(move || {
- let entered = blocking_span.enter();
- let conn = pool.get()?;
- let res = (f)(&conn);
- drop(entered);
- Ok(res) as Result<T, LemmyError>
- })
- .await?;
-
- res
-}
-
-#[tracing::instrument(skip_all)]
-pub async fn is_mod_or_admin(
- pool: &DbPool,
- person_id: PersonId,
- community_id: CommunityId,
-) -> Result<(), LemmyError> {
- let is_mod_or_admin = blocking(pool, move |conn| {
- CommunityView::is_mod_or_admin(conn, person_id, community_id)
- })
- .await?;
- if !is_mod_or_admin {
- return Err(LemmyError::from_message("not_a_mod_or_admin"));
- }
- Ok(())
-}
-
-pub fn is_admin(local_user_view: &LocalUserView) -> Result<(), LemmyError> {
- if !local_user_view.person.admin {
- return Err(LemmyError::from_message("not_an_admin"));
- }
- Ok(())
-}
-
-#[tracing::instrument(skip_all)]
-pub async fn get_post(post_id: PostId, pool: &DbPool) -> Result<Post, LemmyError> {
- blocking(pool, move |conn| Post::read(conn, post_id))
- .await?
- .map_err(|e| LemmyError::from_error_message(e, "couldnt_find_post"))
-}
-
-#[tracing::instrument(skip_all)]
-pub async fn mark_post_as_read(
- person_id: PersonId,
- post_id: PostId,
- pool: &DbPool,
-) -> Result<PostRead, LemmyError> {
- let post_read_form = PostReadForm { post_id, person_id };
-
- blocking(pool, move |conn| {
- PostRead::mark_as_read(conn, &post_read_form)
- })
- .await?
- .map_err(|e| LemmyError::from_error_message(e, "couldnt_mark_post_as_read"))
-}
-
-#[tracing::instrument(skip_all)]
-pub async fn mark_post_as_unread(
- person_id: PersonId,
- post_id: PostId,
- pool: &DbPool,
-) -> Result<usize, LemmyError> {
- let post_read_form = PostReadForm { post_id, person_id };
-
- blocking(pool, move |conn| {
- PostRead::mark_as_unread(conn, &post_read_form)
- })
- .await?
- .map_err(|e| LemmyError::from_error_message(e, "couldnt_mark_post_as_read"))
-}
-
-#[tracing::instrument(skip_all)]
-pub async fn get_local_user_view_from_jwt(
- jwt: &str,
- pool: &DbPool,
- secret: &Secret,
-) -> Result<LocalUserView, LemmyError> {
- let claims = Claims::decode(jwt, &secret.jwt_secret)
- .map_err(|e| e.with_message("not_logged_in"))?
- .claims;
- let local_user_id = LocalUserId(claims.sub);
- let local_user_view =
- blocking(pool, move |conn| LocalUserView::read(conn, local_user_id)).await??;
- // Check for a site ban
- if local_user_view.person.is_banned() {
- return Err(LemmyError::from_message("site_ban"));
- }
-
- // Check for user deletion
- if local_user_view.person.deleted {
- return Err(LemmyError::from_message("deleted"));
- }
-
- check_validator_time(&local_user_view.local_user.validator_time, &claims)?;
-
- Ok(local_user_view)
-}
-
-/// Checks if user's token was issued before user's password reset.
-pub fn check_validator_time(
- validator_time: &chrono::NaiveDateTime,
- claims: &Claims,
-) -> Result<(), LemmyError> {
- let user_validation_time = validator_time.timestamp();
- if user_validation_time > claims.iat {
- Err(LemmyError::from_message("not_logged_in"))
- } else {
- Ok(())
- }
-}
-
-#[tracing::instrument(skip_all)]
-pub async fn get_local_user_view_from_jwt_opt(
- jwt: Option<&Sensitive<String>>,
- pool: &DbPool,
- secret: &Secret,
-) -> Result<Option<LocalUserView>, LemmyError> {
- match jwt {
- Some(jwt) => Ok(Some(get_local_user_view_from_jwt(jwt, pool, secret).await?)),
- None => Ok(None),
- }
-}
-
-#[tracing::instrument(skip_all)]
-pub async fn get_local_user_settings_view_from_jwt(
- jwt: &Sensitive<String>,
- pool: &DbPool,
- secret: &Secret,
-) -> Result<LocalUserSettingsView, LemmyError> {
- let claims = Claims::decode(jwt.as_ref(), &secret.jwt_secret)
- .map_err(|e| e.with_message("not_logged_in"))?
- .claims;
- let local_user_id = LocalUserId(claims.sub);
- let local_user_view = blocking(pool, move |conn| {
- LocalUserSettingsView::read(conn, local_user_id)
- })
- .await??;
- // Check for a site ban
- if local_user_view.person.is_banned() {
- return Err(LemmyError::from_message("site_ban"));
- }
-
- check_validator_time(&local_user_view.local_user.validator_time, &claims)?;
-
- Ok(local_user_view)
-}
-
-#[tracing::instrument(skip_all)]
-pub async fn get_local_user_settings_view_from_jwt_opt(
- jwt: Option<&Sensitive<String>>,
- pool: &DbPool,
- secret: &Secret,
-) -> Result<Option<LocalUserSettingsView>, LemmyError> {
- match jwt {
- Some(jwt) => Ok(Some(
- get_local_user_settings_view_from_jwt(jwt, pool, secret).await?,
- )),
- None => Ok(None),
- }
-}
-
-#[tracing::instrument(skip_all)]
-pub async fn check_community_ban(
- person_id: PersonId,
- community_id: CommunityId,
- pool: &DbPool,
-) -> Result<(), LemmyError> {
- let is_banned =
- move |conn: &'_ _| CommunityPersonBanView::get(conn, person_id, community_id).is_ok();
- if blocking(pool, is_banned).await? {
- Err(LemmyError::from_message("community_ban"))
- } else {
- Ok(())
- }
-}
-
-#[tracing::instrument(skip_all)]
-pub async fn check_community_deleted_or_removed(
- community_id: CommunityId,
- pool: &DbPool,
-) -> Result<(), LemmyError> {
- let community = blocking(pool, move |conn| Community::read(conn, community_id))
- .await?
- .map_err(|e| LemmyError::from_error_message(e, "couldnt_find_community"))?;
- if community.deleted || community.removed {
- Err(LemmyError::from_message("deleted"))
- } else {
- Ok(())
- }
-}
-
-pub fn check_post_deleted_or_removed(post: &Post) -> Result<(), LemmyError> {
- if post.deleted || post.removed {
- Err(LemmyError::from_message("deleted"))
- } else {
- Ok(())
- }
-}
-
-#[tracing::instrument(skip_all)]
-pub async fn check_person_block(
- my_id: PersonId,
- potential_blocker_id: PersonId,
- pool: &DbPool,
-) -> Result<(), LemmyError> {
- let is_blocked = move |conn: &'_ _| PersonBlock::read(conn, potential_blocker_id, my_id).is_ok();
- if blocking(pool, is_blocked).await? {
- Err(LemmyError::from_message("person_block"))
- } else {
- Ok(())
- }
-}
-
-#[tracing::instrument(skip_all)]
-pub async fn check_downvotes_enabled(score: i16, pool: &DbPool) -> Result<(), LemmyError> {
- if score == -1 {
- let site = blocking(pool, Site::read_local_site).await??;
- if !site.enable_downvotes {
- return Err(LemmyError::from_message("downvotes_disabled"));
- }
- }
- Ok(())
-}
-
-#[tracing::instrument(skip_all)]
-pub async fn check_private_instance(
- local_user_view: &Option<LocalUserView>,
- pool: &DbPool,
-) -> Result<(), LemmyError> {
- if local_user_view.is_none() {
- let site = blocking(pool, Site::read_local_site).await?;
-
- // The site might not be set up yet
- if let Ok(site) = site {
- if site.private_instance {
- return Err(LemmyError::from_message("instance_is_private"));
- }
- }
- }
- Ok(())
-}
-
-#[tracing::instrument(skip_all)]
-pub async fn build_federated_instances(
- pool: &DbPool,
- settings: &Settings,
-) -> Result<Option<FederatedInstances>, LemmyError> {
- let federation_config = &settings.federation;
- let hostname = &settings.hostname;
- let federation = federation_config.to_owned();
- if federation.enabled {
- let distinct_communities = blocking(pool, move |conn| {
- Community::distinct_federated_communities(conn)
- })
- .await??;
-
- let allowed = federation.allowed_instances;
- let blocked = federation.blocked_instances;
-
- let mut linked = distinct_communities
- .iter()
- .map(|actor_id| Ok(actor_id.host_str().unwrap_or("").to_string()))
- .collect::<Result<Vec<String>, LemmyError>>()?;
-
- if let Some(allowed) = allowed.as_ref() {
- linked.extend_from_slice(allowed);
- }
-
- if let Some(blocked) = blocked.as_ref() {
- linked.retain(|a| !blocked.contains(a) && !a.eq(hostname));
- }
-
- // Sort and remove dupes
- linked.sort_unstable();
- linked.dedup();
-
- Ok(Some(FederatedInstances {
- linked,
- allowed,
- blocked,
- }))
- } else {
- Ok(None)
- }
-}
-
-/// Checks the password length
-pub fn password_length_check(pass: &str) -> Result<(), LemmyError> {
- if !(10..=60).contains(&pass.len()) {
- Err(LemmyError::from_message("invalid_password"))
- } else {
- Ok(())
- }
-}
-
-/// Checks the site description length
-pub fn site_description_length_check(description: &str) -> Result<(), LemmyError> {
- if description.len() > 150 {
- Err(LemmyError::from_message("site_description_length_overflow"))
- } else {
- Ok(())
- }
-}
-
-/// Checks for a honeypot. If this field is filled, fail the rest of the function
-pub fn honeypot_check(honeypot: &Option<String>) -> Result<(), LemmyError> {
- if honeypot.is_some() {
- Err(LemmyError::from_message("honeypot_fail"))
- } else {
- Ok(())
- }
-}
-
-pub fn send_email_to_user(
- local_user_view: &LocalUserView,
- subject: &str,
- body: &str,
- settings: &Settings,
-) {
- if local_user_view.person.banned || !local_user_view.local_user.send_notifications_to_email {
- return;
- }
-
- if let Some(user_email) = &local_user_view.local_user.email {
- match send_email(
- subject,
- user_email,
- &local_user_view.person.name,
- body,
- settings,
- ) {
- Ok(_o) => _o,
- Err(e) => warn!("{}", e),
- };
- }
-}
-
-pub async fn send_password_reset_email(
- user: &LocalUserView,
- pool: &DbPool,
- settings: &Settings,
-) -> Result<(), LemmyError> {
- // Generate a random token
- let token = generate_random_string();
-
- // Insert the row
- let token2 = token.clone();
- let local_user_id = user.local_user.id;
- blocking(pool, move |conn| {
- PasswordResetRequest::create_token(conn, local_user_id, &token2)
- })
- .await??;
-
- let email = &user.local_user.email.to_owned().expect("email");
- let lang = get_user_lang(user);
- let subject = &lang.password_reset_subject(&user.person.name);
- let protocol_and_hostname = settings.get_protocol_and_hostname();
- let reset_link = format!("{}/password_change/{}", protocol_and_hostname, &token);
- let body = &lang.password_reset_body(&user.person.name, reset_link);
- send_email(subject, email, &user.person.name, body, settings)
-}
-
-/// Send a verification email
-pub async fn send_verification_email(
- user: &LocalUserView,
- new_email: &str,
- pool: &DbPool,
- settings: &Settings,
-) -> Result<(), LemmyError> {
- let form = EmailVerificationForm {
- local_user_id: user.local_user.id,
- email: new_email.to_string(),
- verification_token: generate_random_string(),
- };
- let verify_link = format!(
- "{}/verify_email/{}",
- settings.get_protocol_and_hostname(),
- &form.verification_token
- );
- blocking(pool, move |conn| EmailVerification::create(conn, &form)).await??;
-
- let lang = get_user_lang(user);
- let subject = lang.verify_email_subject(&settings.hostname);
- let body = lang.verify_email_body(&user.person.name, &settings.hostname, verify_link);
- send_email(&subject, new_email, &user.person.name, &body, settings)?;
-
- Ok(())
-}
-
-pub fn send_email_verification_success(
- user: &LocalUserView,
- settings: &Settings,
-) -> Result<(), LemmyError> {
- let email = &user.local_user.email.to_owned().expect("email");
- let lang = get_user_lang(user);
- let subject = &lang.email_verified_subject(&user.person.actor_id);
- let body = &lang.email_verified_body();
- send_email(subject, email, &user.person.name, body, settings)
-}
-
-pub fn get_user_lang(user: &LocalUserView) -> Lang {
- let user_lang = LanguageId::new(user.local_user.lang.clone());
- Lang::from_language_id(&user_lang).unwrap_or_else(|| {
- let en = LanguageId::new("en");
- Lang::from_language_id(&en).expect("default language")
- })
-}
-
-pub fn send_application_approved_email(
- user: &LocalUserView,
- settings: &Settings,
-) -> Result<(), LemmyError> {
- let email = &user.local_user.email.to_owned().expect("email");
- let lang = get_user_lang(user);
- let subject = lang.registration_approved_subject(&user.person.actor_id);
- let body = lang.registration_approved_body(&settings.hostname);
- send_email(&subject, email, &user.person.name, &body, settings)
-}
-
-pub async fn check_registration_application(
- site: &Site,
- local_user_view: &LocalUserView,
- pool: &DbPool,
-) -> Result<(), LemmyError> {
- if site.require_application
- && !local_user_view.local_user.accepted_application
- && !local_user_view.person.admin
- {
- // Fetch the registration, see if its denied
- let local_user_id = local_user_view.local_user.id;
- let registration = blocking(pool, move |conn| {
- RegistrationApplication::find_by_local_user_id(conn, local_user_id)
- })
- .await??;
- if let Some(deny_reason) = registration.deny_reason {
- let lang = get_user_lang(local_user_view);
- let registration_denied_message = format!("{}: {}", lang.registration_denied(), &deny_reason);
- return Err(LemmyError::from_message(®istration_denied_message));
- } else {
- return Err(LemmyError::from_message("registration_application_pending"));
- }
- }
- Ok(())
-}
-
-/// TODO this check should be removed after https://github.com/LemmyNet/lemmy/issues/868 is done.
-pub async fn check_private_instance_and_federation_enabled(
- pool: &DbPool,
- settings: &Settings,
-) -> Result<(), LemmyError> {
- let site_opt = blocking(pool, Site::read_local_site).await?;
-
- if let Ok(site) = site_opt {
- if site.private_instance && settings.federation.enabled {
- return Err(LemmyError::from_message(
- "Cannot have both private instance and federation enabled.",
- ));
- }
- }
- Ok(())
-}
-
-pub async fn remove_user_data(banned_person_id: PersonId, pool: &DbPool) -> Result<(), LemmyError> {
- // Posts
- blocking(pool, move |conn: &'_ _| {
- Post::update_removed_for_creator(conn, banned_person_id, None, true)
- })
- .await??;
-
- // Communities
- // Remove all communities where they're the top mod
- // for now, remove the communities manually
- let first_mod_communities = blocking(pool, move |conn: &'_ _| {
- CommunityModeratorView::get_community_first_mods(conn)
- })
- .await??;
-
- // Filter to only this banned users top communities
- let banned_user_first_communities: Vec<CommunityModeratorView> = first_mod_communities
- .into_iter()
- .filter(|fmc| fmc.moderator.id == banned_person_id)
- .collect();
-
- for first_mod_community in banned_user_first_communities {
- blocking(pool, move |conn: &'_ _| {
- Community::update_removed(conn, first_mod_community.community.id, true)
- })
- .await??;
- }
-
- // Comments
- blocking(pool, move |conn: &'_ _| {
- Comment::update_removed_for_creator(conn, banned_person_id, true)
- })
- .await??;
-
- Ok(())
-}
-
-pub async fn remove_user_data_in_community(
- community_id: CommunityId,
- banned_person_id: PersonId,
- pool: &DbPool,
-) -> Result<(), LemmyError> {
- // Posts
- blocking(pool, move |conn| {
- Post::update_removed_for_creator(conn, banned_person_id, Some(community_id), true)
- })
- .await??;
-
- // Comments
- // TODO Diesel doesn't allow updates with joins, so this has to be a loop
- let comments = blocking(pool, move |conn| {
- CommentQueryBuilder::create(conn)
- .creator_id(banned_person_id)
- .community_id(community_id)
- .limit(std::i64::MAX)
- .list()
- })
- .await??;
-
- for comment_view in &comments {
- let comment_id = comment_view.comment.id;
- blocking(pool, move |conn| {
- Comment::update_removed(conn, comment_id, true)
- })
- .await??;
- }
-
- Ok(())
-}
-
-pub async fn delete_user_account(person_id: PersonId, pool: &DbPool) -> Result<(), LemmyError> {
- // Comments
- let permadelete = move |conn: &'_ _| Comment::permadelete_for_creator(conn, person_id);
- blocking(pool, permadelete)
- .await?
- .map_err(|e| LemmyError::from_error_message(e, "couldnt_update_comment"))?;
-
- // Posts
- let permadelete = move |conn: &'_ _| Post::permadelete_for_creator(conn, person_id);
- blocking(pool, permadelete)
- .await?
- .map_err(|e| LemmyError::from_error_message(e, "couldnt_update_post"))?;
-
- blocking(pool, move |conn| Person::delete_account(conn, person_id)).await??;
-
- Ok(())
-}
-
-pub fn check_image_has_local_domain(url: &Option<DbUrl>) -> Result<(), LemmyError> {
- if let Some(url) = url {
- let settings = Settings::get();
- let domain = url.domain().expect("url has domain");
- if domain != settings.hostname {
- return Err(LemmyError::from_message("image_not_local"));
- }
- }
- Ok(())
-}
-use lemmy_db_views::{
- comment_view::CommentView,
- post_view::PostView,
- private_message_view::PrivateMessageView,
-};
-use lemmy_db_views_actor::{
- community_moderator_view::CommunityModeratorView,
- person_mention_view::PersonMentionView,
- person_view::PersonViewSafe,
-};
-use lemmy_utils::Sensitive;
+use crate::sensitive::Sensitive;
+use lemmy_db_views::structs::{CommentView, PostView, PrivateMessageView};
+use lemmy_db_views_actor::structs::{CommunityModeratorView, PersonMentionView, PersonViewSafe};
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
+use crate::sensitive::Sensitive;
use lemmy_db_schema::newtypes::{CommunityId, PostId, PostReportId};
-use lemmy_db_views::{
- comment_view::CommentView,
- post_report_view::PostReportView,
- post_view::PostView,
-};
-use lemmy_db_views_actor::{
- community_moderator_view::CommunityModeratorView,
- community_view::CommunityView,
-};
-use lemmy_utils::{request::SiteMetadata, Sensitive};
+use lemmy_db_views::structs::{CommentView, PostReportView, PostView};
+use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView};
use serde::{Deserialize, Serialize};
use url::Url;
pub struct GetSiteMetadataResponse {
pub metadata: SiteMetadata,
}
+
+#[derive(Deserialize, Serialize, Debug, PartialEq, Clone)]
+pub struct SiteMetadata {
+ pub title: Option<String>,
+ pub description: Option<String>,
+ pub(crate) image: Option<Url>,
+ pub html: Option<String>,
+}
--- /dev/null
+use crate::post::SiteMetadata;
+use encoding::{all::encodings, DecoderTrap};
+use lemmy_utils::{settings::structs::Settings, version::VERSION, LemmyError, REQWEST_TIMEOUT};
+use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
+use reqwest_middleware::ClientWithMiddleware;
+use serde::Deserialize;
+use tracing::info;
+use url::Url;
+use webpage::HTML;
+
+/// Fetches the post link html tags (like title, description, image, etc)
+#[tracing::instrument(skip_all)]
+pub async fn fetch_site_metadata(
+ client: &ClientWithMiddleware,
+ url: &Url,
+) -> Result<SiteMetadata, LemmyError> {
+ info!("Fetching site metadata for url: {}", url);
+ let response = client
+ .get(url.as_str())
+ .timeout(REQWEST_TIMEOUT)
+ .send()
+ .await?;
+
+ // Can't use .text() here, because it only checks the content header, not the actual bytes
+ // https://github.com/LemmyNet/lemmy/issues/1964
+ let html_bytes = response.bytes().await.map_err(LemmyError::from)?.to_vec();
+
+ let tags = html_to_site_metadata(&html_bytes)?;
+
+ Ok(tags)
+}
+
+fn html_to_site_metadata(html_bytes: &[u8]) -> Result<SiteMetadata, LemmyError> {
+ let html = String::from_utf8_lossy(html_bytes);
+
+ // Make sure the first line is doctype html
+ let first_line = html
+ .trim_start()
+ .lines()
+ .into_iter()
+ .next()
+ .ok_or_else(|| LemmyError::from_message("No lines in html"))?
+ .to_lowercase();
+
+ if !first_line.starts_with("<!doctype html>") {
+ return Err(LemmyError::from_message(
+ "Site metadata page fetch is not DOCTYPE html",
+ ));
+ }
+
+ let mut page = HTML::from_string(html.to_string(), None)?;
+
+ // If the web page specifies that it isn't actually UTF-8, re-decode the received bytes with the
+ // proper encoding. If the specified encoding cannot be found, fall back to the original UTF-8
+ // version.
+ if let Some(charset) = page.meta.get("charset") {
+ if charset.to_lowercase() != "utf-8" {
+ if let Some(encoding_ref) = encodings().iter().find(|e| e.name() == charset) {
+ if let Ok(html_with_encoding) = encoding_ref.decode(html_bytes, DecoderTrap::Replace) {
+ page = HTML::from_string(html_with_encoding, None)?;
+ }
+ }
+ }
+ }
+
+ let page_title = page.title;
+ let page_description = page.description;
+
+ let og_description = page
+ .opengraph
+ .properties
+ .get("description")
+ .map(|t| t.to_string());
+ let og_title = page
+ .opengraph
+ .properties
+ .get("title")
+ .map(|t| t.to_string());
+ let og_image = page
+ .opengraph
+ .images
+ .get(0)
+ .and_then(|ogo| Url::parse(&ogo.url).ok());
+
+ let title = og_title.or(page_title);
+ let description = og_description.or(page_description);
+ let image = og_image;
+
+ Ok(SiteMetadata {
+ title,
+ description,
+ image,
+ html: None,
+ })
+}
+
+#[derive(Deserialize, Debug, Clone)]
+pub(crate) struct PictrsResponse {
+ files: Vec<PictrsFile>,
+ msg: String,
+}
+
+#[derive(Deserialize, Debug, Clone)]
+pub(crate) struct PictrsFile {
+ file: String,
+ #[allow(dead_code)]
+ delete_token: String,
+}
+
+#[tracing::instrument(skip_all)]
+pub(crate) async fn fetch_pictrs(
+ client: &ClientWithMiddleware,
+ settings: &Settings,
+ image_url: &Url,
+) -> Result<PictrsResponse, LemmyError> {
+ if let Some(pictrs_url) = settings.pictrs_url.to_owned() {
+ is_image_content_type(client, image_url).await?;
+
+ let fetch_url = format!(
+ "{}/image/download?url={}",
+ pictrs_url,
+ utf8_percent_encode(image_url.as_str(), NON_ALPHANUMERIC) // TODO this might not be needed
+ );
+
+ let response = client
+ .get(&fetch_url)
+ .timeout(REQWEST_TIMEOUT)
+ .send()
+ .await?;
+
+ let response: PictrsResponse = response.json().await.map_err(LemmyError::from)?;
+
+ if response.msg == "ok" {
+ Ok(response)
+ } else {
+ Err(LemmyError::from_message(&response.msg))
+ }
+ } else {
+ Err(LemmyError::from_message("pictrs_url not set up in config"))
+ }
+}
+
+/// Both are options, since the URL might be either an html page, or an image
+/// Returns the SiteMetadata, and a Pictrs URL, if there is a picture associated
+#[tracing::instrument(skip_all)]
+pub async fn fetch_site_data(
+ client: &ClientWithMiddleware,
+ settings: &Settings,
+ url: Option<&Url>,
+) -> (Option<SiteMetadata>, Option<Url>) {
+ match &url {
+ Some(url) => {
+ // Fetch metadata
+ // Ignore errors, since it may be an image, or not have the data.
+ // Warning, this may ignore SSL errors
+ let metadata_option = fetch_site_metadata(client, url).await.ok();
+
+ // Fetch pictrs thumbnail
+ let pictrs_hash = match &metadata_option {
+ Some(metadata_res) => match &metadata_res.image {
+ // Metadata, with image
+ // Try to generate a small thumbnail if there's a full sized one from post-links
+ Some(metadata_image) => fetch_pictrs(client, settings, metadata_image)
+ .await
+ .map(|r| r.files[0].file.to_owned()),
+ // Metadata, but no image
+ None => fetch_pictrs(client, settings, url)
+ .await
+ .map(|r| r.files[0].file.to_owned()),
+ },
+ // No metadata, try to fetch the URL as an image
+ None => fetch_pictrs(client, settings, url)
+ .await
+ .map(|r| r.files[0].file.to_owned()),
+ };
+
+ // The full urls are necessary for federation
+ let pictrs_thumbnail = pictrs_hash
+ .map(|p| {
+ Url::parse(&format!(
+ "{}/pictrs/image/{}",
+ settings.get_protocol_and_hostname(),
+ p
+ ))
+ .ok()
+ })
+ .ok()
+ .flatten();
+
+ (metadata_option, pictrs_thumbnail)
+ }
+ None => (None, None),
+ }
+}
+
+#[tracing::instrument(skip_all)]
+async fn is_image_content_type(client: &ClientWithMiddleware, url: &Url) -> Result<(), LemmyError> {
+ let response = client
+ .get(url.as_str())
+ .timeout(REQWEST_TIMEOUT)
+ .send()
+ .await?;
+ if response
+ .headers()
+ .get("Content-Type")
+ .ok_or_else(|| LemmyError::from_message("No Content-Type header"))?
+ .to_str()?
+ .starts_with("image/")
+ {
+ Ok(())
+ } else {
+ Err(LemmyError::from_message("Not an image type."))
+ }
+}
+
+pub fn build_user_agent(settings: &Settings) -> String {
+ format!(
+ "Lemmy/{}; +{}",
+ VERSION,
+ settings.get_protocol_and_hostname()
+ )
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::request::{build_user_agent, fetch_site_metadata, SiteMetadata};
+ use lemmy_utils::settings::structs::Settings;
+ use url::Url;
+
+ // These helped with testing
+ #[actix_rt::test]
+ async fn test_site_metadata() {
+ let settings = Settings::init().unwrap();
+ let client = reqwest::Client::builder()
+ .user_agent(build_user_agent(&settings))
+ .build()
+ .unwrap()
+ .into();
+ let sample_url = Url::parse("https://gitlab.com/IzzyOnDroid/repo/-/wikis/FAQ").unwrap();
+ let sample_res = fetch_site_metadata(&client, &sample_url).await.unwrap();
+ assert_eq!(
+ SiteMetadata {
+ title: Some("FAQ · Wiki · IzzyOnDroid / repo · GitLab".to_string()),
+ description: Some(
+ "The F-Droid compatible repo at https://apt.izzysoft.de/fdroid/".to_string()
+ ),
+ image: Some(
+ Url::parse("https://gitlab.com/uploads/-/system/project/avatar/4877469/iod_logo.png")
+ .unwrap()
+ ),
+ html: None,
+ },
+ sample_res
+ );
+
+ let youtube_url = Url::parse("https://www.youtube.com/watch?v=IquO_TcMZIQ").unwrap();
+ let youtube_res = fetch_site_metadata(&client, &youtube_url).await.unwrap();
+ assert_eq!(
+ SiteMetadata {
+ title: Some("A Hard Look at Rent and Rent Seeking with Michael Hudson & Pepe Escobar".to_string()),
+ description: Some("An interactive discussion on wealth inequality and the “Great Game” on the control of natural resources.In this webinar organized jointly by the Henry George...".to_string()),
+ image: Some(Url::parse("https://i.ytimg.com/vi/IquO_TcMZIQ/maxresdefault.jpg").unwrap()),
+ html: None,
+ }, youtube_res);
+ }
+
+ // #[test]
+ // fn test_pictshare() {
+ // let res = fetch_pictshare("https://upload.wikimedia.org/wikipedia/en/2/27/The_Mandalorian_logo.jpg");
+ // assert!(res.is_ok());
+ // let res_other = fetch_pictshare("https://upload.wikimedia.org/wikipedia/en/2/27/The_Mandalorian_logo.jpgaoeu");
+ // assert!(res_other.is_err());
+ // }
+}
+use serde::{Deserialize, Serialize};
use std::{
borrow::Borrow,
ops::{Deref, DerefMut},
};
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, serde::Deserialize, serde::Serialize)]
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
#[serde(transparent)]
pub struct Sensitive<T>(T);
Sensitive(item)
}
- pub fn into_inner(this: Self) -> T {
- this.0
+ pub fn into_inner(self) -> T {
+ self.0
}
}
+use crate::sensitive::Sensitive;
use lemmy_db_schema::newtypes::{CommunityId, PersonId};
-use lemmy_db_views::{
- comment_view::CommentView,
- local_user_view::LocalUserSettingsView,
- post_view::PostView,
- registration_application_view::RegistrationApplicationView,
- site_view::SiteView,
+use lemmy_db_views::structs::{
+ CommentView,
+ LocalUserSettingsView,
+ PostView,
+ RegistrationApplicationView,
+ SiteView,
};
-use lemmy_db_views_actor::{
- community_block_view::CommunityBlockView,
- community_follower_view::CommunityFollowerView,
- community_moderator_view::CommunityModeratorView,
- community_view::CommunityView,
- person_block_view::PersonBlockView,
- person_view::PersonViewSafe,
+use lemmy_db_views_actor::structs::{
+ CommunityBlockView,
+ CommunityFollowerView,
+ CommunityModeratorView,
+ CommunityView,
+ PersonBlockView,
+ PersonViewSafe,
};
-use lemmy_db_views_moderator::{
- mod_add_community_view::ModAddCommunityView,
- mod_add_view::ModAddView,
- mod_ban_from_community_view::ModBanFromCommunityView,
- mod_ban_view::ModBanView,
- mod_hide_community_view::ModHideCommunityView,
- mod_lock_post_view::ModLockPostView,
- mod_remove_comment_view::ModRemoveCommentView,
- mod_remove_community_view::ModRemoveCommunityView,
- mod_remove_post_view::ModRemovePostView,
- mod_sticky_post_view::ModStickyPostView,
- mod_transfer_community_view::ModTransferCommunityView,
+use lemmy_db_views_moderator::structs::{
+ ModAddCommunityView,
+ ModAddView,
+ ModBanFromCommunityView,
+ ModBanView,
+ ModHideCommunityView,
+ ModLockPostView,
+ ModRemoveCommentView,
+ ModRemoveCommunityView,
+ ModRemovePostView,
+ ModStickyPostView,
+ ModTransferCommunityView,
};
-use lemmy_utils::Sensitive;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
--- /dev/null
+use crate::{sensitive::Sensitive, site::FederatedInstances};
+use lemmy_db_schema::{
+ newtypes::{CommunityId, DbUrl, LocalUserId, PersonId, PostId},
+ source::{
+ comment::Comment,
+ community::Community,
+ email_verification::{EmailVerification, EmailVerificationForm},
+ password_reset_request::PasswordResetRequest,
+ person::Person,
+ person_block::PersonBlock,
+ post::{Post, PostRead, PostReadForm},
+ registration_application::RegistrationApplication,
+ secret::Secret,
+ site::Site,
+ },
+ traits::{Crud, Readable},
+ utils::DbPool,
+};
+use lemmy_db_views::{
+ comment_view::CommentQueryBuilder,
+ structs::{LocalUserSettingsView, LocalUserView},
+};
+use lemmy_db_views_actor::structs::{
+ CommunityModeratorView,
+ CommunityPersonBanView,
+ CommunityView,
+};
+use lemmy_utils::{
+ claims::Claims,
+ email::{send_email, translations::Lang},
+ settings::structs::Settings,
+ utils::generate_random_string,
+ LemmyError,
+};
+use rosetta_i18n::{Language, LanguageId};
+use tracing::warn;
+
+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 blocking_span = tracing::info_span!("blocking operation");
+ let res = actix_web::web::block(move || {
+ let entered = blocking_span.enter();
+ let conn = pool.get()?;
+ let res = (f)(&conn);
+ drop(entered);
+ Ok(res) as Result<T, LemmyError>
+ })
+ .await?;
+
+ res
+}
+
+#[tracing::instrument(skip_all)]
+pub async fn is_mod_or_admin(
+ pool: &DbPool,
+ person_id: PersonId,
+ community_id: CommunityId,
+) -> Result<(), LemmyError> {
+ let is_mod_or_admin = blocking(pool, move |conn| {
+ CommunityView::is_mod_or_admin(conn, person_id, community_id)
+ })
+ .await?;
+ if !is_mod_or_admin {
+ return Err(LemmyError::from_message("not_a_mod_or_admin"));
+ }
+ Ok(())
+}
+
+pub fn is_admin(local_user_view: &LocalUserView) -> Result<(), LemmyError> {
+ if !local_user_view.person.admin {
+ return Err(LemmyError::from_message("not_an_admin"));
+ }
+ Ok(())
+}
+
+#[tracing::instrument(skip_all)]
+pub async fn get_post(post_id: PostId, pool: &DbPool) -> Result<Post, LemmyError> {
+ blocking(pool, move |conn| Post::read(conn, post_id))
+ .await?
+ .map_err(|e| LemmyError::from_error_message(e, "couldnt_find_post"))
+}
+
+#[tracing::instrument(skip_all)]
+pub async fn mark_post_as_read(
+ person_id: PersonId,
+ post_id: PostId,
+ pool: &DbPool,
+) -> Result<PostRead, LemmyError> {
+ let post_read_form = PostReadForm { post_id, person_id };
+
+ blocking(pool, move |conn| {
+ PostRead::mark_as_read(conn, &post_read_form)
+ })
+ .await?
+ .map_err(|e| LemmyError::from_error_message(e, "couldnt_mark_post_as_read"))
+}
+
+#[tracing::instrument(skip_all)]
+pub async fn mark_post_as_unread(
+ person_id: PersonId,
+ post_id: PostId,
+ pool: &DbPool,
+) -> Result<usize, LemmyError> {
+ let post_read_form = PostReadForm { post_id, person_id };
+
+ blocking(pool, move |conn| {
+ PostRead::mark_as_unread(conn, &post_read_form)
+ })
+ .await?
+ .map_err(|e| LemmyError::from_error_message(e, "couldnt_mark_post_as_read"))
+}
+
+#[tracing::instrument(skip_all)]
+pub async fn get_local_user_view_from_jwt(
+ jwt: &str,
+ pool: &DbPool,
+ secret: &Secret,
+) -> Result<LocalUserView, LemmyError> {
+ let claims = Claims::decode(jwt, &secret.jwt_secret)
+ .map_err(|e| e.with_message("not_logged_in"))?
+ .claims;
+ let local_user_id = LocalUserId(claims.sub);
+ let local_user_view =
+ blocking(pool, move |conn| LocalUserView::read(conn, local_user_id)).await??;
+ // Check for a site ban
+ if local_user_view.person.is_banned() {
+ return Err(LemmyError::from_message("site_ban"));
+ }
+
+ // Check for user deletion
+ if local_user_view.person.deleted {
+ return Err(LemmyError::from_message("deleted"));
+ }
+
+ check_validator_time(&local_user_view.local_user.validator_time, &claims)?;
+
+ Ok(local_user_view)
+}
+
+/// Checks if user's token was issued before user's password reset.
+pub fn check_validator_time(
+ validator_time: &chrono::NaiveDateTime,
+ claims: &Claims,
+) -> Result<(), LemmyError> {
+ let user_validation_time = validator_time.timestamp();
+ if user_validation_time > claims.iat {
+ Err(LemmyError::from_message("not_logged_in"))
+ } else {
+ Ok(())
+ }
+}
+
+#[tracing::instrument(skip_all)]
+pub async fn get_local_user_view_from_jwt_opt(
+ jwt: Option<&Sensitive<String>>,
+ pool: &DbPool,
+ secret: &Secret,
+) -> Result<Option<LocalUserView>, LemmyError> {
+ match jwt {
+ Some(jwt) => Ok(Some(get_local_user_view_from_jwt(jwt, pool, secret).await?)),
+ None => Ok(None),
+ }
+}
+
+#[tracing::instrument(skip_all)]
+pub async fn get_local_user_settings_view_from_jwt(
+ jwt: &Sensitive<String>,
+ pool: &DbPool,
+ secret: &Secret,
+) -> Result<LocalUserSettingsView, LemmyError> {
+ let claims = Claims::decode(jwt.as_ref(), &secret.jwt_secret)
+ .map_err(|e| e.with_message("not_logged_in"))?
+ .claims;
+ let local_user_id = LocalUserId(claims.sub);
+ let local_user_view = blocking(pool, move |conn| {
+ LocalUserSettingsView::read(conn, local_user_id)
+ })
+ .await??;
+ // Check for a site ban
+ if local_user_view.person.is_banned() {
+ return Err(LemmyError::from_message("site_ban"));
+ }
+
+ check_validator_time(&local_user_view.local_user.validator_time, &claims)?;
+
+ Ok(local_user_view)
+}
+
+#[tracing::instrument(skip_all)]
+pub async fn get_local_user_settings_view_from_jwt_opt(
+ jwt: Option<&Sensitive<String>>,
+ pool: &DbPool,
+ secret: &Secret,
+) -> Result<Option<LocalUserSettingsView>, LemmyError> {
+ match jwt {
+ Some(jwt) => Ok(Some(
+ get_local_user_settings_view_from_jwt(jwt, pool, secret).await?,
+ )),
+ None => Ok(None),
+ }
+}
+
+#[tracing::instrument(skip_all)]
+pub async fn check_community_ban(
+ person_id: PersonId,
+ community_id: CommunityId,
+ pool: &DbPool,
+) -> Result<(), LemmyError> {
+ let is_banned =
+ move |conn: &'_ _| CommunityPersonBanView::get(conn, person_id, community_id).is_ok();
+ if blocking(pool, is_banned).await? {
+ Err(LemmyError::from_message("community_ban"))
+ } else {
+ Ok(())
+ }
+}
+
+#[tracing::instrument(skip_all)]
+pub async fn check_community_deleted_or_removed(
+ community_id: CommunityId,
+ pool: &DbPool,
+) -> Result<(), LemmyError> {
+ let community = blocking(pool, move |conn| Community::read(conn, community_id))
+ .await?
+ .map_err(|e| LemmyError::from_error_message(e, "couldnt_find_community"))?;
+ if community.deleted || community.removed {
+ Err(LemmyError::from_message("deleted"))
+ } else {
+ Ok(())
+ }
+}
+
+pub fn check_post_deleted_or_removed(post: &Post) -> Result<(), LemmyError> {
+ if post.deleted || post.removed {
+ Err(LemmyError::from_message("deleted"))
+ } else {
+ Ok(())
+ }
+}
+
+#[tracing::instrument(skip_all)]
+pub async fn check_person_block(
+ my_id: PersonId,
+ potential_blocker_id: PersonId,
+ pool: &DbPool,
+) -> Result<(), LemmyError> {
+ let is_blocked = move |conn: &'_ _| PersonBlock::read(conn, potential_blocker_id, my_id).is_ok();
+ if blocking(pool, is_blocked).await? {
+ Err(LemmyError::from_message("person_block"))
+ } else {
+ Ok(())
+ }
+}
+
+#[tracing::instrument(skip_all)]
+pub async fn check_downvotes_enabled(score: i16, pool: &DbPool) -> Result<(), LemmyError> {
+ if score == -1 {
+ let site = blocking(pool, Site::read_local_site).await??;
+ if !site.enable_downvotes {
+ return Err(LemmyError::from_message("downvotes_disabled"));
+ }
+ }
+ Ok(())
+}
+
+#[tracing::instrument(skip_all)]
+pub async fn check_private_instance(
+ local_user_view: &Option<LocalUserView>,
+ pool: &DbPool,
+) -> Result<(), LemmyError> {
+ if local_user_view.is_none() {
+ let site = blocking(pool, Site::read_local_site).await?;
+
+ // The site might not be set up yet
+ if let Ok(site) = site {
+ if site.private_instance {
+ return Err(LemmyError::from_message("instance_is_private"));
+ }
+ }
+ }
+ Ok(())
+}
+
+#[tracing::instrument(skip_all)]
+pub async fn build_federated_instances(
+ pool: &DbPool,
+ settings: &Settings,
+) -> Result<Option<FederatedInstances>, LemmyError> {
+ let federation_config = &settings.federation;
+ let hostname = &settings.hostname;
+ let federation = federation_config.to_owned();
+ if federation.enabled {
+ let distinct_communities = blocking(pool, move |conn| {
+ Community::distinct_federated_communities(conn)
+ })
+ .await??;
+
+ let allowed = federation.allowed_instances;
+ let blocked = federation.blocked_instances;
+
+ let mut linked = distinct_communities
+ .iter()
+ .map(|actor_id| Ok(actor_id.host_str().unwrap_or("").to_string()))
+ .collect::<Result<Vec<String>, LemmyError>>()?;
+
+ if let Some(allowed) = allowed.as_ref() {
+ linked.extend_from_slice(allowed);
+ }
+
+ if let Some(blocked) = blocked.as_ref() {
+ linked.retain(|a| !blocked.contains(a) && !a.eq(hostname));
+ }
+
+ // Sort and remove dupes
+ linked.sort_unstable();
+ linked.dedup();
+
+ Ok(Some(FederatedInstances {
+ linked,
+ allowed,
+ blocked,
+ }))
+ } else {
+ Ok(None)
+ }
+}
+
+/// Checks the password length
+pub fn password_length_check(pass: &str) -> Result<(), LemmyError> {
+ if !(10..=60).contains(&pass.len()) {
+ Err(LemmyError::from_message("invalid_password"))
+ } else {
+ Ok(())
+ }
+}
+
+/// Checks the site description length
+pub fn site_description_length_check(description: &str) -> Result<(), LemmyError> {
+ if description.len() > 150 {
+ Err(LemmyError::from_message("site_description_length_overflow"))
+ } else {
+ Ok(())
+ }
+}
+
+/// Checks for a honeypot. If this field is filled, fail the rest of the function
+pub fn honeypot_check(honeypot: &Option<String>) -> Result<(), LemmyError> {
+ if honeypot.is_some() {
+ Err(LemmyError::from_message("honeypot_fail"))
+ } else {
+ Ok(())
+ }
+}
+
+pub fn send_email_to_user(
+ local_user_view: &LocalUserView,
+ subject: &str,
+ body: &str,
+ settings: &Settings,
+) {
+ if local_user_view.person.banned || !local_user_view.local_user.send_notifications_to_email {
+ return;
+ }
+
+ if let Some(user_email) = &local_user_view.local_user.email {
+ match send_email(
+ subject,
+ user_email,
+ &local_user_view.person.name,
+ body,
+ settings,
+ ) {
+ Ok(_o) => _o,
+ Err(e) => warn!("{}", e),
+ };
+ }
+}
+
+pub async fn send_password_reset_email(
+ user: &LocalUserView,
+ pool: &DbPool,
+ settings: &Settings,
+) -> Result<(), LemmyError> {
+ // Generate a random token
+ let token = generate_random_string();
+
+ // Insert the row
+ let token2 = token.clone();
+ let local_user_id = user.local_user.id;
+ blocking(pool, move |conn| {
+ PasswordResetRequest::create_token(conn, local_user_id, &token2)
+ })
+ .await??;
+
+ let email = &user.local_user.email.to_owned().expect("email");
+ let lang = get_user_lang(user);
+ let subject = &lang.password_reset_subject(&user.person.name);
+ let protocol_and_hostname = settings.get_protocol_and_hostname();
+ let reset_link = format!("{}/password_change/{}", protocol_and_hostname, &token);
+ let body = &lang.password_reset_body(&user.person.name, reset_link);
+ send_email(subject, email, &user.person.name, body, settings)
+}
+
+/// Send a verification email
+pub async fn send_verification_email(
+ user: &LocalUserView,
+ new_email: &str,
+ pool: &DbPool,
+ settings: &Settings,
+) -> Result<(), LemmyError> {
+ let form = EmailVerificationForm {
+ local_user_id: user.local_user.id,
+ email: new_email.to_string(),
+ verification_token: generate_random_string(),
+ };
+ let verify_link = format!(
+ "{}/verify_email/{}",
+ settings.get_protocol_and_hostname(),
+ &form.verification_token
+ );
+ blocking(pool, move |conn| EmailVerification::create(conn, &form)).await??;
+
+ let lang = get_user_lang(user);
+ let subject = lang.verify_email_subject(&settings.hostname);
+ let body = lang.verify_email_body(&user.person.name, &settings.hostname, verify_link);
+ send_email(&subject, new_email, &user.person.name, &body, settings)?;
+
+ Ok(())
+}
+
+pub fn send_email_verification_success(
+ user: &LocalUserView,
+ settings: &Settings,
+) -> Result<(), LemmyError> {
+ let email = &user.local_user.email.to_owned().expect("email");
+ let lang = get_user_lang(user);
+ let subject = &lang.email_verified_subject(&user.person.actor_id);
+ let body = &lang.email_verified_body();
+ send_email(subject, email, &user.person.name, body, settings)
+}
+
+pub fn get_user_lang(user: &LocalUserView) -> Lang {
+ let user_lang = LanguageId::new(user.local_user.lang.clone());
+ Lang::from_language_id(&user_lang).unwrap_or_else(|| {
+ let en = LanguageId::new("en");
+ Lang::from_language_id(&en).expect("default language")
+ })
+}
+
+pub fn send_application_approved_email(
+ user: &LocalUserView,
+ settings: &Settings,
+) -> Result<(), LemmyError> {
+ let email = &user.local_user.email.to_owned().expect("email");
+ let lang = get_user_lang(user);
+ let subject = lang.registration_approved_subject(&user.person.actor_id);
+ let body = lang.registration_approved_body(&settings.hostname);
+ send_email(&subject, email, &user.person.name, &body, settings)
+}
+
+pub async fn check_registration_application(
+ site: &Site,
+ local_user_view: &LocalUserView,
+ pool: &DbPool,
+) -> Result<(), LemmyError> {
+ if site.require_application
+ && !local_user_view.local_user.accepted_application
+ && !local_user_view.person.admin
+ {
+ // Fetch the registration, see if its denied
+ let local_user_id = local_user_view.local_user.id;
+ let registration = blocking(pool, move |conn| {
+ RegistrationApplication::find_by_local_user_id(conn, local_user_id)
+ })
+ .await??;
+ if let Some(deny_reason) = registration.deny_reason {
+ let lang = get_user_lang(local_user_view);
+ let registration_denied_message = format!("{}: {}", lang.registration_denied(), &deny_reason);
+ return Err(LemmyError::from_message(®istration_denied_message));
+ } else {
+ return Err(LemmyError::from_message("registration_application_pending"));
+ }
+ }
+ Ok(())
+}
+
+/// TODO this check should be removed after https://github.com/LemmyNet/lemmy/issues/868 is done.
+pub async fn check_private_instance_and_federation_enabled(
+ pool: &DbPool,
+ settings: &Settings,
+) -> Result<(), LemmyError> {
+ let site_opt = blocking(pool, Site::read_local_site).await?;
+
+ if let Ok(site) = site_opt {
+ if site.private_instance && settings.federation.enabled {
+ return Err(LemmyError::from_message(
+ "Cannot have both private instance and federation enabled.",
+ ));
+ }
+ }
+ Ok(())
+}
+
+pub async fn remove_user_data(banned_person_id: PersonId, pool: &DbPool) -> Result<(), LemmyError> {
+ // Posts
+ blocking(pool, move |conn: &'_ _| {
+ Post::update_removed_for_creator(conn, banned_person_id, None, true)
+ })
+ .await??;
+
+ // Communities
+ // Remove all communities where they're the top mod
+ // for now, remove the communities manually
+ let first_mod_communities = blocking(pool, move |conn: &'_ _| {
+ CommunityModeratorView::get_community_first_mods(conn)
+ })
+ .await??;
+
+ // Filter to only this banned users top communities
+ let banned_user_first_communities: Vec<CommunityModeratorView> = first_mod_communities
+ .into_iter()
+ .filter(|fmc| fmc.moderator.id == banned_person_id)
+ .collect();
+
+ for first_mod_community in banned_user_first_communities {
+ blocking(pool, move |conn: &'_ _| {
+ Community::update_removed(conn, first_mod_community.community.id, true)
+ })
+ .await??;
+ }
+
+ // Comments
+ blocking(pool, move |conn: &'_ _| {
+ Comment::update_removed_for_creator(conn, banned_person_id, true)
+ })
+ .await??;
+
+ Ok(())
+}
+
+pub async fn remove_user_data_in_community(
+ community_id: CommunityId,
+ banned_person_id: PersonId,
+ pool: &DbPool,
+) -> Result<(), LemmyError> {
+ // Posts
+ blocking(pool, move |conn| {
+ Post::update_removed_for_creator(conn, banned_person_id, Some(community_id), true)
+ })
+ .await??;
+
+ // Comments
+ // TODO Diesel doesn't allow updates with joins, so this has to be a loop
+ let comments = blocking(pool, move |conn| {
+ CommentQueryBuilder::create(conn)
+ .creator_id(banned_person_id)
+ .community_id(community_id)
+ .limit(std::i64::MAX)
+ .list()
+ })
+ .await??;
+
+ for comment_view in &comments {
+ let comment_id = comment_view.comment.id;
+ blocking(pool, move |conn| {
+ Comment::update_removed(conn, comment_id, true)
+ })
+ .await??;
+ }
+
+ Ok(())
+}
+
+pub async fn delete_user_account(person_id: PersonId, pool: &DbPool) -> Result<(), LemmyError> {
+ // Comments
+ let permadelete = move |conn: &'_ _| Comment::permadelete_for_creator(conn, person_id);
+ blocking(pool, permadelete)
+ .await?
+ .map_err(|e| LemmyError::from_error_message(e, "couldnt_update_comment"))?;
+
+ // Posts
+ let permadelete = move |conn: &'_ _| Post::permadelete_for_creator(conn, person_id);
+ blocking(pool, permadelete)
+ .await?
+ .map_err(|e| LemmyError::from_error_message(e, "couldnt_update_post"))?;
+
+ blocking(pool, move |conn| Person::delete_account(conn, person_id)).await??;
+
+ Ok(())
+}
+
+pub fn check_image_has_local_domain(url: &Option<DbUrl>) -> Result<(), LemmyError> {
+ if let Some(url) = url {
+ let settings = Settings::get();
+ let domain = url.domain().expect("url has domain");
+ if domain != settings.hostname {
+ return Err(LemmyError::from_message("image_not_local"));
+ }
+ }
+ Ok(())
+}
+use crate::sensitive::Sensitive;
use lemmy_db_schema::newtypes::{CommunityId, PostId};
-use lemmy_utils::Sensitive;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)]
lemmy_apub = { version = "=0.16.3", path = "../apub" }
lemmy_apub_lib = { version = "=0.16.3", path = "../apub_lib" }
lemmy_utils = { version = "=0.16.3", path = "../utils" }
-lemmy_db_schema = { version = "=0.16.3", path = "../db_schema" }
-lemmy_db_views = { version = "=0.16.3", path = "../db_views" }
-lemmy_db_views_actor = { version = "=0.16.3", path = "../db_views_actor" }
-lemmy_api_common = { version = "=0.16.3", path = "../api_common" }
+lemmy_db_schema = { version = "=0.16.3", path = "../db_schema", features = ["full"] }
+lemmy_db_views = { version = "=0.16.3", path = "../db_views", features = ["full"] }
+lemmy_db_views_actor = { version = "=0.16.3", path = "../db_views_actor", features = ["full"] }
+lemmy_api_common = { version = "=0.16.3", path = "../api_common", features = ["full"] }
lemmy_websocket = { version = "=0.16.3", path = "../websocket" }
bcrypt = "0.12.1"
serde_json = { version = "1.0.79", features = ["preserve_order"] }
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- check_community_ban,
- check_community_deleted_or_removed,
- check_post_deleted_or_removed,
- comment::*,
- get_local_user_view_from_jwt,
- get_post,
+ comment::{CommentResponse, CreateComment},
+ utils::{
+ blocking,
+ check_community_ban,
+ check_community_deleted_or_removed,
+ check_post_deleted_or_removed,
+ get_local_user_view_from_jwt,
+ get_post,
+ },
};
use lemmy_apub::{
generate_local_apub_endpoint,
},
traits::{Crud, Likeable},
};
-use lemmy_db_views::comment_view::CommentView;
+use lemmy_db_views::structs::CommentView;
use lemmy_utils::{
utils::{remove_slurs, scrape_text_for_mentions},
ConnectionId,
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- check_community_ban,
- comment::*,
- get_local_user_view_from_jwt,
- is_mod_or_admin,
+ comment::{CommentResponse, DeleteComment},
+ utils::{blocking, check_community_ban, get_local_user_view_from_jwt},
};
use lemmy_apub::activities::deletion::{send_apub_delete_in_community, DeletableObjects};
use lemmy_db_schema::{
- source::{
- comment::Comment,
- community::Community,
- moderator::{ModRemoveComment, ModRemoveCommentForm},
- post::Post,
- },
+ source::{comment::Comment, community::Community, post::Post},
traits::Crud,
};
-use lemmy_db_views::comment_view::CommentView;
+use lemmy_db_views::structs::CommentView;
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::{
send::{send_comment_ws_message, send_local_notifs},
Ok(res)
}
}
-
-#[async_trait::async_trait(?Send)]
-impl PerformCrud for RemoveComment {
- type Response = CommentResponse;
-
- #[tracing::instrument(skip(context, websocket_id))]
- async fn perform(
- &self,
- context: &Data<LemmyContext>,
- websocket_id: Option<ConnectionId>,
- ) -> Result<CommentResponse, LemmyError> {
- let data: &RemoveComment = self;
- let local_user_view =
- get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
-
- let comment_id = data.comment_id;
- let orig_comment = blocking(context.pool(), move |conn| {
- CommentView::read(conn, comment_id, None)
- })
- .await??;
-
- check_community_ban(
- local_user_view.person.id,
- orig_comment.community.id,
- context.pool(),
- )
- .await?;
-
- // Verify that only a mod or admin can remove
- is_mod_or_admin(
- context.pool(),
- local_user_view.person.id,
- orig_comment.community.id,
- )
- .await?;
-
- // Do the remove
- let removed = data.removed;
- let updated_comment = blocking(context.pool(), move |conn| {
- Comment::update_removed(conn, comment_id, removed)
- })
- .await?
- .map_err(|e| LemmyError::from_error_message(e, "couldnt_update_comment"))?;
-
- // Mod tables
- let form = ModRemoveCommentForm {
- mod_person_id: local_user_view.person.id,
- comment_id: data.comment_id,
- removed: Some(removed),
- reason: data.reason.to_owned(),
- };
- blocking(context.pool(), move |conn| {
- ModRemoveComment::create(conn, &form)
- })
- .await??;
-
- let post_id = updated_comment.post_id;
- let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
- let recipient_ids = send_local_notifs(
- vec![],
- &updated_comment,
- &local_user_view.person.clone(),
- &post,
- false,
- context,
- )
- .await?;
-
- let res = send_comment_ws_message(
- data.comment_id,
- UserOperationCrud::RemoveComment,
- websocket_id,
- None, // TODO maybe this might clear other forms
- Some(local_user_view.person.id),
- recipient_ids,
- context,
- )
- .await?;
-
- // Send the apub message
- let community = blocking(context.pool(), move |conn| {
- Community::read(conn, orig_comment.post.community_id)
- })
- .await??;
- let deletable = DeletableObjects::Comment(Box::new(updated_comment.clone().into()));
- send_apub_delete_in_community(
- local_user_view.person,
- community,
- deletable,
- data.reason.clone().or_else(|| Some("".to_string())),
- removed,
- context,
- )
- .await?;
-
- Ok(res)
- }
-}
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- check_private_instance,
- comment::*,
- get_local_user_view_from_jwt_opt,
+ comment::{GetComments, GetCommentsResponse},
+ utils::{blocking, check_private_instance, get_local_user_view_from_jwt_opt},
};
use lemmy_apub::{fetcher::resolve_actor_identifier, objects::community::ApubCommunity};
use lemmy_db_schema::{
- from_opt_str_to_opt_enum,
source::community::Community,
traits::DeleteableOrRemoveable,
- ListingType,
- SortType,
+ utils::{from_opt_str_to_opt_enum, ListingType, SortType},
};
use lemmy_db_views::comment_view::CommentQueryBuilder;
use lemmy_utils::{ConnectionId, LemmyError};
mod delete;
mod list;
mod read;
+mod remove;
mod update;
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- check_private_instance,
- comment::*,
- get_local_user_view_from_jwt_opt,
+ comment::{CommentResponse, GetComment},
+ utils::{blocking, check_private_instance, get_local_user_view_from_jwt_opt},
};
-use lemmy_db_views::comment_view::CommentView;
+use lemmy_db_views::structs::CommentView;
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext;
--- /dev/null
+use crate::PerformCrud;
+use actix_web::web::Data;
+use lemmy_api_common::{
+ comment::{CommentResponse, RemoveComment},
+ utils::{blocking, check_community_ban, get_local_user_view_from_jwt, is_mod_or_admin},
+};
+use lemmy_apub::activities::deletion::{send_apub_delete_in_community, DeletableObjects};
+use lemmy_db_schema::{
+ source::{
+ comment::Comment,
+ community::Community,
+ moderator::{ModRemoveComment, ModRemoveCommentForm},
+ post::Post,
+ },
+ traits::Crud,
+};
+use lemmy_db_views::structs::CommentView;
+use lemmy_utils::{ConnectionId, LemmyError};
+use lemmy_websocket::{
+ send::{send_comment_ws_message, send_local_notifs},
+ LemmyContext,
+ UserOperationCrud,
+};
+
+#[async_trait::async_trait(?Send)]
+impl PerformCrud for RemoveComment {
+ type Response = CommentResponse;
+
+ #[tracing::instrument(skip(context, websocket_id))]
+ async fn perform(
+ &self,
+ context: &Data<LemmyContext>,
+ websocket_id: Option<ConnectionId>,
+ ) -> Result<CommentResponse, LemmyError> {
+ let data: &RemoveComment = self;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
+
+ let comment_id = data.comment_id;
+ let orig_comment = blocking(context.pool(), move |conn| {
+ CommentView::read(conn, comment_id, None)
+ })
+ .await??;
+
+ check_community_ban(
+ local_user_view.person.id,
+ orig_comment.community.id,
+ context.pool(),
+ )
+ .await?;
+
+ // Verify that only a mod or admin can remove
+ is_mod_or_admin(
+ context.pool(),
+ local_user_view.person.id,
+ orig_comment.community.id,
+ )
+ .await?;
+
+ // Do the remove
+ let removed = data.removed;
+ let updated_comment = blocking(context.pool(), move |conn| {
+ Comment::update_removed(conn, comment_id, removed)
+ })
+ .await?
+ .map_err(|e| LemmyError::from_error_message(e, "couldnt_update_comment"))?;
+
+ // Mod tables
+ let form = ModRemoveCommentForm {
+ mod_person_id: local_user_view.person.id,
+ comment_id: data.comment_id,
+ removed: Some(removed),
+ reason: data.reason.to_owned(),
+ };
+ blocking(context.pool(), move |conn| {
+ ModRemoveComment::create(conn, &form)
+ })
+ .await??;
+
+ let post_id = updated_comment.post_id;
+ let post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
+ let recipient_ids = send_local_notifs(
+ vec![],
+ &updated_comment,
+ &local_user_view.person.clone(),
+ &post,
+ false,
+ context,
+ )
+ .await?;
+
+ let res = send_comment_ws_message(
+ data.comment_id,
+ UserOperationCrud::RemoveComment,
+ websocket_id,
+ None, // TODO maybe this might clear other forms
+ Some(local_user_view.person.id),
+ recipient_ids,
+ context,
+ )
+ .await?;
+
+ // Send the apub message
+ let community = blocking(context.pool(), move |conn| {
+ Community::read(conn, orig_comment.post.community_id)
+ })
+ .await??;
+ let deletable = DeletableObjects::Comment(Box::new(updated_comment.clone().into()));
+ send_apub_delete_in_community(
+ local_user_view.person,
+ community,
+ deletable,
+ data.reason.clone().or_else(|| Some("".to_string())),
+ removed,
+ context,
+ )
+ .await?;
+
+ Ok(res)
+ }
+}
use actix_web::web::Data;
-
use lemmy_api_common::{
- blocking,
- check_community_ban,
- check_community_deleted_or_removed,
- check_post_deleted_or_removed,
- comment::*,
- get_local_user_view_from_jwt,
+ comment::{CommentResponse, EditComment},
+ utils::{
+ blocking,
+ check_community_ban,
+ check_community_deleted_or_removed,
+ check_post_deleted_or_removed,
+ get_local_user_view_from_jwt,
+ },
};
use lemmy_apub::protocol::activities::{
create_or_update::comment::CreateOrUpdateComment,
CreateOrUpdateType,
};
use lemmy_db_schema::source::comment::Comment;
-use lemmy_db_views::comment_view::CommentView;
+use lemmy_db_views::structs::CommentView;
use lemmy_utils::{
utils::{remove_slurs, scrape_text_for_mentions},
ConnectionId,
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- check_image_has_local_domain,
community::{CommunityResponse, CreateCommunity},
- get_local_user_view_from_jwt,
- is_admin,
+ utils::{blocking, check_image_has_local_domain, get_local_user_view_from_jwt, is_admin},
};
use lemmy_apub::{
generate_followers_url,
};
use lemmy_apub_lib::object_id::ObjectId;
use lemmy_db_schema::{
- diesel_option_overwrite_to_url,
source::{
community::{
Community,
site::Site,
},
traits::{Crud, Followable, Joinable},
+ utils::diesel_option_overwrite_to_url,
};
-use lemmy_db_views_actor::community_view::CommunityView;
+use lemmy_db_views_actor::structs::CommunityView;
use lemmy_utils::{
apub::generate_actor_keypair,
utils::{check_slurs, check_slurs_opt, is_valid_actor_name},
use crate::PerformCrud;
use actix_web::web::Data;
-use lemmy_api_common::{blocking, community::*, get_local_user_view_from_jwt, is_admin};
-use lemmy_apub::activities::deletion::{send_apub_delete_in_community, DeletableObjects};
-use lemmy_db_schema::{
- source::{
- community::Community,
- moderator::{ModRemoveCommunity, ModRemoveCommunityForm},
- },
- traits::Crud,
+use lemmy_api_common::{
+ community::{CommunityResponse, DeleteCommunity},
+ utils::{blocking, get_local_user_view_from_jwt},
};
-use lemmy_db_views_actor::community_moderator_view::CommunityModeratorView;
-use lemmy_utils::{utils::naive_from_unix, ConnectionId, LemmyError};
+use lemmy_apub::activities::deletion::{send_apub_delete_in_community, DeletableObjects};
+use lemmy_db_schema::source::community::Community;
+use lemmy_db_views_actor::structs::CommunityModeratorView;
+use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::{send::send_community_ws_message, LemmyContext, UserOperationCrud};
#[async_trait::async_trait(?Send)]
Ok(res)
}
}
-
-#[async_trait::async_trait(?Send)]
-impl PerformCrud for RemoveCommunity {
- type Response = CommunityResponse;
-
- #[tracing::instrument(skip(context, websocket_id))]
- async fn perform(
- &self,
- context: &Data<LemmyContext>,
- websocket_id: Option<ConnectionId>,
- ) -> Result<CommunityResponse, LemmyError> {
- let data: &RemoveCommunity = self;
- let local_user_view =
- get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
-
- // Verify its an admin (only an admin can remove a community)
- is_admin(&local_user_view)?;
-
- // Do the remove
- let community_id = data.community_id;
- let removed = data.removed;
- let updated_community = blocking(context.pool(), move |conn| {
- Community::update_removed(conn, community_id, removed)
- })
- .await?
- .map_err(|e| LemmyError::from_error_message(e, "couldnt_update_community"))?;
-
- // Mod tables
- let expires = data.expires.map(naive_from_unix);
- let form = ModRemoveCommunityForm {
- mod_person_id: local_user_view.person.id,
- community_id: data.community_id,
- removed: Some(removed),
- reason: data.reason.to_owned(),
- expires,
- };
- blocking(context.pool(), move |conn| {
- ModRemoveCommunity::create(conn, &form)
- })
- .await??;
-
- let res = send_community_ws_message(
- data.community_id,
- UserOperationCrud::RemoveCommunity,
- websocket_id,
- Some(local_user_view.person.id),
- context,
- )
- .await?;
-
- // Apub messages
- let deletable = DeletableObjects::Community(Box::new(updated_community.clone().into()));
- send_apub_delete_in_community(
- local_user_view.person,
- updated_community,
- deletable,
- data.reason.clone().or_else(|| Some("".to_string())),
- removed,
- context,
- )
- .await?;
- Ok(res)
- }
-}
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- check_private_instance,
- community::*,
- get_local_user_view_from_jwt_opt,
+ community::{ListCommunities, ListCommunitiesResponse},
+ utils::{blocking, check_private_instance, get_local_user_view_from_jwt_opt},
};
use lemmy_db_schema::{
- from_opt_str_to_opt_enum,
traits::DeleteableOrRemoveable,
- ListingType,
- SortType,
+ utils::{from_opt_str_to_opt_enum, ListingType, SortType},
};
use lemmy_db_views_actor::community_view::CommunityQueryBuilder;
use lemmy_utils::{ConnectionId, LemmyError};
mod delete;
mod list;
mod read;
+mod remove;
mod update;
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- check_private_instance,
- community::*,
- get_local_user_view_from_jwt_opt,
+ community::{GetCommunity, GetCommunityResponse},
+ utils::{blocking, check_private_instance, get_local_user_view_from_jwt_opt},
};
use lemmy_apub::{
fetcher::resolve_actor_identifier,
source::{community::Community, site::Site},
traits::DeleteableOrRemoveable,
};
-use lemmy_db_views_actor::{
- community_moderator_view::CommunityModeratorView,
- community_view::CommunityView,
-};
+use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView};
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::{messages::GetCommunityUsersOnline, LemmyContext};
--- /dev/null
+use crate::PerformCrud;
+use actix_web::web::Data;
+use lemmy_api_common::{
+ community::{CommunityResponse, RemoveCommunity},
+ utils::{blocking, get_local_user_view_from_jwt, is_admin},
+};
+use lemmy_apub::activities::deletion::{send_apub_delete_in_community, DeletableObjects};
+use lemmy_db_schema::{
+ source::{
+ community::Community,
+ moderator::{ModRemoveCommunity, ModRemoveCommunityForm},
+ },
+ traits::Crud,
+};
+use lemmy_utils::{utils::naive_from_unix, ConnectionId, LemmyError};
+use lemmy_websocket::{send::send_community_ws_message, LemmyContext, UserOperationCrud};
+
+#[async_trait::async_trait(?Send)]
+impl PerformCrud for RemoveCommunity {
+ type Response = CommunityResponse;
+
+ #[tracing::instrument(skip(context, websocket_id))]
+ async fn perform(
+ &self,
+ context: &Data<LemmyContext>,
+ websocket_id: Option<ConnectionId>,
+ ) -> Result<CommunityResponse, LemmyError> {
+ let data: &RemoveCommunity = self;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
+
+ // Verify its an admin (only an admin can remove a community)
+ is_admin(&local_user_view)?;
+
+ // Do the remove
+ let community_id = data.community_id;
+ let removed = data.removed;
+ let updated_community = blocking(context.pool(), move |conn| {
+ Community::update_removed(conn, community_id, removed)
+ })
+ .await?
+ .map_err(|e| LemmyError::from_error_message(e, "couldnt_update_community"))?;
+
+ // Mod tables
+ let expires = data.expires.map(naive_from_unix);
+ let form = ModRemoveCommunityForm {
+ mod_person_id: local_user_view.person.id,
+ community_id: data.community_id,
+ removed: Some(removed),
+ reason: data.reason.to_owned(),
+ expires,
+ };
+ blocking(context.pool(), move |conn| {
+ ModRemoveCommunity::create(conn, &form)
+ })
+ .await??;
+
+ let res = send_community_ws_message(
+ data.community_id,
+ UserOperationCrud::RemoveCommunity,
+ websocket_id,
+ Some(local_user_view.person.id),
+ context,
+ )
+ .await?;
+
+ // Apub messages
+ let deletable = DeletableObjects::Community(Box::new(updated_community.clone().into()));
+ send_apub_delete_in_community(
+ local_user_view.person,
+ updated_community,
+ deletable,
+ data.reason.clone().or_else(|| Some("".to_string())),
+ removed,
+ context,
+ )
+ .await?;
+ Ok(res)
+ }
+}
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- check_image_has_local_domain,
community::{CommunityResponse, EditCommunity},
- get_local_user_view_from_jwt,
+ utils::{blocking, check_image_has_local_domain, get_local_user_view_from_jwt},
};
use lemmy_apub::protocol::activities::community::update::UpdateCommunity;
use lemmy_db_schema::{
- diesel_option_overwrite_to_url,
- naive_now,
newtypes::PersonId,
source::community::{Community, CommunityForm},
traits::Crud,
+ utils::{diesel_option_overwrite_to_url, naive_now},
};
-use lemmy_db_views_actor::community_moderator_view::CommunityModeratorView;
+use lemmy_db_views_actor::structs::CommunityModeratorView;
use lemmy_utils::{utils::check_slurs_opt, ConnectionId, LemmyError};
use lemmy_websocket::{send::send_community_ws_message, LemmyContext, UserOperationCrud};
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- check_community_ban,
- check_community_deleted_or_removed,
- get_local_user_view_from_jwt,
- honeypot_check,
- mark_post_as_read,
- post::*,
+ post::{CreatePost, PostResponse},
+ request::fetch_site_data,
+ utils::{
+ blocking,
+ check_community_ban,
+ check_community_deleted_or_removed,
+ get_local_user_view_from_jwt,
+ honeypot_check,
+ mark_post_as_read,
+ },
};
use lemmy_apub::{
generate_local_apub_endpoint,
},
traits::{Crud, Likeable},
};
-use lemmy_db_views_actor::community_view::CommunityView;
+use lemmy_db_views_actor::structs::CommunityView;
use lemmy_utils::{
- request::fetch_site_data,
utils::{
check_slurs,
check_slurs_opt,
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- check_community_ban,
- check_community_deleted_or_removed,
- get_local_user_view_from_jwt,
- is_mod_or_admin,
- post::*,
+ post::{DeletePost, PostResponse},
+ utils::{
+ blocking,
+ check_community_ban,
+ check_community_deleted_or_removed,
+ get_local_user_view_from_jwt,
+ },
};
use lemmy_apub::activities::deletion::{send_apub_delete_in_community, DeletableObjects};
use lemmy_db_schema::{
- source::{
- community::Community,
- moderator::{ModRemovePost, ModRemovePostForm},
- post::Post,
- },
+ source::{community::Community, post::Post},
traits::Crud,
};
use lemmy_utils::{ConnectionId, LemmyError};
Ok(res)
}
}
-
-#[async_trait::async_trait(?Send)]
-impl PerformCrud for RemovePost {
- type Response = PostResponse;
-
- #[tracing::instrument(skip(context, websocket_id))]
- async fn perform(
- &self,
- context: &Data<LemmyContext>,
- websocket_id: Option<ConnectionId>,
- ) -> Result<PostResponse, LemmyError> {
- let data: &RemovePost = self;
- let local_user_view =
- get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
-
- let post_id = data.post_id;
- let orig_post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
-
- check_community_ban(
- local_user_view.person.id,
- orig_post.community_id,
- context.pool(),
- )
- .await?;
-
- // Verify that only the mods can remove
- is_mod_or_admin(
- context.pool(),
- local_user_view.person.id,
- orig_post.community_id,
- )
- .await?;
-
- // Update the post
- let post_id = data.post_id;
- let removed = data.removed;
- let updated_post = blocking(context.pool(), move |conn| {
- Post::update_removed(conn, post_id, removed)
- })
- .await??;
-
- // Mod tables
- let form = ModRemovePostForm {
- mod_person_id: local_user_view.person.id,
- post_id: data.post_id,
- removed: Some(removed),
- reason: data.reason.to_owned(),
- };
- blocking(context.pool(), move |conn| {
- ModRemovePost::create(conn, &form)
- })
- .await??;
-
- let res = send_post_ws_message(
- data.post_id,
- UserOperationCrud::RemovePost,
- websocket_id,
- Some(local_user_view.person.id),
- context,
- )
- .await?;
-
- // apub updates
- let community = blocking(context.pool(), move |conn| {
- Community::read(conn, orig_post.community_id)
- })
- .await??;
- let deletable = DeletableObjects::Post(Box::new(updated_post.into()));
- send_apub_delete_in_community(
- local_user_view.person,
- community,
- deletable,
- data.reason.clone().or_else(|| Some("".to_string())),
- removed,
- context,
- )
- .await?;
- Ok(res)
- }
-}
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- check_private_instance,
- get_local_user_view_from_jwt_opt,
post::{GetPosts, GetPostsResponse},
+ utils::{blocking, check_private_instance, get_local_user_view_from_jwt_opt},
};
use lemmy_apub::{fetcher::resolve_actor_identifier, objects::community::ApubCommunity};
use lemmy_db_schema::{
- from_opt_str_to_opt_enum,
source::{community::Community, site::Site},
traits::DeleteableOrRemoveable,
- ListingType,
- SortType,
+ utils::{from_opt_str_to_opt_enum, ListingType, SortType},
};
use lemmy_db_views::post_view::PostQueryBuilder;
use lemmy_utils::{ConnectionId, LemmyError};
mod delete;
mod list;
mod read;
+mod remove;
mod update;
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- check_private_instance,
- get_local_user_view_from_jwt_opt,
- mark_post_as_read,
post::{GetPost, GetPostResponse},
+ utils::{blocking, check_private_instance, get_local_user_view_from_jwt_opt, mark_post_as_read},
};
use lemmy_db_schema::traits::DeleteableOrRemoveable;
-use lemmy_db_views::{comment_view::CommentQueryBuilder, post_view::PostView};
-use lemmy_db_views_actor::{
- community_moderator_view::CommunityModeratorView,
- community_view::CommunityView,
-};
+use lemmy_db_views::{comment_view::CommentQueryBuilder, structs::PostView};
+use lemmy_db_views_actor::structs::{CommunityModeratorView, CommunityView};
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::{messages::GetPostUsersOnline, LemmyContext};
--- /dev/null
+use crate::PerformCrud;
+use actix_web::web::Data;
+use lemmy_api_common::{
+ post::{PostResponse, RemovePost},
+ utils::{blocking, check_community_ban, get_local_user_view_from_jwt, is_mod_or_admin},
+};
+use lemmy_apub::activities::deletion::{send_apub_delete_in_community, DeletableObjects};
+use lemmy_db_schema::{
+ source::{
+ community::Community,
+ moderator::{ModRemovePost, ModRemovePostForm},
+ post::Post,
+ },
+ traits::Crud,
+};
+use lemmy_utils::{ConnectionId, LemmyError};
+use lemmy_websocket::{send::send_post_ws_message, LemmyContext, UserOperationCrud};
+
+#[async_trait::async_trait(?Send)]
+impl PerformCrud for RemovePost {
+ type Response = PostResponse;
+
+ #[tracing::instrument(skip(context, websocket_id))]
+ async fn perform(
+ &self,
+ context: &Data<LemmyContext>,
+ websocket_id: Option<ConnectionId>,
+ ) -> Result<PostResponse, LemmyError> {
+ let data: &RemovePost = self;
+ let local_user_view =
+ get_local_user_view_from_jwt(&data.auth, context.pool(), context.secret()).await?;
+
+ let post_id = data.post_id;
+ let orig_post = blocking(context.pool(), move |conn| Post::read(conn, post_id)).await??;
+
+ check_community_ban(
+ local_user_view.person.id,
+ orig_post.community_id,
+ context.pool(),
+ )
+ .await?;
+
+ // Verify that only the mods can remove
+ is_mod_or_admin(
+ context.pool(),
+ local_user_view.person.id,
+ orig_post.community_id,
+ )
+ .await?;
+
+ // Update the post
+ let post_id = data.post_id;
+ let removed = data.removed;
+ let updated_post = blocking(context.pool(), move |conn| {
+ Post::update_removed(conn, post_id, removed)
+ })
+ .await??;
+
+ // Mod tables
+ let form = ModRemovePostForm {
+ mod_person_id: local_user_view.person.id,
+ post_id: data.post_id,
+ removed: Some(removed),
+ reason: data.reason.to_owned(),
+ };
+ blocking(context.pool(), move |conn| {
+ ModRemovePost::create(conn, &form)
+ })
+ .await??;
+
+ let res = send_post_ws_message(
+ data.post_id,
+ UserOperationCrud::RemovePost,
+ websocket_id,
+ Some(local_user_view.person.id),
+ context,
+ )
+ .await?;
+
+ // apub updates
+ let community = blocking(context.pool(), move |conn| {
+ Community::read(conn, orig_post.community_id)
+ })
+ .await??;
+ let deletable = DeletableObjects::Post(Box::new(updated_post.into()));
+ send_apub_delete_in_community(
+ local_user_view.person,
+ community,
+ deletable,
+ data.reason.clone().or_else(|| Some("".to_string())),
+ removed,
+ context,
+ )
+ .await?;
+ Ok(res)
+ }
+}
use actix_web::web::Data;
-
use lemmy_api_common::{
- blocking,
- check_community_ban,
- check_community_deleted_or_removed,
- get_local_user_view_from_jwt,
- post::*,
+ post::{EditPost, PostResponse},
+ request::fetch_site_data,
+ utils::{
+ blocking,
+ check_community_ban,
+ check_community_deleted_or_removed,
+ get_local_user_view_from_jwt,
+ },
};
use lemmy_apub::protocol::activities::{
create_or_update::post::CreateOrUpdatePost,
CreateOrUpdateType,
};
use lemmy_db_schema::{
- naive_now,
source::post::{Post, PostForm},
traits::Crud,
+ utils::naive_now,
};
use lemmy_utils::{
- request::fetch_site_data,
utils::{check_slurs_opt, clean_optional_text, clean_url_params, is_valid_post_title},
ConnectionId,
LemmyError,
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- check_person_block,
- get_local_user_view_from_jwt,
- get_user_lang,
person::{CreatePrivateMessage, PrivateMessageResponse},
- send_email_to_user,
+ utils::{
+ blocking,
+ check_person_block,
+ get_local_user_view_from_jwt,
+ get_user_lang,
+ send_email_to_user,
+ },
};
use lemmy_apub::{
generate_local_apub_endpoint,
source::private_message::{PrivateMessage, PrivateMessageForm},
traits::Crud,
};
-use lemmy_db_views::local_user_view::LocalUserView;
+use lemmy_db_views::structs::LocalUserView;
use lemmy_utils::{utils::remove_slurs, ConnectionId, LemmyError};
use lemmy_websocket::{send::send_pm_ws_message, LemmyContext, UserOperationCrud};
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- get_local_user_view_from_jwt,
person::{DeletePrivateMessage, PrivateMessageResponse},
+ utils::{blocking, get_local_user_view_from_jwt},
};
use lemmy_apub::activities::deletion::send_apub_delete_private_message;
use lemmy_db_schema::{source::private_message::PrivateMessage, traits::Crud};
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- get_local_user_view_from_jwt,
person::{GetPrivateMessages, PrivateMessagesResponse},
+ utils::{blocking, get_local_user_view_from_jwt},
};
use lemmy_db_schema::traits::DeleteableOrRemoveable;
use lemmy_db_views::private_message_view::PrivateMessageQueryBuilder;
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- get_local_user_view_from_jwt,
person::{EditPrivateMessage, PrivateMessageResponse},
+ utils::{blocking, get_local_user_view_from_jwt},
};
use lemmy_apub::protocol::activities::{
create_or_update::private_message::CreateOrUpdatePrivateMessage,
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- check_image_has_local_domain,
- get_local_user_view_from_jwt,
- is_admin,
- site::*,
- site_description_length_check,
+ site::{CreateSite, SiteResponse},
+ utils::{
+ blocking,
+ check_image_has_local_domain,
+ get_local_user_view_from_jwt,
+ is_admin,
+ site_description_length_check,
+ },
};
use lemmy_apub::generate_site_inbox_url;
use lemmy_db_schema::{
- diesel_option_overwrite,
- diesel_option_overwrite_to_url,
- naive_now,
newtypes::DbUrl,
source::site::{Site, SiteForm},
traits::Crud,
+ utils::{diesel_option_overwrite, diesel_option_overwrite_to_url, naive_now},
};
-use lemmy_db_views::site_view::SiteView;
+use lemmy_db_views::structs::SiteView;
use lemmy_utils::{
apub::generate_actor_keypair,
settings::structs::Settings,
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- build_federated_instances,
- get_local_user_settings_view_from_jwt_opt,
person::Register,
- site::*,
+ site::{CreateSite, GetSite, GetSiteResponse, MyUserInfo},
+ utils::{blocking, build_federated_instances, get_local_user_settings_view_from_jwt_opt},
};
-use lemmy_db_views::site_view::SiteView;
-use lemmy_db_views_actor::{
- community_block_view::CommunityBlockView,
- community_follower_view::CommunityFollowerView,
- community_moderator_view::CommunityModeratorView,
- person_block_view::PersonBlockView,
- person_view::PersonViewSafe,
+use lemmy_db_views::structs::SiteView;
+use lemmy_db_views_actor::structs::{
+ CommunityBlockView,
+ CommunityFollowerView,
+ CommunityModeratorView,
+ PersonBlockView,
+ PersonViewSafe,
};
use lemmy_utils::{version, ConnectionId, LemmyError};
use lemmy_websocket::{messages::GetUsersOnline, LemmyContext};
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- check_image_has_local_domain,
- get_local_user_view_from_jwt,
- is_admin,
site::{EditSite, SiteResponse},
- site_description_length_check,
+ utils::{
+ blocking,
+ check_image_has_local_domain,
+ get_local_user_view_from_jwt,
+ is_admin,
+ site_description_length_check,
+ },
};
use lemmy_db_schema::{
- diesel_option_overwrite,
- diesel_option_overwrite_to_url,
- naive_now,
source::{
local_user::LocalUser,
site::{Site, SiteForm},
},
traits::Crud,
- ListingType,
+ utils::{diesel_option_overwrite, diesel_option_overwrite_to_url, naive_now, ListingType},
};
-use lemmy_db_views::site_view::SiteView;
+use lemmy_db_views::structs::SiteView;
use lemmy_utils::{utils::check_slurs_opt, ConnectionId, LemmyError};
use lemmy_websocket::{messages::SendAllMessage, LemmyContext, UserOperationCrud};
use std::{default::Default, str::FromStr};
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- honeypot_check,
- password_length_check,
- person::*,
- send_verification_email,
+ person::{LoginResponse, Register},
+ utils::{blocking, honeypot_check, password_length_check, send_verification_email},
};
use lemmy_apub::{
generate_followers_url,
EndpointType,
};
use lemmy_db_schema::{
- aggregates::person_aggregates::PersonAggregates,
+ aggregates::structs::PersonAggregates,
newtypes::CommunityId,
source::{
community::{
},
traits::{Crud, Followable, Joinable},
};
-use lemmy_db_views::local_user_view::LocalUserView;
-use lemmy_db_views_actor::person_view::PersonViewSafe;
+use lemmy_db_views::structs::LocalUserView;
+use lemmy_db_views_actor::structs::PersonViewSafe;
use lemmy_utils::{
apub::generate_actor_keypair,
claims::Claims,
use crate::PerformCrud;
use actix_web::web::Data;
use bcrypt::verify;
-use lemmy_api_common::{delete_user_account, get_local_user_view_from_jwt, person::*};
+use lemmy_api_common::{
+ person::{DeleteAccount, DeleteAccountResponse},
+ utils::{delete_user_account, get_local_user_view_from_jwt},
+};
use lemmy_apub::protocol::activities::deletion::delete_user::DeleteUser;
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext;
use crate::PerformCrud;
use actix_web::web::Data;
use lemmy_api_common::{
- blocking,
- check_private_instance,
- get_local_user_view_from_jwt_opt,
- person::*,
+ person::{GetPersonDetails, GetPersonDetailsResponse},
+ utils::{blocking, check_private_instance, get_local_user_view_from_jwt_opt},
};
use lemmy_apub::{fetcher::resolve_actor_identifier, objects::person::ApubPerson};
-use lemmy_db_schema::{from_opt_str_to_opt_enum, source::person::Person, SortType};
-use lemmy_db_views::{comment_view::CommentQueryBuilder, post_view::PostQueryBuilder};
-use lemmy_db_views_actor::{
- community_moderator_view::CommunityModeratorView,
- person_view::PersonViewSafe,
+use lemmy_db_schema::{
+ source::person::Person,
+ utils::{from_opt_str_to_opt_enum, SortType},
};
+use lemmy_db_views::{comment_view::CommentQueryBuilder, post_view::PostQueryBuilder};
+use lemmy_db_views_actor::structs::{CommunityModeratorView, PersonViewSafe};
use lemmy_utils::{ConnectionId, LemmyError};
use lemmy_websocket::LemmyContext;
[dependencies]
lemmy_utils = { version = "=0.16.3", path = "../utils" }
lemmy_apub_lib = { version = "=0.16.3", path = "../apub_lib" }
-lemmy_db_schema = { version = "=0.16.3", path = "../db_schema" }
-lemmy_db_views = { version = "=0.16.3", path = "../db_views" }
-lemmy_db_views_actor = { version = "=0.16.3", path = "../db_views_actor" }
-lemmy_api_common = { version = "=0.16.3", path = "../api_common" }
+lemmy_db_schema = { version = "=0.16.3", path = "../db_schema", features = ["full"] }
+lemmy_db_views = { version = "=0.16.3", path = "../db_views", features = ["full"] }
+lemmy_db_views_actor = { version = "=0.16.3", path = "../db_views_actor", features = ["full"] }
+lemmy_api_common = { version = "=0.16.3", path = "../api_common", features = ["full"] }
lemmy_websocket = { version = "=0.16.3", path = "../websocket" }
diesel = "1.4.8"
activitystreams-kinds = "0.2.1"
-chrono = { version = "0.4.19", features = ["serde"] }
+chrono = { version = "0.4.19", features = ["serde"], default-features = false }
serde_json = { version = "1.0.79", features = ["preserve_order"] }
serde = { version = "1.0.136", features = ["derive"] }
serde_with = "1.12.0"
use activitystreams_kinds::{activity::BlockType, public};
use anyhow::anyhow;
use chrono::NaiveDateTime;
-use lemmy_api_common::{blocking, remove_user_data, remove_user_data_in_community};
+use lemmy_api_common::utils::{blocking, remove_user_data, remove_user_data_in_community};
use lemmy_apub_lib::{
data::Data,
object_id::ObjectId,
protocol::objects::{group::Group, instance::Instance},
};
use chrono::NaiveDateTime;
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::{
object_id::ObjectId,
traits::{ActorType, ApubObject},
};
-use lemmy_db_schema::{source::site::Site, DbPool};
+use lemmy_db_schema::{source::site::Site, utils::DbPool};
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
use serde::Deserialize;
protocol::activities::block::{block_user::BlockUser, undo_block_user::UndoBlockUser},
};
use activitystreams_kinds::{activity::UndoType, public};
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::{
data::Data,
object_id::ObjectId,
protocol::activities::community::add_mod::AddMod,
};
use activitystreams_kinds::{activity::AddType, public};
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::{
data::Data,
object_id::ObjectId,
protocol::activities::community::remove_mod::RemoveMod,
};
use activitystreams_kinds::{activity::RemoveType, public};
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::{
data::Data,
object_id::ObjectId,
PostOrComment,
};
use activitystreams_kinds::activity::FlagType;
-use lemmy_api_common::{blocking, comment::CommentReportResponse, post::PostReportResponse};
+use lemmy_api_common::{comment::CommentReportResponse, post::PostReportResponse, utils::blocking};
use lemmy_apub_lib::{
data::Data,
object_id::ObjectId,
},
traits::Reportable,
};
-use lemmy_db_views::{comment_report_view::CommentReportView, post_report_view::PostReportView};
+use lemmy_db_views::structs::{CommentReportView, PostReportView};
use lemmy_utils::LemmyError;
use lemmy_websocket::{messages::SendModRoomMessage, LemmyContext, UserOperation};
protocol::activities::community::update::UpdateCommunity,
};
use activitystreams_kinds::{activity::UpdateType, public};
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::{
data::Data,
object_id::ObjectId,
protocol::activities::{create_or_update::comment::CreateOrUpdateComment, CreateOrUpdateType},
};
use activitystreams_kinds::public;
-use lemmy_api_common::{blocking, check_post_deleted_or_removed};
+use lemmy_api_common::utils::{blocking, check_post_deleted_or_removed};
use lemmy_apub_lib::{
data::Data,
object_id::ObjectId,
use crate::objects::person::ApubPerson;
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::object_id::ObjectId;
use lemmy_db_schema::{
newtypes::LocalUserId,
protocol::activities::{create_or_update::post::CreateOrUpdatePost, CreateOrUpdateType},
};
use activitystreams_kinds::public;
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::{
data::Data,
object_id::ObjectId,
CreateOrUpdateType,
},
};
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::{
data::Data,
object_id::ObjectId,
};
use activitystreams_kinds::activity::DeleteType;
use anyhow::anyhow;
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::{data::Data, object_id::ObjectId, traits::ActivityHandler};
use lemmy_db_schema::{
source::{
protocol::activities::deletion::delete_user::DeleteUser,
};
use activitystreams_kinds::{activity::DeleteType, public};
-use lemmy_api_common::{blocking, delete_user_account};
+use lemmy_api_common::utils::{blocking, delete_user_account};
use lemmy_apub_lib::{
data::Data,
object_id::ObjectId,
protocol::activities::deletion::{delete::Delete, undo_delete::UndoDelete},
};
use activitystreams_kinds::public;
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::{
object_id::ObjectId,
traits::{ActorType, ApubObject},
protocol::activities::deletion::{delete::Delete, undo_delete::UndoDelete},
};
use activitystreams_kinds::activity::UndoType;
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::{data::Data, object_id::ObjectId, traits::ActivityHandler};
use lemmy_db_schema::{
source::{
protocol::activities::following::{accept::AcceptFollowCommunity, follow::FollowCommunity},
};
use activitystreams_kinds::activity::AcceptType;
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::{
data::Data,
object_id::ObjectId,
protocol::activities::following::{accept::AcceptFollowCommunity, follow::FollowCommunity},
};
use activitystreams_kinds::activity::FollowType;
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::{
data::Data,
object_id::ObjectId,
protocol::activities::following::{follow::FollowCommunity, undo_follow::UndoFollowCommunity},
};
use activitystreams_kinds::activity::UndoType;
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::{
data::Data,
object_id::ObjectId,
};
use activitystreams_kinds::public;
use anyhow::anyhow;
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::{
activity_queue::send_activity,
object_id::ObjectId,
verify::verify_domains_match,
};
use lemmy_db_schema::source::community::Community;
-use lemmy_db_views_actor::{
- community_person_ban_view::CommunityPersonBanView,
- community_view::CommunityView,
-};
+use lemmy_db_views_actor::structs::{CommunityPersonBanView, CommunityView};
use lemmy_utils::{settings::structs::Settings, LemmyError};
use lemmy_websocket::LemmyContext;
use serde::Serialize;
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_db_schema::{
source::{
comment::{CommentLike, CommentLikeForm},
PostOrComment,
};
use activitystreams_kinds::{activity::UndoType, public};
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::{
data::Data,
object_id::ObjectId,
};
use activitystreams_kinds::public;
use anyhow::anyhow;
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::{
data::Data,
object_id::ObjectId,
};
use activitystreams_kinds::collection::OrderedCollectionType;
use chrono::NaiveDateTime;
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::{object_id::ObjectId, traits::ApubObject, verify::verify_domains_match};
use lemmy_db_schema::{
source::community::{CommunityModerator, CommunityModeratorForm},
traits::Joinable,
};
-use lemmy_db_views_actor::community_moderator_view::CommunityModeratorView;
+use lemmy_db_views_actor::structs::CommunityModeratorView;
use lemmy_utils::LemmyError;
use url::Url;
use activitystreams_kinds::collection::OrderedCollectionType;
use chrono::NaiveDateTime;
use futures::future::join_all;
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::{
data::Data,
traits::{ActivityHandler, ApubObject},
use crate::fetcher::post_or_comment::PostOrComment;
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_db_queries::source::{
comment::Comment_,
community::Community_,
use crate::fetcher::webfinger::webfinger_resolve_actor;
use itertools::Itertools;
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::traits::{ActorType, ApubObject};
use lemmy_db_schema::traits::ApubActor;
use lemmy_utils::{settings::structs::Settings, LemmyError};
traits::{ActorType, ApubObject},
};
use lemmy_db_schema::newtypes::DbUrl;
-use lemmy_utils::{
- request::{retry, RecvError},
- LemmyError,
-};
+use lemmy_utils::{request::retry, LemmyError};
use lemmy_websocket::LemmyContext;
use serde::{Deserialize, Serialize};
use tracing::debug;
let response = retry(|| context.client().get(&fetch_url).send()).await?;
- let res: WebfingerResponse = response
- .json()
- .await
- .map_err(|e| RecvError(e.to_string()))?;
+ let res: WebfingerResponse = response.json().await.map_err(LemmyError::from)?;
let links: Vec<Url> = res
.links
};
use actix_web::{web, web::Path, HttpResponse};
use diesel::result::Error::NotFound;
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::traits::ApubObject;
use lemmy_db_schema::{newtypes::CommentId, source::comment::Comment, traits::Crud};
use lemmy_utils::LemmyError;
},
};
use actix_web::{web, web::Payload, HttpRequest, HttpResponse};
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::{object_id::ObjectId, traits::ApubObject};
use lemmy_db_schema::{source::community::Community, traits::ApubActor};
use lemmy_utils::LemmyError;
use anyhow::{anyhow, Context};
use futures::StreamExt;
use http::StatusCode;
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::{
data::Data,
object_id::ObjectId,
protocol::collections::empty_outbox::EmptyOutbox,
};
use actix_web::{web, web::Payload, HttpRequest, HttpResponse};
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::traits::ApubObject;
use lemmy_db_schema::{source::person::Person, traits::ApubActor};
use lemmy_utils::LemmyError;
};
use actix_web::{web, HttpResponse};
use diesel::result::Error::NotFound;
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::traits::ApubObject;
use lemmy_db_schema::{newtypes::PostId, source::post::Post, traits::Crud};
use lemmy_utils::LemmyError;
protocol::collections::empty_outbox::EmptyOutbox,
};
use actix_web::{web, web::Payload, HttpRequest, HttpResponse};
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::traits::ApubObject;
use lemmy_db_schema::source::site::Site;
use lemmy_utils::{settings::structs::Settings, LemmyError};
use crate::fetcher::post_or_comment::PostOrComment;
use anyhow::{anyhow, Context};
-use lemmy_api_common::blocking;
-use lemmy_db_schema::{newtypes::DbUrl, source::activity::Activity, DbPool};
+use lemmy_api_common::utils::blocking;
+use lemmy_db_schema::{newtypes::DbUrl, source::activity::Activity, utils::DbPool};
use lemmy_utils::{location_info, settings::structs::Settings, LemmyError};
use serde::{Deserialize, Deserializer};
use std::net::IpAddr;
pub mod fetcher;
pub mod http;
pub(crate) mod mentions;
-pub mod migrations;
pub mod objects;
pub mod protocol;
objects::{comment::ApubComment, community::ApubCommunity, person::ApubPerson},
};
use activitystreams_kinds::link::MentionType;
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::{object_id::ObjectId, traits::ActorType};
use lemmy_db_schema::{
source::{comment::Comment, person::Person, post::Post},
traits::Crud,
- DbPool,
+ utils::DbPool,
};
use lemmy_utils::{
utils::{scrape_text_for_mentions, MentionData},
};
use activitystreams_kinds::{object::NoteType, public};
use chrono::NaiveDateTime;
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::{
object_id::ObjectId,
traits::ApubObject,
use activitystreams_kinds::actor::GroupType;
use chrono::NaiveDateTime;
use itertools::Itertools;
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::{
object_id::ObjectId,
traits::{ActorType, ApubObject},
};
use lemmy_db_schema::{source::community::Community, traits::ApubActor};
-use lemmy_db_views_actor::community_follower_view::CommunityFollowerView;
+use lemmy_db_views_actor::structs::CommunityFollowerView;
use lemmy_utils::{
utils::{convert_datetime, markdown_to_html},
LemmyError,
},
};
use chrono::NaiveDateTime;
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::{
object_id::ObjectId,
traits::{ActorType, ApubObject},
verify::verify_domains_match,
};
use lemmy_db_schema::{
- naive_now,
source::site::{Site, SiteForm},
+ utils::naive_now,
};
use lemmy_utils::{
utils::{check_slurs, check_slurs_opt, convert_datetime, markdown_to_html},
r2d2::{ConnectionManager, Pool},
PgConnection,
};
+ use lemmy_api_common::request::build_user_agent;
use lemmy_apub_lib::activity_queue::create_activity_queue;
use lemmy_db_schema::{
- establish_unpooled_connection,
- get_database_url_from_env,
source::secret::Secret,
+ utils::{establish_unpooled_connection, get_database_url_from_env},
};
use lemmy_utils::{
rate_limit::{rate_limiter::RateLimiter, RateLimit},
- request::build_user_agent,
settings::structs::Settings,
LemmyError,
};
},
};
use chrono::NaiveDateTime;
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::{
object_id::ObjectId,
traits::{ActorType, ApubObject},
verify::verify_domains_match,
};
use lemmy_db_schema::{
- naive_now,
source::person::{Person as DbPerson, PersonForm},
traits::ApubActor,
+ utils::naive_now,
};
use lemmy_utils::{
utils::{check_slurs, check_slurs_opt, convert_datetime, markdown_to_html},
};
use activitystreams_kinds::public;
use chrono::NaiveDateTime;
-use lemmy_api_common::blocking;
+use lemmy_api_common::{request::fetch_site_data, utils::blocking};
use lemmy_apub_lib::{
object_id::ObjectId,
traits::ApubObject,
traits::Crud,
};
use lemmy_utils::{
- request::fetch_site_data,
utils::{check_slurs, convert_datetime, markdown_to_html, remove_slurs},
LemmyError,
};
},
};
use chrono::NaiveDateTime;
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::{
object_id::ObjectId,
traits::ApubObject,
use crate::generate_followers_url;
use activitystreams_kinds::collection::CollectionType;
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_db_schema::source::community::Community;
-use lemmy_db_views_actor::community_follower_view::CommunityFollowerView;
+use lemmy_db_views_actor::structs::CommunityFollowerView;
use lemmy_utils::LemmyError;
use lemmy_websocket::LemmyContext;
use serde::{Deserialize, Serialize};
use activitystreams_kinds::actor::GroupType;
use chrono::{DateTime, FixedOffset};
use lemmy_apub_lib::{object_id::ObjectId, signatures::PublicKey, verify::verify_domains_match};
-use lemmy_db_schema::{naive_now, source::community::CommunityForm};
+use lemmy_db_schema::{source::community::CommunityForm, utils::naive_now};
use lemmy_utils::{
utils::{check_slurs, check_slurs_opt},
LemmyError,
};
use activitystreams_kinds::object::NoteType;
use chrono::{DateTime, FixedOffset};
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub_lib::{object_id::ObjectId, values::MediaTypeHtml};
use lemmy_db_schema::{newtypes::CommentId, source::post::Post, traits::Crud};
use lemmy_utils::LemmyError;
[dependencies]
lemmy_utils = { version = "=0.16.3", path = "../utils" }
lemmy_apub_lib_derive = { version = "=0.16.3", path = "../apub_lib_derive" }
-chrono = "0.4.19"
+chrono = { version = "0.4.19", default-features = false }
serde = { version = "1.0.136", features = ["derive"] }
async-trait = "0.1.53"
url = { version = "2.2.2", features = ["serde"] }
path = "src/lib.rs"
doctest = false
+[features]
+full = ["diesel", "diesel-derive-newtype", "diesel_migrations", "bcrypt", "lemmy_utils",
+ "lemmy_apub_lib", "strum", "strum_macros", "sha2", "regex", "once_cell", "serde_json"]
+
[dependencies]
-lemmy_utils = { version = "=0.16.3", path = "../utils" }
-lemmy_apub_lib = { version = "=0.16.3", path = "../apub_lib" }
-diesel = { version = "1.4.8", features = ["postgres","chrono","r2d2","serde_json"] }
-diesel_migrations = "1.4.0"
-chrono = { version = "0.4.19", features = ["serde"] }
+chrono = { version = "0.4.19", features = ["serde"], default-features = false }
serde = { version = "1.0.136", features = ["derive"] }
-serde_json = { version = "1.0.79", features = ["preserve_order"] }
url = { version = "2.2.2", features = ["serde"] }
-diesel-derive-newtype = "0.1.2"
-regex = "1.5.5"
-once_cell = "1.10.0"
-strum = "0.24.0"
-strum_macros = "0.24.0"
-sha2 = "0.10.2"
-bcrypt = "0.12.1"
+serde_json = { version = "1.0.79", features = ["preserve_order"], optional = true }
+lemmy_apub_lib = { version = "=0.16.3", path = "../apub_lib", optional = true }
+lemmy_utils = { version = "=0.16.3", path = "../utils", optional = true }
+bcrypt = { version = "0.12.1", optional = true }
+diesel = { version = "1.4.8", features = ["postgres","chrono","r2d2","serde_json"], optional = true }
+diesel-derive-newtype = { version = "0.1.2", optional = true }
+diesel_migrations = { version = "1.4.0", optional = true }
+strum = { version = "0.24.0", optional = true }
+strum_macros = { version = "0.24.0", optional = true }
+sha2 = { version = "0.10.2", optional = true }
+regex = { version = "1.5.5", optional = true }
+once_cell = { version = "1.10.0", optional = true }
[dev-dependencies]
serial_test = "0.6.0"
-use crate::{newtypes::CommentId, schema::comment_aggregates};
+use crate::{
+ aggregates::structs::CommentAggregates,
+ newtypes::CommentId,
+ schema::comment_aggregates,
+};
use diesel::{result::Error, *};
-use serde::{Deserialize, Serialize};
-
-#[derive(
- Queryable, Associations, Identifiable, PartialEq, Debug, Serialize, Deserialize, Clone,
-)]
-#[table_name = "comment_aggregates"]
-pub struct CommentAggregates {
- pub id: i32,
- pub comment_id: CommentId,
- pub score: i64,
- pub upvotes: i64,
- pub downvotes: i64,
- pub published: chrono::NaiveDateTime,
-}
impl CommentAggregates {
pub fn read(conn: &PgConnection, comment_id: CommentId) -> Result<Self, Error> {
mod tests {
use crate::{
aggregates::comment_aggregates::CommentAggregates,
- establish_unpooled_connection,
source::{
comment::{Comment, CommentForm, CommentLike, CommentLikeForm},
community::{Community, CommunityForm},
post::{Post, PostForm},
},
traits::{Crud, Likeable},
+ utils::establish_unpooled_connection,
};
use serial_test::serial;
-use crate::{newtypes::CommunityId, schema::community_aggregates};
+use crate::{
+ aggregates::structs::CommunityAggregates,
+ newtypes::CommunityId,
+ schema::community_aggregates,
+};
use diesel::{result::Error, *};
-use serde::{Deserialize, Serialize};
-
-#[derive(
- Queryable, Associations, Identifiable, PartialEq, Debug, Serialize, Deserialize, Clone,
-)]
-#[table_name = "community_aggregates"]
-pub struct CommunityAggregates {
- pub id: i32,
- pub community_id: CommunityId,
- pub subscribers: i64,
- pub posts: i64,
- pub comments: i64,
- pub published: chrono::NaiveDateTime,
- pub users_active_day: i64,
- pub users_active_week: i64,
- pub users_active_month: i64,
- pub users_active_half_year: i64,
-}
impl CommunityAggregates {
pub fn read(conn: &PgConnection, community_id: CommunityId) -> Result<Self, Error> {
mod tests {
use crate::{
aggregates::community_aggregates::CommunityAggregates,
- establish_unpooled_connection,
source::{
comment::{Comment, CommentForm},
community::{Community, CommunityFollower, CommunityFollowerForm, CommunityForm},
post::{Post, PostForm},
},
traits::{Crud, Followable},
+ utils::establish_unpooled_connection,
};
use serial_test::serial;
+#[cfg(feature = "full")]
pub mod comment_aggregates;
+#[cfg(feature = "full")]
pub mod community_aggregates;
+#[cfg(feature = "full")]
pub mod person_aggregates;
+#[cfg(feature = "full")]
pub mod post_aggregates;
+#[cfg(feature = "full")]
pub mod site_aggregates;
+pub mod structs;
-use crate::{newtypes::PersonId, schema::person_aggregates};
+use crate::{aggregates::structs::PersonAggregates, newtypes::PersonId, schema::person_aggregates};
use diesel::{result::Error, *};
-use serde::{Deserialize, Serialize};
-
-#[derive(
- Queryable, Associations, Identifiable, PartialEq, Debug, Serialize, Deserialize, Clone, Default,
-)]
-#[table_name = "person_aggregates"]
-pub struct PersonAggregates {
- pub id: i32,
- pub person_id: PersonId,
- pub post_count: i64,
- pub post_score: i64,
- pub comment_count: i64,
- pub comment_score: i64,
-}
impl PersonAggregates {
pub fn read(conn: &PgConnection, person_id: PersonId) -> Result<Self, Error> {
mod tests {
use crate::{
aggregates::person_aggregates::PersonAggregates,
- establish_unpooled_connection,
source::{
comment::{Comment, CommentForm, CommentLike, CommentLikeForm},
community::{Community, CommunityForm},
post::{Post, PostForm, PostLike, PostLikeForm},
},
traits::{Crud, Likeable},
+ utils::establish_unpooled_connection,
};
use serial_test::serial;
-use crate::{newtypes::PostId, schema::post_aggregates};
+use crate::{aggregates::structs::PostAggregates, newtypes::PostId, schema::post_aggregates};
use diesel::{result::Error, *};
-use serde::{Deserialize, Serialize};
-
-#[derive(
- Queryable, Associations, Identifiable, PartialEq, Debug, Serialize, Deserialize, Clone,
-)]
-#[table_name = "post_aggregates"]
-pub struct PostAggregates {
- pub id: i32,
- pub post_id: PostId,
- pub comments: i64,
- pub score: i64,
- pub upvotes: i64,
- pub downvotes: i64,
- pub stickied: bool,
- pub published: chrono::NaiveDateTime,
- pub newest_comment_time_necro: chrono::NaiveDateTime, // A newest comment time, limited to 2 days, to prevent necrobumping
- pub newest_comment_time: chrono::NaiveDateTime,
-}
impl PostAggregates {
pub fn read(conn: &PgConnection, post_id: PostId) -> Result<Self, Error> {
mod tests {
use crate::{
aggregates::post_aggregates::PostAggregates,
- establish_unpooled_connection,
source::{
comment::{Comment, CommentForm},
community::{Community, CommunityForm},
post::{Post, PostForm, PostLike, PostLikeForm},
},
traits::{Crud, Likeable},
+ utils::establish_unpooled_connection,
};
use serial_test::serial;
-use crate::schema::site_aggregates;
+use crate::{aggregates::structs::SiteAggregates, schema::site_aggregates};
use diesel::{result::Error, *};
-use serde::{Deserialize, Serialize};
-
-#[derive(
- Queryable, Associations, Identifiable, PartialEq, Debug, Serialize, Deserialize, Clone,
-)]
-#[table_name = "site_aggregates"]
-pub struct SiteAggregates {
- pub id: i32,
- pub site_id: i32,
- pub users: i64,
- pub posts: i64,
- pub comments: i64,
- pub communities: i64,
- pub users_active_day: i64,
- pub users_active_week: i64,
- pub users_active_month: i64,
- pub users_active_half_year: i64,
-}
impl SiteAggregates {
pub fn read(conn: &PgConnection) -> Result<Self, Error> {
mod tests {
use crate::{
aggregates::site_aggregates::SiteAggregates,
- establish_unpooled_connection,
source::{
comment::{Comment, CommentForm},
community::{Community, CommunityForm},
site::{Site, SiteForm},
},
traits::Crud,
+ utils::establish_unpooled_connection,
};
use serial_test::serial;
--- /dev/null
+use crate::newtypes::{CommentId, CommunityId, PersonId, PostId};
+use serde::{Deserialize, Serialize};
+
+#[cfg(feature = "full")]
+use crate::schema::{
+ comment_aggregates,
+ community_aggregates,
+ person_aggregates,
+ post_aggregates,
+ site_aggregates,
+};
+
+#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
+#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "comment_aggregates")]
+pub struct CommentAggregates {
+ pub id: i32,
+ pub comment_id: CommentId,
+ pub score: i64,
+ pub upvotes: i64,
+ pub downvotes: i64,
+ pub published: chrono::NaiveDateTime,
+}
+
+#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
+#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "community_aggregates")]
+pub struct CommunityAggregates {
+ pub id: i32,
+ pub community_id: CommunityId,
+ pub subscribers: i64,
+ pub posts: i64,
+ pub comments: i64,
+ pub published: chrono::NaiveDateTime,
+ pub users_active_day: i64,
+ pub users_active_week: i64,
+ pub users_active_month: i64,
+ pub users_active_half_year: i64,
+}
+
+#[derive(PartialEq, Debug, Serialize, Deserialize, Clone, Default)]
+#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "person_aggregates")]
+pub struct PersonAggregates {
+ pub id: i32,
+ pub person_id: PersonId,
+ pub post_count: i64,
+ pub post_score: i64,
+ pub comment_count: i64,
+ pub comment_score: i64,
+}
+
+#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
+#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "post_aggregates")]
+pub struct PostAggregates {
+ pub id: i32,
+ pub post_id: PostId,
+ pub comments: i64,
+ pub score: i64,
+ pub upvotes: i64,
+ pub downvotes: i64,
+ pub stickied: bool,
+ pub published: chrono::NaiveDateTime,
+ pub newest_comment_time_necro: chrono::NaiveDateTime, // A newest comment time, limited to 2 days, to prevent necrobumping
+ pub newest_comment_time: chrono::NaiveDateTime,
+}
+
+#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
+#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "site_aggregates")]
+pub struct SiteAggregates {
+ pub id: i32,
+ pub site_id: i32,
+ pub users: i64,
+ pub posts: i64,
+ pub comments: i64,
+ pub communities: i64,
+ pub users_active_day: i64,
+ pub users_active_week: i64,
+ pub users_active_month: i64,
+ pub users_active_half_year: i64,
+}
mod tests {
use super::*;
use crate::{
- establish_unpooled_connection,
newtypes::DbUrl,
source::{
activity::{Activity, ActivityForm},
person::{Person, PersonForm},
},
+ utils::establish_unpooled_connection,
};
use serde_json::Value;
use serial_test::serial;
use crate::{
- naive_now,
newtypes::{CommentId, DbUrl, PersonId},
source::comment::{
Comment,
CommentSavedForm,
},
traits::{Crud, DeleteableOrRemoveable, Likeable, Saveable},
+ utils::naive_now,
};
use diesel::{dsl::*, result::Error, *};
use url::Url;
#[cfg(test)]
mod tests {
use crate::{
- establish_unpooled_connection,
source::{
comment::*,
community::{Community, CommunityForm},
post::*,
},
traits::{Crud, Likeable, Saveable},
+ utils::establish_unpooled_connection,
};
use serial_test::serial;
use crate::{
- naive_now,
newtypes::{CommentReportId, PersonId},
source::comment_report::{CommentReport, CommentReportForm},
traits::Reportable,
+ utils::naive_now,
};
use diesel::{dsl::*, result::Error, *};
use crate::{
- functions::lower,
- naive_now,
newtypes::{CommunityId, DbUrl, PersonId},
source::community::{
Community,
CommunitySafe,
},
traits::{ApubActor, Bannable, Crud, DeleteableOrRemoveable, Followable, Joinable},
+ utils::{functions::lower, naive_now},
};
use diesel::{
dsl::*,
#[cfg(test)]
mod tests {
use crate::{
- establish_unpooled_connection,
source::{community::*, person::*},
traits::{Bannable, Crud, Followable, Joinable},
+ utils::establish_unpooled_connection,
};
use serial_test::serial;
use crate::{
- naive_now,
newtypes::LocalUserId,
schema::local_user::dsl::*,
source::local_user::{LocalUser, LocalUserForm},
traits::Crud,
+ utils::naive_now,
};
use bcrypt::{hash, DEFAULT_COST};
use diesel::{dsl::*, result::Error, *};
#[cfg(test)]
mod tests {
use crate::{
- establish_unpooled_connection,
source::{comment::*, community::*, moderator::*, person::*, post::*},
traits::Crud,
+ utils::establish_unpooled_connection,
};
use serial_test::serial;
#[cfg(test)]
mod tests {
use crate::{
- establish_unpooled_connection,
source::{
local_user::{LocalUser, LocalUserForm},
password_reset_request::PasswordResetRequest,
person::*,
},
traits::Crud,
+ utils::establish_unpooled_connection,
};
use serial_test::serial;
use crate::{
- functions::lower,
- naive_now,
newtypes::{DbUrl, PersonId},
schema::person::dsl::*,
source::person::{Person, PersonForm, PersonSafe},
traits::{ApubActor, Crud},
+ utils::{functions::lower, naive_now},
};
use diesel::{
dsl::*,
#[cfg(test)]
mod tests {
- use crate::{establish_unpooled_connection, source::person::*, traits::Crud};
+ use crate::{source::person::*, traits::Crud, utils::establish_unpooled_connection};
#[test]
fn test_crud() {
#[cfg(test)]
mod tests {
use crate::{
- establish_unpooled_connection,
source::{
comment::*,
community::{Community, CommunityForm},
post::*,
},
traits::Crud,
+ utils::establish_unpooled_connection,
};
use serial_test::serial;
use crate::{
- naive_now,
newtypes::{CommunityId, DbUrl, PersonId, PostId},
source::post::{
Post,
PostSavedForm,
},
traits::{Crud, DeleteableOrRemoveable, Likeable, Readable, Saveable},
+ utils::naive_now,
};
use diesel::{dsl::*, result::Error, ExpressionMethods, PgConnection, QueryDsl, RunQueryDsl};
use url::Url;
#[cfg(test)]
mod tests {
use crate::{
- establish_unpooled_connection,
source::{
community::{Community, CommunityForm},
person::*,
post::*,
},
traits::{Crud, Likeable, Readable, Saveable},
+ utils::establish_unpooled_connection,
};
use serial_test::serial;
use crate::{
- naive_now,
newtypes::{PersonId, PostReportId},
source::post_report::*,
traits::Reportable,
+ utils::naive_now,
};
use diesel::{dsl::*, result::Error, *};
use crate::{
- naive_now,
newtypes::{DbUrl, PersonId, PrivateMessageId},
source::private_message::*,
traits::{Crud, DeleteableOrRemoveable},
+ utils::naive_now,
};
use diesel::{dsl::*, result::Error, *};
use lemmy_utils::LemmyError;
#[cfg(test)]
mod tests {
use crate::{
- establish_unpooled_connection,
source::{person::*, private_message::*},
traits::Crud,
+ utils::establish_unpooled_connection,
};
use serial_test::serial;
-use crate::{source::site::*, traits::Crud, DbUrl};
+use crate::{newtypes::DbUrl, source::site::*, traits::Crud};
use diesel::{dsl::*, result::Error, *};
use url::Url;
+#[cfg(feature = "full")]
+#[macro_use]
+extern crate strum_macros;
+#[cfg(feature = "full")]
#[macro_use]
extern crate diesel;
+#[cfg(feature = "full")]
#[macro_use]
extern crate diesel_derive_newtype;
// this is used in tests
+#[cfg(feature = "full")]
#[allow(unused_imports)]
#[macro_use]
extern crate diesel_migrations;
-#[macro_use]
-extern crate strum_macros;
pub mod aggregates;
+#[cfg(feature = "full")]
pub mod impls;
pub mod newtypes;
+#[cfg(feature = "full")]
pub mod schema;
pub mod source;
+#[cfg(feature = "full")]
pub mod traits;
-
-pub type DbPool = diesel::r2d2::Pool<diesel::r2d2::ConnectionManager<diesel::PgConnection>>;
-
-use crate::newtypes::DbUrl;
-use chrono::NaiveDateTime;
-use diesel::{Connection, PgConnection};
-use lemmy_utils::LemmyError;
-use once_cell::sync::Lazy;
-use regex::Regex;
-use serde::{Deserialize, Serialize};
-use std::{env, env::VarError};
-use url::Url;
-
-pub fn get_database_url_from_env() -> Result<String, VarError> {
- env::var("LEMMY_DATABASE_URL")
-}
-
-#[derive(EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy)]
-pub enum SortType {
- Active,
- Hot,
- New,
- TopDay,
- TopWeek,
- TopMonth,
- TopYear,
- TopAll,
- MostComments,
- NewComments,
-}
-
-#[derive(EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq)]
-pub enum ListingType {
- All,
- Local,
- Subscribed,
- Community,
-}
-
-#[derive(EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy)]
-pub enum SearchType {
- All,
- Comments,
- Posts,
- Communities,
- Users,
- Url,
-}
-
-pub fn from_opt_str_to_opt_enum<T: std::str::FromStr>(opt: &Option<String>) -> Option<T> {
- opt.as_ref().and_then(|t| T::from_str(t).ok())
-}
-
-pub fn fuzzy_search(q: &str) -> String {
- let replaced = q.replace('%', "\\%").replace('_', "\\_").replace(' ', "%");
- format!("%{}%", replaced)
-}
-
-pub fn limit_and_offset(page: Option<i64>, limit: Option<i64>) -> (i64, i64) {
- let page = page.unwrap_or(1);
- let limit = limit.unwrap_or(10);
- let offset = limit * (page - 1);
- (limit, offset)
-}
-
-pub fn is_email_regex(test: &str) -> bool {
- EMAIL_REGEX.is_match(test)
-}
-
-pub fn diesel_option_overwrite(opt: &Option<String>) -> Option<Option<String>> {
- match opt {
- // An empty string is an erase
- Some(unwrapped) => {
- if !unwrapped.eq("") {
- Some(Some(unwrapped.to_owned()))
- } else {
- Some(None)
- }
- }
- None => None,
- }
-}
-
-pub fn diesel_option_overwrite_to_url(
- opt: &Option<String>,
-) -> Result<Option<Option<DbUrl>>, LemmyError> {
- match opt.as_ref().map(|s| s.as_str()) {
- // An empty string is an erase
- Some("") => Ok(Some(None)),
- Some(str_url) => match Url::parse(str_url) {
- Ok(url) => Ok(Some(Some(url.into()))),
- Err(e) => Err(LemmyError::from_error_message(e, "invalid_url")),
- },
- None => Ok(None),
- }
-}
-
-embed_migrations!();
-
-pub fn establish_unpooled_connection() -> PgConnection {
- let db_url = match get_database_url_from_env() {
- Ok(url) => url,
- Err(e) => panic!(
- "Failed to read database URL from env var LEMMY_DATABASE_URL: {}",
- e
- ),
- };
- let conn =
- PgConnection::establish(&db_url).unwrap_or_else(|_| panic!("Error connecting to {}", db_url));
- embedded_migrations::run(&conn).expect("load migrations");
- conn
-}
-
-pub fn naive_now() -> NaiveDateTime {
- chrono::prelude::Utc::now().naive_utc()
-}
-
-static EMAIL_REGEX: Lazy<Regex> = Lazy::new(|| {
- Regex::new(r"^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$")
- .expect("compile email regex")
-});
-
-pub mod functions {
- use diesel::sql_types::*;
-
- sql_function! {
- fn hot_rank(score: BigInt, time: Timestamp) -> Integer;
- }
-
- sql_function!(fn lower(x: Text) -> Text);
-}
-
-#[cfg(test)]
-mod tests {
- use super::{fuzzy_search, *};
- use crate::is_email_regex;
-
- #[test]
- fn test_fuzzy_search() {
- let test = "This %is% _a_ fuzzy search";
- assert_eq!(
- fuzzy_search(test),
- "%This%\\%is\\%%\\_a\\_%fuzzy%search%".to_string()
- );
- }
-
- #[test]
- fn test_email() {
- assert!(is_email_regex("gush@gmail.com"));
- assert!(!is_email_regex("nada_neutho"));
- }
-
- #[test]
- fn test_diesel_option_overwrite() {
- assert_eq!(diesel_option_overwrite(&None), None);
- assert_eq!(diesel_option_overwrite(&Some("".to_string())), Some(None));
- assert_eq!(
- diesel_option_overwrite(&Some("test".to_string())),
- Some(Some("test".to_string()))
- );
- }
-
- #[test]
- fn test_diesel_option_overwrite_to_url() {
- assert!(matches!(diesel_option_overwrite_to_url(&None), Ok(None)));
- assert!(matches!(
- diesel_option_overwrite_to_url(&Some("".to_string())),
- Ok(Some(None))
- ));
- assert!(matches!(
- diesel_option_overwrite_to_url(&Some("invalid_url".to_string())),
- Err(_)
- ));
- let example_url = "https://example.com";
- assert!(matches!(
- diesel_option_overwrite_to_url(&Some(example_url.to_string())),
- Ok(Some(Some(url))) if url == Url::parse(example_url).unwrap().into()
- ));
- }
-}
+#[cfg(feature = "full")]
+pub mod utils;
-use diesel::{
- backend::Backend,
- deserialize::FromSql,
- serialize::{Output, ToSql},
- sql_types::Text,
-};
-use lemmy_apub_lib::{object_id::ObjectId, traits::ApubObject};
use serde::{Deserialize, Serialize};
use std::{
fmt,
fmt::{Display, Formatter},
- io::Write,
ops::Deref,
};
use url::Url;
-#[derive(
- Debug, Copy, Clone, Hash, Eq, PartialEq, Default, Serialize, Deserialize, DieselNewType,
-)]
+#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Default, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(DieselNewType))]
pub struct PostId(pub i32);
impl fmt::Display for PostId {
}
}
-#[derive(
- Debug, Copy, Clone, Hash, Eq, PartialEq, Default, Serialize, Deserialize, DieselNewType,
-)]
+#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Default, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(DieselNewType))]
pub struct PersonId(pub i32);
-#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, DieselNewType)]
+#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(DieselNewType))]
pub struct CommentId(pub i32);
impl fmt::Display for CommentId {
}
}
-#[derive(
- Debug, Copy, Clone, Hash, Eq, PartialEq, Default, Serialize, Deserialize, DieselNewType,
-)]
+#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Default, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(DieselNewType))]
pub struct CommunityId(pub i32);
-#[derive(
- Debug, Copy, Clone, Hash, Eq, PartialEq, Default, Serialize, Deserialize, DieselNewType,
-)]
+#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Default, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(DieselNewType))]
pub struct LocalUserId(pub i32);
-#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, DieselNewType)]
+#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(DieselNewType))]
pub struct PrivateMessageId(i32);
impl fmt::Display for PrivateMessageId {
}
}
-#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, DieselNewType)]
+#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(DieselNewType))]
pub struct PersonMentionId(i32);
-#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, DieselNewType)]
+#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(DieselNewType))]
pub struct PersonBlockId(i32);
-#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, DieselNewType)]
+#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(DieselNewType))]
pub struct CommunityBlockId(i32);
-#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, DieselNewType)]
+#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(DieselNewType))]
pub struct CommentReportId(i32);
-#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize, DieselNewType)]
+#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(DieselNewType))]
pub struct PostReportId(i32);
#[repr(transparent)]
-#[derive(Clone, PartialEq, Serialize, Deserialize, Debug, AsExpression, FromSqlRow)]
-#[sql_type = "Text"]
-pub struct DbUrl(Url);
-
-impl<DB: Backend> ToSql<Text, DB> for DbUrl
-where
- String: ToSql<Text, DB>,
-{
- fn to_sql<W: Write>(&self, out: &mut Output<W, DB>) -> diesel::serialize::Result {
- self.0.to_string().to_sql(out)
- }
-}
-
-impl<DB: Backend> FromSql<Text, DB> for DbUrl
-where
- String: FromSql<Text, DB>,
-{
- fn from_sql(bytes: Option<&DB::RawValue>) -> diesel::deserialize::Result<Self> {
- let str = String::from_sql(bytes)?;
- Ok(DbUrl(Url::parse(&str)?))
- }
-}
+#[derive(Clone, PartialEq, Serialize, Deserialize, Debug)]
+#[cfg_attr(feature = "full", derive(AsExpression, FromSqlRow))]
+#[cfg_attr(feature = "full", sql_type = "diesel::sql_types::Text")]
+pub struct DbUrl(pub(crate) Url);
impl Display for DbUrl {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
}
}
-impl<Kind> From<ObjectId<Kind>> for DbUrl
-where
- Kind: ApubObject + Send + 'static,
- for<'de2> <Kind as ApubObject>::ApubType: serde::Deserialize<'de2>,
-{
- fn from(id: ObjectId<Kind>) -> Self {
- DbUrl(id.into())
- }
-}
-
impl Deref for DbUrl {
type Target = Url;
use serde_json::Value;
use std::fmt::Debug;
-#[derive(Queryable, Identifiable, PartialEq, Debug)]
+#[derive(PartialEq, Debug, Queryable, Identifiable)]
#[table_name = "activity"]
pub struct Activity {
pub id: i32,
-use crate::{
- newtypes::{CommentId, DbUrl, PersonId, PostId},
- schema::{comment, comment_alias_1, comment_like, comment_saved},
- source::post::Post,
-};
+use crate::newtypes::{CommentId, DbUrl, PersonId, PostId};
use serde::{Deserialize, Serialize};
+#[cfg(feature = "full")]
+use crate::schema::{comment, comment_alias_1, comment_like, comment_saved};
+
// WITH RECURSIVE MyTree AS (
// SELECT * FROM comment WHERE parent_id IS NULL
// UNION ALL
// )
// SELECT * FROM MyTree;
-#[derive(
- Clone, Queryable, Associations, Identifiable, PartialEq, Debug, Serialize, Deserialize,
-)]
-#[belongs_to(Post)]
-#[table_name = "comment"]
+#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable))]
+#[cfg_attr(feature = "full", belongs_to(crate::source::post::Post))]
+#[cfg_attr(feature = "full", table_name = "comment")]
pub struct Comment {
pub id: CommentId,
pub creator_id: PersonId,
pub local: bool,
}
-#[derive(
- Clone, Queryable, Associations, Identifiable, PartialEq, Debug, Serialize, Deserialize,
-)]
-#[belongs_to(Post)]
-#[table_name = "comment_alias_1"]
+#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable))]
+#[cfg_attr(feature = "full", belongs_to(crate::source::post::Post))]
+#[cfg_attr(feature = "full", table_name = "comment_alias_1")]
pub struct CommentAlias1 {
pub id: CommentId,
pub creator_id: PersonId,
pub local: bool,
}
-#[derive(Insertable, AsChangeset, Clone, Default)]
-#[table_name = "comment"]
+#[derive(Clone, Default)]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "comment")]
pub struct CommentForm {
pub creator_id: PersonId,
pub post_id: PostId,
pub local: Option<bool>,
}
-#[derive(Identifiable, Queryable, Associations, PartialEq, Debug, Clone)]
-#[belongs_to(Comment)]
-#[table_name = "comment_like"]
+#[derive(PartialEq, Debug, Clone)]
+#[cfg_attr(feature = "full", derive(Identifiable, Queryable, Associations))]
+#[cfg_attr(feature = "full", belongs_to(Comment))]
+#[cfg_attr(feature = "full", table_name = "comment_like")]
pub struct CommentLike {
pub id: i32,
pub person_id: PersonId,
pub published: chrono::NaiveDateTime,
}
-#[derive(Insertable, AsChangeset, Clone)]
-#[table_name = "comment_like"]
+#[derive(Clone)]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "comment_like")]
pub struct CommentLikeForm {
pub person_id: PersonId,
pub comment_id: CommentId,
pub score: i16,
}
-#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
-#[belongs_to(Comment)]
-#[table_name = "comment_saved"]
+#[derive(PartialEq, Debug)]
+#[cfg_attr(feature = "full", derive(Identifiable, Queryable, Associations))]
+#[cfg_attr(feature = "full", belongs_to(Comment))]
+#[cfg_attr(feature = "full", table_name = "comment_saved")]
pub struct CommentSaved {
pub id: i32,
pub comment_id: CommentId,
pub published: chrono::NaiveDateTime,
}
-#[derive(Insertable, AsChangeset)]
-#[table_name = "comment_saved"]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "comment_saved")]
pub struct CommentSavedForm {
pub comment_id: CommentId,
pub person_id: PersonId,
-use crate::{
- newtypes::{CommentId, CommentReportId, PersonId},
- schema::comment_report,
- source::comment::Comment,
-};
+use crate::newtypes::{CommentId, CommentReportId, PersonId};
use serde::{Deserialize, Serialize};
-#[derive(
- Identifiable, Queryable, Associations, PartialEq, Serialize, Deserialize, Debug, Clone,
-)]
-#[belongs_to(Comment)]
-#[table_name = "comment_report"]
+#[cfg(feature = "full")]
+use crate::schema::comment_report;
+
+#[derive(PartialEq, Serialize, Deserialize, Debug, Clone)]
+#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable))]
+#[cfg_attr(feature = "full", belongs_to(crate::source::comment::Comment))]
+#[cfg_attr(feature = "full", table_name = "comment_report")]
pub struct CommentReport {
pub id: CommentReportId,
pub creator_id: PersonId,
pub updated: Option<chrono::NaiveDateTime>,
}
-#[derive(Insertable, AsChangeset, Clone)]
-#[table_name = "comment_report"]
+#[derive(Clone)]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "comment_report")]
pub struct CommentReportForm {
pub creator_id: PersonId,
pub comment_id: CommentId,
-use crate::{
- newtypes::{CommunityId, DbUrl, PersonId},
- schema::{community, community_follower, community_moderator, community_person_ban},
-};
+use crate::newtypes::{CommunityId, DbUrl, PersonId};
use serde::{Deserialize, Serialize};
-#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
-#[table_name = "community"]
+#[cfg(feature = "full")]
+use crate::schema::{community, community_follower, community_moderator, community_person_ban};
+
+#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "community")]
pub struct Community {
pub id: CommunityId,
pub name: String,
}
/// A safe representation of community, without the sensitive info
-#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
-#[table_name = "community"]
+#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "community")]
pub struct CommunitySafe {
pub id: CommunityId,
pub name: String,
pub posting_restricted_to_mods: bool,
}
-#[derive(Insertable, AsChangeset, Debug, Default)]
-#[table_name = "community"]
+#[derive(Debug, Default)]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "community")]
pub struct CommunityForm {
pub name: String,
pub title: String,
pub posting_restricted_to_mods: Option<bool>,
}
-#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
-#[belongs_to(Community)]
-#[table_name = "community_moderator"]
+#[derive(PartialEq, Debug)]
+#[cfg_attr(feature = "full", derive(Identifiable, Queryable, Associations))]
+#[cfg_attr(feature = "full", belongs_to(Community))]
+#[cfg_attr(feature = "full", table_name = "community_moderator")]
pub struct CommunityModerator {
pub id: i32,
pub community_id: CommunityId,
pub published: chrono::NaiveDateTime,
}
-#[derive(Insertable, AsChangeset, Clone)]
-#[table_name = "community_moderator"]
+#[derive(Clone)]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "community_moderator")]
pub struct CommunityModeratorForm {
pub community_id: CommunityId,
pub person_id: PersonId,
}
-#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
-#[belongs_to(Community)]
-#[table_name = "community_person_ban"]
+#[derive(PartialEq, Debug)]
+#[cfg_attr(feature = "full", derive(Identifiable, Queryable, Associations))]
+#[cfg_attr(feature = "full", belongs_to(Community))]
+#[cfg_attr(feature = "full", table_name = "community_person_ban")]
pub struct CommunityPersonBan {
pub id: i32,
pub community_id: CommunityId,
pub expires: Option<chrono::NaiveDateTime>,
}
-#[derive(Insertable, AsChangeset, Clone)]
-#[table_name = "community_person_ban"]
+#[derive(Clone)]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "community_person_ban")]
pub struct CommunityPersonBanForm {
pub community_id: CommunityId,
pub person_id: PersonId,
pub expires: Option<Option<chrono::NaiveDateTime>>,
}
-#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
-#[belongs_to(Community)]
-#[table_name = "community_follower"]
+#[derive(PartialEq, Debug)]
+#[cfg_attr(feature = "full", derive(Identifiable, Queryable, Associations))]
+#[cfg_attr(feature = "full", belongs_to(Community))]
+#[cfg_attr(feature = "full", table_name = "community_follower")]
pub struct CommunityFollower {
pub id: i32,
pub community_id: CommunityId,
pub pending: Option<bool>,
}
-#[derive(Insertable, AsChangeset, Clone)]
-#[table_name = "community_follower"]
+#[derive(Clone)]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "community_follower")]
pub struct CommunityFollowerForm {
pub community_id: CommunityId,
pub person_id: PersonId,
-use crate::{
- newtypes::{CommunityBlockId, CommunityId, PersonId},
- schema::community_block,
- source::community::Community,
-};
+use crate::newtypes::{CommunityBlockId, CommunityId, PersonId};
use serde::{Deserialize, Serialize};
-#[derive(
- Clone, Queryable, Associations, Identifiable, PartialEq, Debug, Serialize, Deserialize,
-)]
-#[table_name = "community_block"]
-#[belongs_to(Community)]
+#[cfg(feature = "full")]
+use crate::schema::community_block;
+
+#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable))]
+#[cfg_attr(feature = "full", belongs_to(crate::source::community::Community))]
+#[cfg_attr(feature = "full", table_name = "community_block")]
pub struct CommunityBlock {
pub id: CommunityBlockId,
pub person_id: PersonId,
pub published: chrono::NaiveDateTime,
}
-#[derive(Insertable, AsChangeset)]
-#[table_name = "community_block"]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "community_block")]
pub struct CommunityBlockForm {
pub person_id: PersonId,
pub community_id: CommunityId,
-use crate::{newtypes::LocalUserId, schema::email_verification};
+use crate::newtypes::LocalUserId;
-#[derive(Queryable, Identifiable, Clone)]
-#[table_name = "email_verification"]
+#[cfg(feature = "full")]
+use crate::schema::email_verification;
+
+#[derive(Clone)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "email_verification")]
pub struct EmailVerification {
pub id: i32,
pub local_user_id: LocalUserId,
pub published: chrono::NaiveDateTime,
}
-#[derive(Insertable, AsChangeset)]
-#[table_name = "email_verification"]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "email_verification")]
pub struct EmailVerificationForm {
pub local_user_id: LocalUserId,
pub email: String,
-use crate::{
- newtypes::{LocalUserId, PersonId},
- schema::local_user,
-};
+use crate::newtypes::{LocalUserId, PersonId};
use serde::{Deserialize, Serialize};
-#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
-#[table_name = "local_user"]
+#[cfg(feature = "full")]
+use crate::schema::local_user;
+
+#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "local_user")]
pub struct LocalUser {
pub id: LocalUserId,
pub person_id: PersonId,
}
// TODO redo these, check table defaults
-#[derive(Insertable, AsChangeset, Clone, Default)]
-#[table_name = "local_user"]
+#[derive(Clone, Default)]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "local_user")]
pub struct LocalUserForm {
pub person_id: Option<PersonId>,
pub password_encrypted: Option<String>,
}
/// A local user view that removes password encrypted
-#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
-#[table_name = "local_user"]
+#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "local_user")]
pub struct LocalUserSettings {
pub id: LocalUserId,
pub person_id: PersonId,
+#[cfg(feature = "full")]
pub mod activity;
pub mod comment;
pub mod comment_report;
-use crate::{
- newtypes::{CommentId, CommunityId, PersonId, PostId},
- schema::{
- mod_add,
- mod_add_community,
- mod_ban,
- mod_ban_from_community,
- mod_hide_community,
- mod_lock_post,
- mod_remove_comment,
- mod_remove_community,
- mod_remove_post,
- mod_sticky_post,
- mod_transfer_community,
- },
-};
+use crate::newtypes::{CommentId, CommunityId, PersonId, PostId};
use serde::{Deserialize, Serialize};
-#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
-#[table_name = "mod_remove_post"]
+#[cfg(feature = "full")]
+use crate::schema::{
+ mod_add,
+ mod_add_community,
+ mod_ban,
+ mod_ban_from_community,
+ mod_hide_community,
+ mod_lock_post,
+ mod_remove_comment,
+ mod_remove_community,
+ mod_remove_post,
+ mod_sticky_post,
+ mod_transfer_community,
+};
+
+#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "mod_remove_post")]
pub struct ModRemovePost {
pub id: i32,
pub mod_person_id: PersonId,
pub when_: chrono::NaiveDateTime,
}
-#[derive(Insertable, AsChangeset)]
-#[table_name = "mod_remove_post"]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "mod_remove_post")]
pub struct ModRemovePostForm {
pub mod_person_id: PersonId,
pub post_id: PostId,
pub removed: Option<bool>,
}
-#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
-#[table_name = "mod_lock_post"]
+#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "mod_lock_post")]
pub struct ModLockPost {
pub id: i32,
pub mod_person_id: PersonId,
pub when_: chrono::NaiveDateTime,
}
-#[derive(Insertable, AsChangeset)]
-#[table_name = "mod_lock_post"]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "mod_lock_post")]
pub struct ModLockPostForm {
pub mod_person_id: PersonId,
pub post_id: PostId,
pub locked: Option<bool>,
}
-#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
-#[table_name = "mod_sticky_post"]
+#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "mod_sticky_post")]
pub struct ModStickyPost {
pub id: i32,
pub mod_person_id: PersonId,
pub when_: chrono::NaiveDateTime,
}
-#[derive(Insertable, AsChangeset)]
-#[table_name = "mod_sticky_post"]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "mod_sticky_post")]
pub struct ModStickyPostForm {
pub mod_person_id: PersonId,
pub post_id: PostId,
pub stickied: Option<bool>,
}
-#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
-#[table_name = "mod_remove_comment"]
+#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "mod_remove_comment")]
pub struct ModRemoveComment {
pub id: i32,
pub mod_person_id: PersonId,
pub when_: chrono::NaiveDateTime,
}
-#[derive(Insertable, AsChangeset)]
-#[table_name = "mod_remove_comment"]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "mod_remove_comment")]
pub struct ModRemoveCommentForm {
pub mod_person_id: PersonId,
pub comment_id: CommentId,
pub removed: Option<bool>,
}
-#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
-#[table_name = "mod_remove_community"]
+#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "mod_remove_community")]
pub struct ModRemoveCommunity {
pub id: i32,
pub mod_person_id: PersonId,
pub when_: chrono::NaiveDateTime,
}
-#[derive(Insertable, AsChangeset)]
-#[table_name = "mod_remove_community"]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "mod_remove_community")]
pub struct ModRemoveCommunityForm {
pub mod_person_id: PersonId,
pub community_id: CommunityId,
pub expires: Option<chrono::NaiveDateTime>,
}
-#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
-#[table_name = "mod_ban_from_community"]
+#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "mod_ban_from_community")]
pub struct ModBanFromCommunity {
pub id: i32,
pub mod_person_id: PersonId,
pub when_: chrono::NaiveDateTime,
}
-#[derive(Insertable, AsChangeset)]
-#[table_name = "mod_ban_from_community"]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "mod_ban_from_community")]
pub struct ModBanFromCommunityForm {
pub mod_person_id: PersonId,
pub other_person_id: PersonId,
pub expires: Option<chrono::NaiveDateTime>,
}
-#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
-#[table_name = "mod_ban"]
+#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "mod_ban")]
pub struct ModBan {
pub id: i32,
pub mod_person_id: PersonId,
pub when_: chrono::NaiveDateTime,
}
-#[derive(Insertable, AsChangeset)]
-#[table_name = "mod_hide_community"]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "mod_hide_community")]
pub struct ModHideCommunityForm {
pub community_id: CommunityId,
pub mod_person_id: PersonId,
pub hidden: Option<bool>,
pub reason: Option<String>,
}
-#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
-#[table_name = "mod_hide_community"]
+#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "mod_hide_community")]
pub struct ModHideCommunity {
pub id: i32,
pub community_id: CommunityId,
pub when_: chrono::NaiveDateTime,
}
-#[derive(Insertable, AsChangeset)]
-#[table_name = "mod_ban"]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "mod_ban")]
pub struct ModBanForm {
pub mod_person_id: PersonId,
pub other_person_id: PersonId,
pub expires: Option<chrono::NaiveDateTime>,
}
-#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
-#[table_name = "mod_add_community"]
+#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "mod_add_community")]
pub struct ModAddCommunity {
pub id: i32,
pub mod_person_id: PersonId,
pub when_: chrono::NaiveDateTime,
}
-#[derive(Insertable, AsChangeset)]
-#[table_name = "mod_add_community"]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "mod_add_community")]
pub struct ModAddCommunityForm {
pub mod_person_id: PersonId,
pub other_person_id: PersonId,
pub removed: Option<bool>,
}
-#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
-#[table_name = "mod_transfer_community"]
+#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "mod_transfer_community")]
pub struct ModTransferCommunity {
pub id: i32,
pub mod_person_id: PersonId,
pub when_: chrono::NaiveDateTime,
}
-#[derive(Insertable, AsChangeset)]
-#[table_name = "mod_transfer_community"]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "mod_transfer_community")]
pub struct ModTransferCommunityForm {
pub mod_person_id: PersonId,
pub other_person_id: PersonId,
pub removed: Option<bool>,
}
-#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
-#[table_name = "mod_add"]
+#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "mod_add")]
pub struct ModAdd {
pub id: i32,
pub mod_person_id: PersonId,
pub when_: chrono::NaiveDateTime,
}
-#[derive(Insertable, AsChangeset)]
-#[table_name = "mod_add"]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "mod_add")]
pub struct ModAddForm {
pub mod_person_id: PersonId,
pub other_person_id: PersonId,
-use crate::{newtypes::LocalUserId, schema::password_reset_request};
+use crate::newtypes::LocalUserId;
-#[derive(Queryable, Identifiable, PartialEq, Debug)]
-#[table_name = "password_reset_request"]
+#[cfg(feature = "full")]
+use crate::schema::password_reset_request;
+
+#[derive(PartialEq, Debug)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "password_reset_request")]
pub struct PasswordResetRequest {
pub id: i32,
pub token_encrypted: String,
pub local_user_id: LocalUserId,
}
-#[derive(Insertable, AsChangeset)]
-#[table_name = "password_reset_request"]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "password_reset_request")]
pub struct PasswordResetRequestForm {
pub local_user_id: LocalUserId,
pub token_encrypted: String,
-use crate::{
- newtypes::{DbUrl, PersonId},
- schema::{person, person_alias_1, person_alias_2},
-};
+use crate::newtypes::{DbUrl, PersonId};
use serde::{Deserialize, Serialize};
-#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
-#[table_name = "person"]
+#[cfg(feature = "full")]
+use crate::schema::{person, person_alias_1, person_alias_2};
+
+#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "person")]
pub struct Person {
pub id: PersonId,
pub name: String,
}
/// A safe representation of person, without the sensitive info
-#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
-#[table_name = "person"]
+#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "person")]
pub struct PersonSafe {
pub id: PersonId,
pub name: String,
pub ban_expires: Option<chrono::NaiveDateTime>,
}
-#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
-#[table_name = "person_alias_1"]
+#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "person_alias_1")]
pub struct PersonAlias1 {
pub id: PersonId,
pub name: String,
pub ban_expires: Option<chrono::NaiveDateTime>,
}
-#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
-#[table_name = "person_alias_1"]
+#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "person_alias_1")]
pub struct PersonSafeAlias1 {
pub id: PersonId,
pub name: String,
pub ban_expires: Option<chrono::NaiveDateTime>,
}
-#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
-#[table_name = "person_alias_2"]
+#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "person_alias_2")]
pub struct PersonAlias2 {
pub id: PersonId,
pub name: String,
pub ban_expires: Option<chrono::NaiveDateTime>,
}
-#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
-#[table_name = "person_alias_1"]
+#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "person_alias_1")]
pub struct PersonSafeAlias2 {
pub id: PersonId,
pub name: String,
pub ban_expires: Option<chrono::NaiveDateTime>,
}
-#[derive(Insertable, AsChangeset, Clone, Default)]
-#[table_name = "person"]
+#[derive(Clone, Default)]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "person")]
pub struct PersonForm {
pub name: String,
pub display_name: Option<Option<String>>,
-use crate::{
- newtypes::{PersonBlockId, PersonId},
- schema::person_block,
-};
+use crate::newtypes::{PersonBlockId, PersonId};
use serde::{Deserialize, Serialize};
-#[derive(
- Clone, Queryable, Associations, Identifiable, PartialEq, Debug, Serialize, Deserialize,
-)]
-#[table_name = "person_block"]
+#[cfg(feature = "full")]
+use crate::schema::person_block;
+
+#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "person_block")]
pub struct PersonBlock {
pub id: PersonBlockId,
pub person_id: PersonId,
pub published: chrono::NaiveDateTime,
}
-#[derive(Insertable, AsChangeset)]
-#[table_name = "person_block"]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "person_block")]
pub struct PersonBlockForm {
pub person_id: PersonId,
pub target_id: PersonId,
-use crate::{
- newtypes::{CommentId, PersonId, PersonMentionId},
- schema::person_mention,
- source::comment::Comment,
-};
+use crate::newtypes::{CommentId, PersonId, PersonMentionId};
use serde::{Deserialize, Serialize};
-#[derive(
- Clone, Queryable, Associations, Identifiable, PartialEq, Debug, Serialize, Deserialize,
-)]
-#[belongs_to(Comment)]
-#[table_name = "person_mention"]
+#[cfg(feature = "full")]
+use crate::schema::person_mention;
+
+#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable))]
+#[cfg_attr(feature = "full", belongs_to(crate::source::comment::Comment))]
+#[cfg_attr(feature = "full", table_name = "person_mention")]
pub struct PersonMention {
pub id: PersonMentionId,
pub recipient_id: PersonId,
pub published: chrono::NaiveDateTime,
}
-#[derive(Insertable, AsChangeset)]
-#[table_name = "person_mention"]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "person_mention")]
pub struct PersonMentionForm {
pub recipient_id: PersonId,
pub comment_id: CommentId,
-use crate::{
- newtypes::{CommunityId, DbUrl, PersonId, PostId},
- schema::{post, post_like, post_read, post_saved},
-};
+use crate::newtypes::{CommunityId, DbUrl, PersonId, PostId};
use serde::{Deserialize, Serialize};
-#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
-#[table_name = "post"]
+
+#[cfg(feature = "full")]
+use crate::schema::{post, post_like, post_read, post_saved};
+
+#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "post")]
pub struct Post {
pub id: PostId,
pub name: String,
pub local: bool,
}
-#[derive(Insertable, AsChangeset, Default)]
-#[table_name = "post"]
+#[derive(Default)]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "post")]
pub struct PostForm {
pub name: String,
pub creator_id: PersonId,
pub local: Option<bool>,
}
-#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
-#[belongs_to(Post)]
-#[table_name = "post_like"]
+#[derive(PartialEq, Debug)]
+#[cfg_attr(feature = "full", derive(Identifiable, Queryable, Associations))]
+#[cfg_attr(feature = "full", belongs_to(Post))]
+#[cfg_attr(feature = "full", table_name = "post_like")]
pub struct PostLike {
pub id: i32,
pub post_id: PostId,
pub published: chrono::NaiveDateTime,
}
-#[derive(Insertable, AsChangeset, Clone)]
-#[table_name = "post_like"]
+#[derive(Clone)]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "post_like")]
pub struct PostLikeForm {
pub post_id: PostId,
pub person_id: PersonId,
pub score: i16,
}
-#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
-#[belongs_to(Post)]
-#[table_name = "post_saved"]
+#[derive(PartialEq, Debug)]
+#[cfg_attr(feature = "full", derive(Identifiable, Queryable, Associations))]
+#[cfg_attr(feature = "full", belongs_to(Post))]
+#[cfg_attr(feature = "full", table_name = "post_saved")]
pub struct PostSaved {
pub id: i32,
pub post_id: PostId,
pub published: chrono::NaiveDateTime,
}
-#[derive(Insertable, AsChangeset)]
-#[table_name = "post_saved"]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "post_saved")]
pub struct PostSavedForm {
pub post_id: PostId,
pub person_id: PersonId,
}
-#[derive(Identifiable, Queryable, Associations, PartialEq, Debug)]
-#[belongs_to(Post)]
-#[table_name = "post_read"]
+#[derive(PartialEq, Debug)]
+#[cfg_attr(feature = "full", derive(Identifiable, Queryable, Associations))]
+#[cfg_attr(feature = "full", belongs_to(Post))]
+#[cfg_attr(feature = "full", table_name = "post_read")]
pub struct PostRead {
pub id: i32,
pub post_id: PostId,
pub published: chrono::NaiveDateTime,
}
-#[derive(Insertable, AsChangeset)]
-#[table_name = "post_read"]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "post_read")]
pub struct PostReadForm {
pub post_id: PostId,
pub person_id: PersonId,
-use crate::{
- newtypes::{DbUrl, PersonId, PostId, PostReportId},
- schema::post_report,
- source::post::Post,
-};
+use crate::newtypes::{DbUrl, PersonId, PostId, PostReportId};
use serde::{Deserialize, Serialize};
-#[derive(
- Identifiable, Queryable, Associations, PartialEq, Serialize, Deserialize, Debug, Clone,
-)]
-#[belongs_to(Post)]
-#[table_name = "post_report"]
+#[cfg(feature = "full")]
+use crate::schema::post_report;
+
+#[derive(PartialEq, Serialize, Deserialize, Debug, Clone)]
+#[cfg_attr(feature = "full", derive(Identifiable, Queryable, Associations))]
+#[cfg_attr(feature = "full", belongs_to(crate::source::post::Post))]
+#[cfg_attr(feature = "full", table_name = "post_report")]
pub struct PostReport {
pub id: PostReportId,
pub creator_id: PersonId,
pub updated: Option<chrono::NaiveDateTime>,
}
-#[derive(Insertable, AsChangeset, Clone)]
-#[table_name = "post_report"]
+#[derive(Clone)]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "post_report")]
pub struct PostReportForm {
pub creator_id: PersonId,
pub post_id: PostId,
-use crate::{
- newtypes::{DbUrl, PersonId, PrivateMessageId},
- schema::private_message,
-};
+use crate::newtypes::{DbUrl, PersonId, PrivateMessageId};
use serde::{Deserialize, Serialize};
-#[derive(
- Clone, Queryable, Associations, Identifiable, PartialEq, Debug, Serialize, Deserialize,
-)]
-#[table_name = "private_message"]
+#[cfg(feature = "full")]
+use crate::schema::private_message;
+
+#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Associations, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "private_message")]
pub struct PrivateMessage {
pub id: PrivateMessageId,
pub creator_id: PersonId,
pub local: bool,
}
-#[derive(Insertable, AsChangeset, Default)]
-#[table_name = "private_message"]
+#[derive(Default)]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "private_message")]
pub struct PrivateMessageForm {
pub creator_id: PersonId,
pub recipient_id: PersonId,
-use crate::{
- newtypes::{LocalUserId, PersonId},
- schema::registration_application,
-};
+use crate::newtypes::{LocalUserId, PersonId};
use serde::{Deserialize, Serialize};
-#[derive(Clone, Queryable, Identifiable, PartialEq, Debug, Serialize, Deserialize)]
-#[table_name = "registration_application"]
+#[cfg(feature = "full")]
+use crate::schema::registration_application;
+
+#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "registration_application")]
pub struct RegistrationApplication {
pub id: i32,
pub local_user_id: LocalUserId,
pub published: chrono::NaiveDateTime,
}
-#[derive(Insertable, AsChangeset, Default)]
-#[table_name = "registration_application"]
+#[derive(Default)]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "registration_application")]
pub struct RegistrationApplicationForm {
pub local_user_id: Option<LocalUserId>,
pub answer: Option<String>,
+#[cfg(feature = "full")]
use crate::schema::secret;
-#[derive(Queryable, Identifiable, Clone)]
-#[table_name = "secret"]
+#[derive(Clone)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "secret")]
pub struct Secret {
pub id: i32,
pub jwt_secret: String,
-use crate::{newtypes::DbUrl, schema::site};
+use crate::newtypes::DbUrl;
use serde::{Deserialize, Serialize};
-#[derive(Queryable, Identifiable, PartialEq, Debug, Clone, Serialize, Deserialize)]
-#[table_name = "site"]
+#[cfg(feature = "full")]
+use crate::schema::site;
+
+#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
+#[cfg_attr(feature = "full", derive(Queryable, Identifiable))]
+#[cfg_attr(feature = "full", table_name = "site")]
pub struct Site {
pub id: i32,
pub name: String,
pub default_post_listing_type: String,
}
-#[derive(Insertable, AsChangeset, Default)]
-#[table_name = "site"]
+#[derive(Default)]
+#[cfg_attr(feature = "full", derive(Insertable, AsChangeset))]
+#[cfg_attr(feature = "full", table_name = "site")]
pub struct SiteForm {
pub name: String,
pub sidebar: Option<Option<String>>,
-use crate::{
- newtypes::{CommunityId, PersonId},
- DbUrl,
-};
+use crate::newtypes::{CommunityId, DbUrl, PersonId};
use diesel::{result::Error, PgConnection};
pub trait Crud {
--- /dev/null
+use crate::newtypes::DbUrl;
+use chrono::NaiveDateTime;
+use diesel::{
+ backend::Backend,
+ deserialize::FromSql,
+ serialize::{Output, ToSql},
+ sql_types::Text,
+ Connection,
+ PgConnection,
+};
+use lemmy_apub_lib::{object_id::ObjectId, traits::ApubObject};
+use lemmy_utils::LemmyError;
+use once_cell::sync::Lazy;
+use regex::Regex;
+use serde::{Deserialize, Serialize};
+use std::{env, env::VarError, io::Write};
+use url::Url;
+
+pub type DbPool = diesel::r2d2::Pool<diesel::r2d2::ConnectionManager<diesel::PgConnection>>;
+
+pub fn get_database_url_from_env() -> Result<String, VarError> {
+ env::var("LEMMY_DATABASE_URL")
+}
+
+#[derive(EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy)]
+pub enum SortType {
+ Active,
+ Hot,
+ New,
+ TopDay,
+ TopWeek,
+ TopMonth,
+ TopYear,
+ TopAll,
+ MostComments,
+ NewComments,
+}
+
+#[derive(EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq)]
+pub enum ListingType {
+ All,
+ Local,
+ Subscribed,
+ Community,
+}
+
+#[derive(EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy)]
+pub enum SearchType {
+ All,
+ Comments,
+ Posts,
+ Communities,
+ Users,
+ Url,
+}
+
+pub fn from_opt_str_to_opt_enum<T: std::str::FromStr>(opt: &Option<String>) -> Option<T> {
+ opt.as_ref().and_then(|t| T::from_str(t).ok())
+}
+
+pub fn fuzzy_search(q: &str) -> String {
+ let replaced = q.replace('%', "\\%").replace('_', "\\_").replace(' ', "%");
+ format!("%{}%", replaced)
+}
+
+pub fn limit_and_offset(page: Option<i64>, limit: Option<i64>) -> (i64, i64) {
+ let page = page.unwrap_or(1);
+ let limit = limit.unwrap_or(10);
+ let offset = limit * (page - 1);
+ (limit, offset)
+}
+
+pub fn is_email_regex(test: &str) -> bool {
+ EMAIL_REGEX.is_match(test)
+}
+
+pub fn diesel_option_overwrite(opt: &Option<String>) -> Option<Option<String>> {
+ match opt {
+ // An empty string is an erase
+ Some(unwrapped) => {
+ if !unwrapped.eq("") {
+ Some(Some(unwrapped.to_owned()))
+ } else {
+ Some(None)
+ }
+ }
+ None => None,
+ }
+}
+
+pub fn diesel_option_overwrite_to_url(
+ opt: &Option<String>,
+) -> Result<Option<Option<DbUrl>>, LemmyError> {
+ match opt.as_ref().map(|s| s.as_str()) {
+ // An empty string is an erase
+ Some("") => Ok(Some(None)),
+ Some(str_url) => match Url::parse(str_url) {
+ Ok(url) => Ok(Some(Some(url.into()))),
+ Err(e) => Err(LemmyError::from_error_message(e, "invalid_url")),
+ },
+ None => Ok(None),
+ }
+}
+
+embed_migrations!();
+
+pub fn establish_unpooled_connection() -> PgConnection {
+ let db_url = match get_database_url_from_env() {
+ Ok(url) => url,
+ Err(e) => panic!(
+ "Failed to read database URL from env var LEMMY_DATABASE_URL: {}",
+ e
+ ),
+ };
+ let conn =
+ PgConnection::establish(&db_url).unwrap_or_else(|_| panic!("Error connecting to {}", db_url));
+ embedded_migrations::run(&conn).expect("load migrations");
+ conn
+}
+
+pub fn naive_now() -> NaiveDateTime {
+ chrono::prelude::Utc::now().naive_utc()
+}
+
+static EMAIL_REGEX: Lazy<Regex> = Lazy::new(|| {
+ Regex::new(r"^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$")
+ .expect("compile email regex")
+});
+
+pub mod functions {
+ use diesel::sql_types::*;
+
+ sql_function! {
+ fn hot_rank(score: BigInt, time: Timestamp) -> Integer;
+ }
+
+ sql_function!(fn lower(x: Text) -> Text);
+}
+
+impl<DB: Backend> ToSql<Text, DB> for DbUrl
+where
+ String: ToSql<Text, DB>,
+{
+ fn to_sql<W: Write>(&self, out: &mut Output<W, DB>) -> diesel::serialize::Result {
+ self.0.to_string().to_sql(out)
+ }
+}
+
+impl<DB: Backend> FromSql<Text, DB> for DbUrl
+where
+ String: FromSql<Text, DB>,
+{
+ fn from_sql(bytes: Option<&DB::RawValue>) -> diesel::deserialize::Result<Self> {
+ let str = String::from_sql(bytes)?;
+ Ok(DbUrl(Url::parse(&str)?))
+ }
+}
+
+impl<Kind> From<ObjectId<Kind>> for DbUrl
+where
+ Kind: ApubObject + Send + 'static,
+ for<'de2> <Kind as ApubObject>::ApubType: serde::Deserialize<'de2>,
+{
+ fn from(id: ObjectId<Kind>) -> Self {
+ DbUrl(id.into())
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::{fuzzy_search, *};
+ use crate::utils::is_email_regex;
+
+ #[test]
+ fn test_fuzzy_search() {
+ let test = "This %is% _a_ fuzzy search";
+ assert_eq!(
+ fuzzy_search(test),
+ "%This%\\%is\\%%\\_a\\_%fuzzy%search%".to_string()
+ );
+ }
+
+ #[test]
+ fn test_email() {
+ assert!(is_email_regex("gush@gmail.com"));
+ assert!(!is_email_regex("nada_neutho"));
+ }
+
+ #[test]
+ fn test_diesel_option_overwrite() {
+ assert_eq!(diesel_option_overwrite(&None), None);
+ assert_eq!(diesel_option_overwrite(&Some("".to_string())), Some(None));
+ assert_eq!(
+ diesel_option_overwrite(&Some("test".to_string())),
+ Some(Some("test".to_string()))
+ );
+ }
+
+ #[test]
+ fn test_diesel_option_overwrite_to_url() {
+ assert!(matches!(diesel_option_overwrite_to_url(&None), Ok(None)));
+ assert!(matches!(
+ diesel_option_overwrite_to_url(&Some("".to_string())),
+ Ok(Some(None))
+ ));
+ assert!(matches!(
+ diesel_option_overwrite_to_url(&Some("invalid_url".to_string())),
+ Err(_)
+ ));
+ let example_url = "https://example.com";
+ assert!(matches!(
+ diesel_option_overwrite_to_url(&Some(example_url.to_string())),
+ Ok(Some(Some(url))) if url == Url::parse(example_url).unwrap().into()
+ ));
+ }
+}
[lib]
doctest = false
+[features]
+full = ["lemmy_db_schema/full", "diesel", "tracing"]
+
[dependencies]
lemmy_db_schema = { version = "=0.16.3", path = "../db_schema" }
-diesel = { version = "1.4.8", features = ["postgres","chrono","r2d2","serde_json"] }
+diesel = { version = "1.4.8", features = ["postgres","chrono","r2d2","serde_json"], optional = true }
serde = { version = "1.0.136", features = ["derive"] }
-tracing = "0.1.32"
+tracing = { version = "0.1.32", optional = true }
[dev-dependencies]
serial_test = "0.6.0"
+use crate::structs::CommentReportView;
use diesel::{dsl::*, result::Error, *};
use lemmy_db_schema::{
- aggregates::comment_aggregates::CommentAggregates,
- limit_and_offset,
+ aggregates::structs::CommentAggregates,
newtypes::{CommentReportId, CommunityId, PersonId},
schema::{
comment,
post::Post,
},
traits::{MaybeOptional, ToSafe, ViewToVec},
+ utils::limit_and_offset,
};
-use serde::{Deserialize, Serialize};
-
-#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
-pub struct CommentReportView {
- pub comment_report: CommentReport,
- pub comment: Comment,
- pub post: Post,
- pub community: CommunitySafe,
- pub creator: PersonSafe,
- pub comment_creator: PersonSafeAlias1,
- pub counts: CommentAggregates,
- pub creator_banned_from_community: bool, // Left Join to CommunityPersonBan
- pub my_vote: Option<i16>, // Left join to CommentLike
- pub resolver: Option<PersonSafeAlias2>,
-}
type CommentReportViewTuple = (
CommentReport,
mod tests {
use crate::comment_report_view::{CommentReportQueryBuilder, CommentReportView};
use lemmy_db_schema::{
- aggregates::comment_aggregates::CommentAggregates,
- establish_unpooled_connection,
+ aggregates::structs::CommentAggregates,
source::{comment::*, comment_report::*, community::*, person::*, post::*},
traits::{Crud, Joinable, Reportable},
+ utils::establish_unpooled_connection,
};
use serial_test::serial;
+use crate::structs::CommentView;
use diesel::{dsl::*, result::Error, *};
use lemmy_db_schema::{
- aggregates::comment_aggregates::CommentAggregates,
- functions::hot_rank,
- fuzzy_search,
- limit_and_offset,
+ aggregates::structs::CommentAggregates,
newtypes::{CommentId, CommunityId, DbUrl, PersonId, PostId},
schema::{
comment,
post::Post,
},
traits::{MaybeOptional, ToSafe, ViewToVec},
- ListingType,
- SortType,
+ utils::{functions::hot_rank, fuzzy_search, limit_and_offset, ListingType, SortType},
};
-use serde::{Deserialize, Serialize};
-
-#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
-pub struct CommentView {
- pub comment: Comment,
- pub creator: PersonSafe,
- pub recipient: Option<PersonSafeAlias1>, // Left joins to comment and person
- pub post: Post,
- pub community: CommunitySafe,
- pub counts: CommentAggregates,
- pub creator_banned_from_community: bool, // Left Join to CommunityPersonBan
- pub subscribed: bool, // Left join to CommunityFollower
- pub saved: bool, // Left join to CommentSaved
- pub creator_blocked: bool, // Left join to PersonBlock
- pub my_vote: Option<i16>, // Left join to CommentLike
-}
type CommentViewTuple = (
Comment,
mod tests {
use crate::comment_view::*;
use lemmy_db_schema::{
- aggregates::comment_aggregates::CommentAggregates,
- establish_unpooled_connection,
+ aggregates::structs::CommentAggregates,
source::{comment::*, community::*, person::*, person_block::PersonBlockForm, post::*},
traits::{Blockable, Crud, Likeable},
+ utils::establish_unpooled_connection,
};
use serial_test::serial;
#[cfg(test)]
extern crate serial_test;
+#[cfg(feature = "full")]
pub mod comment_report_view;
+#[cfg(feature = "full")]
pub mod comment_view;
+#[cfg(feature = "full")]
pub mod local_user_view;
+#[cfg(feature = "full")]
pub mod post_report_view;
+#[cfg(feature = "full")]
pub mod post_view;
+#[cfg(feature = "full")]
pub mod private_message_view;
+#[cfg(feature = "full")]
pub mod registration_application_view;
+#[cfg(feature = "full")]
pub mod site_view;
+pub mod structs;
+use crate::structs::{LocalUserSettingsView, LocalUserView};
use diesel::{result::Error, *};
use lemmy_db_schema::{
- aggregates::person_aggregates::PersonAggregates,
- functions::lower,
+ aggregates::structs::PersonAggregates,
newtypes::{LocalUserId, PersonId},
schema::{local_user, person, person_aggregates},
source::{
person::{Person, PersonSafe},
},
traits::{ToSafe, ToSafeSettings},
+ utils::functions::lower,
};
-use serde::{Deserialize, Serialize};
-
-#[derive(Debug, Serialize, Deserialize, Clone)]
-pub struct LocalUserView {
- pub local_user: LocalUser,
- pub person: Person,
- pub counts: PersonAggregates,
-}
type LocalUserViewTuple = (LocalUser, Person, PersonAggregates);
}
}
-#[derive(Debug, Serialize, Deserialize, Clone)]
-pub struct LocalUserSettingsView {
- pub local_user: LocalUserSettings,
- pub person: PersonSafe,
- pub counts: PersonAggregates,
-}
-
type LocalUserSettingsViewTuple = (LocalUserSettings, PersonSafe, PersonAggregates);
impl LocalUserSettingsView {
+use crate::structs::PostReportView;
use diesel::{dsl::*, result::Error, *};
use lemmy_db_schema::{
- aggregates::post_aggregates::PostAggregates,
- limit_and_offset,
+ aggregates::structs::PostAggregates,
newtypes::{CommunityId, PersonId, PostReportId},
schema::{
community,
post_report::PostReport,
},
traits::{MaybeOptional, ToSafe, ViewToVec},
+ utils::limit_and_offset,
};
-use serde::{Deserialize, Serialize};
-
-#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
-pub struct PostReportView {
- pub post_report: PostReport,
- pub post: Post,
- pub community: CommunitySafe,
- pub creator: PersonSafe,
- pub post_creator: PersonSafeAlias1,
- pub creator_banned_from_community: bool,
- pub my_vote: Option<i16>,
- pub counts: PostAggregates,
- pub resolver: Option<PersonSafeAlias2>,
-}
type PostReportViewTuple = (
PostReport,
mod tests {
use crate::post_report_view::{PostReportQueryBuilder, PostReportView};
use lemmy_db_schema::{
- aggregates::post_aggregates::PostAggregates,
- establish_unpooled_connection,
+ aggregates::structs::PostAggregates,
source::{
community::*,
person::*,
post_report::{PostReport, PostReportForm},
},
traits::{Crud, Joinable, Reportable},
+ utils::establish_unpooled_connection,
};
use serial_test::serial;
+use crate::structs::PostView;
use diesel::{dsl::*, pg::Pg, result::Error, *};
use lemmy_db_schema::{
- aggregates::post_aggregates::PostAggregates,
- functions::hot_rank,
- fuzzy_search,
- limit_and_offset,
+ aggregates::structs::PostAggregates,
newtypes::{CommunityId, DbUrl, PersonId, PostId},
schema::{
community,
post::{Post, PostRead, PostSaved},
},
traits::{MaybeOptional, ToSafe, ViewToVec},
- ListingType,
- SortType,
+ utils::{functions::hot_rank, fuzzy_search, limit_and_offset, ListingType, SortType},
};
-use serde::{Deserialize, Serialize};
use tracing::debug;
-#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
-pub struct PostView {
- pub post: Post,
- pub creator: PersonSafe,
- pub community: CommunitySafe,
- pub creator_banned_from_community: bool, // Left Join to CommunityPersonBan
- pub counts: PostAggregates,
- pub subscribed: bool, // Left join to CommunityFollower
- pub saved: bool, // Left join to PostSaved
- pub read: bool, // Left join to PostRead
- pub creator_blocked: bool, // Left join to PersonBlock
- pub my_vote: Option<i16>, // Left join to PostLike
-}
-
type PostViewTuple = (
Post,
PersonSafe,
mod tests {
use crate::post_view::{PostQueryBuilder, PostView};
use lemmy_db_schema::{
- aggregates::post_aggregates::PostAggregates,
- establish_unpooled_connection,
+ aggregates::structs::PostAggregates,
source::{
community::*,
community_block::{CommunityBlock, CommunityBlockForm},
post::*,
},
traits::{Blockable, Crud, Likeable},
- ListingType,
- SortType,
+ utils::{establish_unpooled_connection, ListingType, SortType},
};
use serial_test::serial;
+use crate::structs::PrivateMessageView;
use diesel::{pg::Pg, result::Error, *};
use lemmy_db_schema::{
- limit_and_offset,
newtypes::{PersonId, PrivateMessageId},
schema::{person, person_alias_1, private_message},
source::{
private_message::PrivateMessage,
},
traits::{MaybeOptional, ToSafe, ViewToVec},
+ utils::limit_and_offset,
};
-use serde::{Deserialize, Serialize};
use tracing::debug;
-#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
-pub struct PrivateMessageView {
- pub private_message: PrivateMessage,
- pub creator: PersonSafe,
- pub recipient: PersonSafeAlias1,
-}
-
type PrivateMessageViewTuple = (PrivateMessage, PersonSafe, PersonSafeAlias1);
impl PrivateMessageView {
+use crate::structs::RegistrationApplicationView;
use diesel::{dsl::count, result::Error, *};
use lemmy_db_schema::{
- limit_and_offset,
schema::{local_user, person, person_alias_1, registration_application},
source::{
local_user::{LocalUser, LocalUserSettings},
registration_application::RegistrationApplication,
},
traits::{MaybeOptional, ToSafe, ToSafeSettings, ViewToVec},
+ utils::limit_and_offset,
};
-use serde::{Deserialize, Serialize};
-
-#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
-pub struct RegistrationApplicationView {
- pub registration_application: RegistrationApplication,
- pub creator_local_user: LocalUserSettings,
- pub creator: PersonSafe,
- pub admin: Option<PersonSafeAlias1>,
-}
type RegistrationApplicationViewTuple = (
RegistrationApplication,
RegistrationApplicationView,
};
use lemmy_db_schema::{
- establish_unpooled_connection,
source::{
local_user::{LocalUser, LocalUserForm, LocalUserSettings},
person::*,
registration_application::{RegistrationApplication, RegistrationApplicationForm},
},
traits::Crud,
+ utils::establish_unpooled_connection,
};
use serial_test::serial;
+use crate::structs::SiteView;
use diesel::{result::Error, *};
use lemmy_db_schema::{
- aggregates::site_aggregates::SiteAggregates,
+ aggregates::structs::SiteAggregates,
schema::{site, site_aggregates},
source::site::Site,
};
-use serde::{Deserialize, Serialize};
-
-#[derive(Debug, Serialize, Deserialize, Clone)]
-pub struct SiteView {
- pub site: Site,
- pub counts: SiteAggregates,
-}
impl SiteView {
pub fn read_local(conn: &PgConnection) -> Result<Self, Error> {
--- /dev/null
+use lemmy_db_schema::{
+ aggregates::structs::{CommentAggregates, PersonAggregates, PostAggregates, SiteAggregates},
+ source::{
+ comment::Comment,
+ comment_report::CommentReport,
+ community::CommunitySafe,
+ local_user::{LocalUser, LocalUserSettings},
+ person::{Person, PersonSafe, PersonSafeAlias1, PersonSafeAlias2},
+ post::Post,
+ post_report::PostReport,
+ private_message::PrivateMessage,
+ registration_application::RegistrationApplication,
+ site::Site,
+ },
+};
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
+pub struct CommentReportView {
+ pub comment_report: CommentReport,
+ pub comment: Comment,
+ pub post: Post,
+ pub community: CommunitySafe,
+ pub creator: PersonSafe,
+ pub comment_creator: PersonSafeAlias1,
+ pub counts: CommentAggregates,
+ pub creator_banned_from_community: bool, // Left Join to CommunityPersonBan
+ pub my_vote: Option<i16>, // Left join to CommentLike
+ pub resolver: Option<PersonSafeAlias2>,
+}
+
+#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
+pub struct CommentView {
+ pub comment: Comment,
+ pub creator: PersonSafe,
+ pub recipient: Option<PersonSafeAlias1>, // Left joins to comment and person
+ pub post: Post,
+ pub community: CommunitySafe,
+ pub counts: CommentAggregates,
+ pub creator_banned_from_community: bool, // Left Join to CommunityPersonBan
+ pub subscribed: bool, // Left join to CommunityFollower
+ pub saved: bool, // Left join to CommentSaved
+ pub creator_blocked: bool, // Left join to PersonBlock
+ pub my_vote: Option<i16>, // Left join to CommentLike
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct LocalUserView {
+ pub local_user: LocalUser,
+ pub person: Person,
+ pub counts: PersonAggregates,
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct LocalUserSettingsView {
+ pub local_user: LocalUserSettings,
+ pub person: PersonSafe,
+ pub counts: PersonAggregates,
+}
+
+#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
+pub struct PostReportView {
+ pub post_report: PostReport,
+ pub post: Post,
+ pub community: CommunitySafe,
+ pub creator: PersonSafe,
+ pub post_creator: PersonSafeAlias1,
+ pub creator_banned_from_community: bool,
+ pub my_vote: Option<i16>,
+ pub counts: PostAggregates,
+ pub resolver: Option<PersonSafeAlias2>,
+}
+
+#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
+pub struct PostView {
+ pub post: Post,
+ pub creator: PersonSafe,
+ pub community: CommunitySafe,
+ pub creator_banned_from_community: bool, // Left Join to CommunityPersonBan
+ pub counts: PostAggregates,
+ pub subscribed: bool, // Left join to CommunityFollower
+ pub saved: bool, // Left join to PostSaved
+ pub read: bool, // Left join to PostRead
+ pub creator_blocked: bool, // Left join to PersonBlock
+ pub my_vote: Option<i16>, // Left join to PostLike
+}
+
+#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
+pub struct PrivateMessageView {
+ pub private_message: PrivateMessage,
+ pub creator: PersonSafe,
+ pub recipient: PersonSafeAlias1,
+}
+
+#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
+pub struct RegistrationApplicationView {
+ pub registration_application: RegistrationApplication,
+ pub creator_local_user: LocalUserSettings,
+ pub creator: PersonSafe,
+ pub admin: Option<PersonSafeAlias1>,
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct SiteView {
+ pub site: Site,
+ pub counts: SiteAggregates,
+}
[lib]
doctest = false
+[features]
+full = ["lemmy_db_schema/full", "diesel"]
+
[dependencies]
lemmy_db_schema = { version = "=0.16.3", path = "../db_schema" }
-diesel = { version = "1.4.8", features = ["postgres","chrono","r2d2","serde_json"] }
+diesel = { version = "1.4.8", features = ["postgres","chrono","r2d2","serde_json"], optional = true }
serde = { version = "1.0.136", features = ["derive"] }
+use crate::structs::CommunityBlockView;
use diesel::{result::Error, *};
use lemmy_db_schema::{
newtypes::PersonId,
},
traits::{ToSafe, ViewToVec},
};
-use serde::{Deserialize, Serialize};
-
-#[derive(Debug, Serialize, Deserialize, Clone)]
-pub struct CommunityBlockView {
- pub person: PersonSafe,
- pub community: CommunitySafe,
-}
type CommunityBlockViewTuple = (PersonSafe, CommunitySafe);
+use crate::structs::CommunityFollowerView;
use diesel::{result::Error, *};
use lemmy_db_schema::{
newtypes::{CommunityId, PersonId},
},
traits::{ToSafe, ViewToVec},
};
-use serde::{Deserialize, Serialize};
-
-#[derive(Debug, Serialize, Deserialize, Clone)]
-pub struct CommunityFollowerView {
- pub community: CommunitySafe,
- pub follower: PersonSafe,
-}
type CommunityFollowerViewTuple = (CommunitySafe, PersonSafe);
+use crate::structs::CommunityModeratorView;
use diesel::{result::Error, *};
use lemmy_db_schema::{
newtypes::{CommunityId, PersonId},
},
traits::{ToSafe, ViewToVec},
};
-use serde::{Deserialize, Serialize};
-
-#[derive(Debug, Serialize, Deserialize, Clone)]
-pub struct CommunityModeratorView {
- pub community: CommunitySafe,
- pub moderator: PersonSafe,
-}
type CommunityModeratorViewTuple = (CommunitySafe, PersonSafe);
+use crate::structs::CommunityPersonBanView;
use diesel::{dsl::*, result::Error, *};
use lemmy_db_schema::{
newtypes::{CommunityId, PersonId},
},
traits::ToSafe,
};
-use serde::{Deserialize, Serialize};
-
-#[derive(Debug, Serialize, Deserialize, Clone)]
-pub struct CommunityPersonBanView {
- pub community: CommunitySafe,
- pub person: PersonSafe,
-}
impl CommunityPersonBanView {
pub fn get(
-use crate::{community_moderator_view::CommunityModeratorView, person_view::PersonViewSafe};
+use crate::structs::{CommunityModeratorView, CommunityView, PersonViewSafe};
use diesel::{result::Error, *};
use lemmy_db_schema::{
- aggregates::community_aggregates::CommunityAggregates,
- functions::hot_rank,
- fuzzy_search,
- limit_and_offset,
+ aggregates::structs::CommunityAggregates,
newtypes::{CommunityId, PersonId},
schema::{community, community_aggregates, community_block, community_follower, local_user},
source::{
community_block::CommunityBlock,
},
traits::{MaybeOptional, ToSafe, ViewToVec},
- ListingType,
- SortType,
+ utils::{functions::hot_rank, fuzzy_search, limit_and_offset, ListingType, SortType},
};
-use serde::{Deserialize, Serialize};
-
-#[derive(Debug, Serialize, Deserialize, Clone)]
-pub struct CommunityView {
- pub community: CommunitySafe,
- pub subscribed: bool,
- pub blocked: bool,
- pub counts: CommunityAggregates,
-}
type CommunityViewTuple = (
CommunitySafe,
+#[cfg(feature = "full")]
pub mod community_block_view;
+#[cfg(feature = "full")]
pub mod community_follower_view;
+#[cfg(feature = "full")]
pub mod community_moderator_view;
+#[cfg(feature = "full")]
pub mod community_person_ban_view;
+#[cfg(feature = "full")]
pub mod community_view;
+#[cfg(feature = "full")]
pub mod person_block_view;
+#[cfg(feature = "full")]
pub mod person_mention_view;
+#[cfg(feature = "full")]
pub mod person_view;
+pub mod structs;
+use crate::structs::PersonBlockView;
use diesel::{result::Error, *};
use lemmy_db_schema::{
newtypes::PersonId,
source::person::{Person, PersonAlias1, PersonSafe, PersonSafeAlias1},
traits::{ToSafe, ViewToVec},
};
-use serde::{Deserialize, Serialize};
-
-#[derive(Debug, Serialize, Deserialize, Clone)]
-pub struct PersonBlockView {
- pub person: PersonSafe,
- pub target: PersonSafeAlias1,
-}
type PersonBlockViewTuple = (PersonSafe, PersonSafeAlias1);
+use crate::structs::PersonMentionView;
use diesel::{dsl::*, result::Error, *};
use lemmy_db_schema::{
- aggregates::comment_aggregates::CommentAggregates,
- functions::hot_rank,
- limit_and_offset,
+ aggregates::structs::CommentAggregates,
newtypes::{PersonId, PersonMentionId},
schema::{
comment,
post::Post,
},
traits::{MaybeOptional, ToSafe, ViewToVec},
- SortType,
+ utils::{functions::hot_rank, limit_and_offset, SortType},
};
-use serde::{Deserialize, Serialize};
-
-#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
-pub struct PersonMentionView {
- pub person_mention: PersonMention,
- pub comment: Comment,
- pub creator: PersonSafe,
- pub post: Post,
- pub community: CommunitySafe,
- pub recipient: PersonSafeAlias1,
- pub counts: CommentAggregates,
- pub creator_banned_from_community: bool, // Left Join to CommunityPersonBan
- pub subscribed: bool, // Left join to CommunityFollower
- pub saved: bool, // Left join to CommentSaved
- pub creator_blocked: bool, // Left join to PersonBlock
- pub my_vote: Option<i16>, // Left join to CommentLike
-}
type PersonMentionViewTuple = (
PersonMention,
+use crate::structs::PersonViewSafe;
use diesel::{dsl::*, result::Error, *};
use lemmy_db_schema::{
- aggregates::person_aggregates::PersonAggregates,
- fuzzy_search,
- limit_and_offset,
+ aggregates::structs::PersonAggregates,
newtypes::PersonId,
schema::{person, person_aggregates},
source::person::{Person, PersonSafe},
traits::{MaybeOptional, ToSafe, ViewToVec},
- SortType,
+ utils::{fuzzy_search, limit_and_offset, SortType},
};
-use serde::{Deserialize, Serialize};
-
-#[derive(Debug, Serialize, Deserialize, Clone)]
-pub struct PersonViewSafe {
- pub person: PersonSafe,
- pub counts: PersonAggregates,
-}
type PersonViewSafeTuple = (PersonSafe, PersonAggregates);
--- /dev/null
+use lemmy_db_schema::{
+ aggregates::structs::{CommentAggregates, CommunityAggregates, PersonAggregates},
+ source::{
+ comment::Comment,
+ community::CommunitySafe,
+ person::{PersonSafe, PersonSafeAlias1},
+ person_mention::PersonMention,
+ post::Post,
+ },
+};
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct CommunityBlockView {
+ pub person: PersonSafe,
+ pub community: CommunitySafe,
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct CommunityFollowerView {
+ pub community: CommunitySafe,
+ pub follower: PersonSafe,
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct CommunityModeratorView {
+ pub community: CommunitySafe,
+ pub moderator: PersonSafe,
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct CommunityPersonBanView {
+ pub community: CommunitySafe,
+ pub person: PersonSafe,
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct CommunityView {
+ pub community: CommunitySafe,
+ pub subscribed: bool,
+ pub blocked: bool,
+ pub counts: CommunityAggregates,
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct PersonBlockView {
+ pub person: PersonSafe,
+ pub target: PersonSafeAlias1,
+}
+
+#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
+pub struct PersonMentionView {
+ pub person_mention: PersonMention,
+ pub comment: Comment,
+ pub creator: PersonSafe,
+ pub post: Post,
+ pub community: CommunitySafe,
+ pub recipient: PersonSafeAlias1,
+ pub counts: CommentAggregates,
+ pub creator_banned_from_community: bool, // Left Join to CommunityPersonBan
+ pub subscribed: bool, // Left join to CommunityFollower
+ pub saved: bool, // Left join to CommentSaved
+ pub creator_blocked: bool, // Left join to PersonBlock
+ pub my_vote: Option<i16>, // Left join to CommentLike
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct PersonViewSafe {
+ pub person: PersonSafe,
+ pub counts: PersonAggregates,
+}
[lib]
doctest = false
+[features]
+full = ["lemmy_db_schema/full", "diesel"]
+
[dependencies]
lemmy_db_schema = { version = "=0.16.3", path = "../db_schema" }
-diesel = { version = "1.4.8", features = ["postgres","chrono","r2d2","serde_json"] }
+diesel = { version = "1.4.8", features = ["postgres","chrono","r2d2","serde_json"], optional = true }
serde = { version = "1.0.136", features = ["derive"] }
+#[cfg(feature = "full")]
pub mod mod_add_community_view;
+#[cfg(feature = "full")]
pub mod mod_add_view;
+#[cfg(feature = "full")]
pub mod mod_ban_from_community_view;
+#[cfg(feature = "full")]
pub mod mod_ban_view;
+#[cfg(feature = "full")]
pub mod mod_hide_community_view;
+#[cfg(feature = "full")]
pub mod mod_lock_post_view;
+#[cfg(feature = "full")]
pub mod mod_remove_comment_view;
+#[cfg(feature = "full")]
pub mod mod_remove_community_view;
+#[cfg(feature = "full")]
pub mod mod_remove_post_view;
+#[cfg(feature = "full")]
pub mod mod_sticky_post_view;
+#[cfg(feature = "full")]
pub mod mod_transfer_community_view;
+pub mod structs;
+use crate::structs::ModAddCommunityView;
use diesel::{result::Error, *};
use lemmy_db_schema::{
- limit_and_offset,
newtypes::{CommunityId, PersonId},
schema::{community, mod_add_community, person, person_alias_1},
source::{
person::{Person, PersonAlias1, PersonSafe, PersonSafeAlias1},
},
traits::{ToSafe, ViewToVec},
+ utils::limit_and_offset,
};
-use serde::{Deserialize, Serialize};
-
-#[derive(Debug, Serialize, Deserialize, Clone)]
-pub struct ModAddCommunityView {
- pub mod_add_community: ModAddCommunity,
- pub moderator: PersonSafe,
- pub community: CommunitySafe,
- pub modded_person: PersonSafeAlias1,
-}
type ModAddCommunityViewTuple = (ModAddCommunity, PersonSafe, CommunitySafe, PersonSafeAlias1);
+use crate::structs::ModAddView;
use diesel::{result::Error, *};
use lemmy_db_schema::{
- limit_and_offset,
newtypes::PersonId,
schema::{mod_add, person, person_alias_1},
source::{
person::{Person, PersonAlias1, PersonSafe, PersonSafeAlias1},
},
traits::{ToSafe, ViewToVec},
+ utils::limit_and_offset,
};
-use serde::{Deserialize, Serialize};
-
-#[derive(Debug, Serialize, Deserialize, Clone)]
-pub struct ModAddView {
- pub mod_add: ModAdd,
- pub moderator: PersonSafe,
- pub modded_person: PersonSafeAlias1,
-}
type ModAddViewTuple = (ModAdd, PersonSafe, PersonSafeAlias1);
+use crate::structs::ModBanFromCommunityView;
use diesel::{result::Error, *};
use lemmy_db_schema::{
- limit_and_offset,
newtypes::{CommunityId, PersonId},
schema::{community, mod_ban_from_community, person, person_alias_1},
source::{
person::{Person, PersonAlias1, PersonSafe, PersonSafeAlias1},
},
traits::{ToSafe, ViewToVec},
+ utils::limit_and_offset,
};
-use serde::{Deserialize, Serialize};
-
-#[derive(Debug, Serialize, Deserialize, Clone)]
-pub struct ModBanFromCommunityView {
- pub mod_ban_from_community: ModBanFromCommunity,
- pub moderator: PersonSafe,
- pub community: CommunitySafe,
- pub banned_person: PersonSafeAlias1,
-}
type ModBanFromCommunityViewTuple = (
ModBanFromCommunity,
+use crate::structs::ModBanView;
use diesel::{result::Error, *};
use lemmy_db_schema::{
- limit_and_offset,
newtypes::PersonId,
schema::{mod_ban, person, person_alias_1},
source::{
person::{Person, PersonAlias1, PersonSafe, PersonSafeAlias1},
},
traits::{ToSafe, ViewToVec},
+ utils::limit_and_offset,
};
-use serde::{Deserialize, Serialize};
-
-#[derive(Debug, Serialize, Deserialize, Clone)]
-pub struct ModBanView {
- pub mod_ban: ModBan,
- pub moderator: PersonSafe,
- pub banned_person: PersonSafeAlias1,
-}
type ModBanViewTuple = (ModBan, PersonSafe, PersonSafeAlias1);
+use crate::structs::ModHideCommunityView;
use diesel::{result::Error, *};
use lemmy_db_schema::{
- limit_and_offset,
newtypes::{CommunityId, PersonId},
schema::{community, mod_hide_community, person},
source::{
person::{Person, PersonSafe},
},
traits::{ToSafe, ViewToVec},
+ utils::limit_and_offset,
};
-use serde::{Deserialize, Serialize};
-
-#[derive(Debug, Serialize, Deserialize, Clone)]
-pub struct ModHideCommunityView {
- pub mod_hide_community: ModHideCommunity,
- pub admin: PersonSafe,
- pub community: CommunitySafe,
-}
type ModHideCommunityViewTuple = (ModHideCommunity, PersonSafe, CommunitySafe);
+use crate::structs::ModLockPostView;
use diesel::{result::Error, *};
use lemmy_db_schema::{
- limit_and_offset,
newtypes::{CommunityId, PersonId},
schema::{community, mod_lock_post, person, post},
source::{
post::Post,
},
traits::{ToSafe, ViewToVec},
+ utils::limit_and_offset,
};
-use serde::{Deserialize, Serialize};
-
-#[derive(Debug, Serialize, Deserialize, Clone)]
-pub struct ModLockPostView {
- pub mod_lock_post: ModLockPost,
- pub moderator: PersonSafe,
- pub post: Post,
- pub community: CommunitySafe,
-}
type ModLockPostViewTuple = (ModLockPost, PersonSafe, Post, CommunitySafe);
+use crate::structs::ModRemoveCommentView;
use diesel::{result::Error, *};
use lemmy_db_schema::{
- limit_and_offset,
newtypes::{CommunityId, PersonId},
schema::{comment, community, mod_remove_comment, person, person_alias_1, post},
source::{
post::Post,
},
traits::{ToSafe, ViewToVec},
+ utils::limit_and_offset,
};
-use serde::{Deserialize, Serialize};
-
-#[derive(Debug, Serialize, Deserialize, Clone)]
-pub struct ModRemoveCommentView {
- pub mod_remove_comment: ModRemoveComment,
- pub moderator: PersonSafe,
- pub comment: Comment,
- pub commenter: PersonSafeAlias1,
- pub post: Post,
- pub community: CommunitySafe,
-}
type ModRemoveCommentViewTuple = (
ModRemoveComment,
+use crate::structs::ModRemoveCommunityView;
use diesel::{result::Error, *};
use lemmy_db_schema::{
- limit_and_offset,
newtypes::PersonId,
schema::{community, mod_remove_community, person},
source::{
person::{Person, PersonSafe},
},
traits::{ToSafe, ViewToVec},
+ utils::limit_and_offset,
};
-use serde::{Deserialize, Serialize};
-
-#[derive(Debug, Serialize, Deserialize, Clone)]
-pub struct ModRemoveCommunityView {
- pub mod_remove_community: ModRemoveCommunity,
- pub moderator: PersonSafe,
- pub community: CommunitySafe,
-}
type ModRemoveCommunityTuple = (ModRemoveCommunity, PersonSafe, CommunitySafe);
+use crate::structs::ModRemovePostView;
use diesel::{result::Error, *};
use lemmy_db_schema::{
- limit_and_offset,
newtypes::{CommunityId, PersonId},
schema::{community, mod_remove_post, person, post},
source::{
post::Post,
},
traits::{ToSafe, ViewToVec},
+ utils::limit_and_offset,
};
-use serde::{Deserialize, Serialize};
-
-#[derive(Debug, Serialize, Deserialize, Clone)]
-pub struct ModRemovePostView {
- pub mod_remove_post: ModRemovePost,
- pub moderator: PersonSafe,
- pub post: Post,
- pub community: CommunitySafe,
-}
type ModRemovePostViewTuple = (ModRemovePost, PersonSafe, Post, CommunitySafe);
+use crate::structs::ModStickyPostView;
use diesel::{result::Error, *};
use lemmy_db_schema::{
- limit_and_offset,
newtypes::{CommunityId, PersonId},
schema::{community, mod_sticky_post, person, post},
source::{
post::Post,
},
traits::{ToSafe, ViewToVec},
+ utils::limit_and_offset,
};
-use serde::{Deserialize, Serialize};
-
-#[derive(Debug, Serialize, Deserialize, Clone)]
-pub struct ModStickyPostView {
- pub mod_sticky_post: ModStickyPost,
- pub moderator: PersonSafe,
- pub post: Post,
- pub community: CommunitySafe,
-}
type ModStickyPostViewTuple = (ModStickyPost, PersonSafe, Post, CommunitySafe);
+use crate::structs::ModTransferCommunityView;
use diesel::{result::Error, *};
use lemmy_db_schema::{
- limit_and_offset,
newtypes::{CommunityId, PersonId},
schema::{community, mod_transfer_community, person, person_alias_1},
source::{
person::{Person, PersonAlias1, PersonSafe, PersonSafeAlias1},
},
traits::{ToSafe, ViewToVec},
+ utils::limit_and_offset,
};
-use serde::{Deserialize, Serialize};
-
-#[derive(Debug, Serialize, Deserialize, Clone)]
-pub struct ModTransferCommunityView {
- pub mod_transfer_community: ModTransferCommunity,
- pub moderator: PersonSafe,
- pub community: CommunitySafe,
- pub modded_person: PersonSafeAlias1,
-}
type ModTransferCommunityViewTuple = (
ModTransferCommunity,
--- /dev/null
+use lemmy_db_schema::source::{
+ comment::Comment,
+ community::CommunitySafe,
+ moderator::{
+ ModAdd,
+ ModAddCommunity,
+ ModBan,
+ ModBanFromCommunity,
+ ModHideCommunity,
+ ModLockPost,
+ ModRemoveComment,
+ ModRemoveCommunity,
+ ModRemovePost,
+ ModStickyPost,
+ ModTransferCommunity,
+ },
+ person::{PersonSafe, PersonSafeAlias1},
+ post::Post,
+};
+use serde::{Deserialize, Serialize};
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct ModAddCommunityView {
+ pub mod_add_community: ModAddCommunity,
+ pub moderator: PersonSafe,
+ pub community: CommunitySafe,
+ pub modded_person: PersonSafeAlias1,
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct ModAddView {
+ pub mod_add: ModAdd,
+ pub moderator: PersonSafe,
+ pub modded_person: PersonSafeAlias1,
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct ModBanFromCommunityView {
+ pub mod_ban_from_community: ModBanFromCommunity,
+ pub moderator: PersonSafe,
+ pub community: CommunitySafe,
+ pub banned_person: PersonSafeAlias1,
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct ModBanView {
+ pub mod_ban: ModBan,
+ pub moderator: PersonSafe,
+ pub banned_person: PersonSafeAlias1,
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct ModHideCommunityView {
+ pub mod_hide_community: ModHideCommunity,
+ pub admin: PersonSafe,
+ pub community: CommunitySafe,
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct ModLockPostView {
+ pub mod_lock_post: ModLockPost,
+ pub moderator: PersonSafe,
+ pub post: Post,
+ pub community: CommunitySafe,
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct ModRemoveCommentView {
+ pub mod_remove_comment: ModRemoveComment,
+ pub moderator: PersonSafe,
+ pub comment: Comment,
+ pub commenter: PersonSafeAlias1,
+ pub post: Post,
+ pub community: CommunitySafe,
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct ModRemoveCommunityView {
+ pub mod_remove_community: ModRemoveCommunity,
+ pub moderator: PersonSafe,
+ pub community: CommunitySafe,
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct ModRemovePostView {
+ pub mod_remove_post: ModRemovePost,
+ pub moderator: PersonSafe,
+ pub post: Post,
+ pub community: CommunitySafe,
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct ModStickyPostView {
+ pub mod_sticky_post: ModStickyPost,
+ pub moderator: PersonSafe,
+ pub post: Post,
+ pub community: CommunitySafe,
+}
+
+#[derive(Debug, Serialize, Deserialize, Clone)]
+pub struct ModTransferCommunityView {
+ pub mod_transfer_community: ModTransferCommunity,
+ pub moderator: PersonSafe,
+ pub community: CommunitySafe,
+ pub modded_person: PersonSafeAlias1,
+}
diesel = "1.4.8"
actix-web = { version = "4.0.1", default-features = false, features = ["rustls"] }
anyhow = "1.0.56"
-chrono = { version = "0.4.19", features = ["serde"] }
+chrono = { version = "0.4.19", features = ["serde"], default-features = false }
futures = "0.3.21"
reqwest = { version = "0.11.10", features = ["stream"] }
reqwest-middleware = "0.1.5"
use anyhow::anyhow;
use chrono::{DateTime, NaiveDateTime, Utc};
use diesel::PgConnection;
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_db_schema::{
newtypes::LocalUserId,
source::{community::Community, local_user::LocalUser, person::Person},
traits::{ApubActor, Crud},
- ListingType,
- SortType,
+ utils::{ListingType, SortType},
};
use lemmy_db_views::{
- comment_view::{CommentQueryBuilder, CommentView},
- post_view::{PostQueryBuilder, PostView},
- site_view::SiteView,
+ comment_view::CommentQueryBuilder,
+ post_view::PostQueryBuilder,
+ structs::{CommentView, PostView, SiteView},
+};
+use lemmy_db_views_actor::{
+ person_mention_view::PersonMentionQueryBuilder,
+ structs::PersonMentionView,
};
-use lemmy_db_views_actor::person_mention_view::{PersonMentionQueryBuilder, PersonMentionView};
use lemmy_utils::{claims::Claims, utils::markdown_to_html, LemmyError};
use lemmy_websocket::LemmyContext;
use once_cell::sync::Lazy;
use actix_web::{error::ErrorBadRequest, *};
use anyhow::anyhow;
-use lemmy_api_common::blocking;
-use lemmy_db_views::site_view::SiteView;
+use lemmy_api_common::utils::blocking;
+use lemmy_db_views::structs::SiteView;
use lemmy_utils::{version, LemmyError};
use lemmy_websocket::LemmyContext;
use serde::{Deserialize, Serialize};
use actix_web::{web, web::Query, HttpResponse};
use anyhow::Context;
-use lemmy_api_common::blocking;
+use lemmy_api_common::utils::blocking;
use lemmy_apub::fetcher::webfinger::{WebfingerLink, WebfingerResponse};
use lemmy_db_schema::{
source::{community::Community, person::Person},
[dependencies]
regex = "1.5.5"
-chrono = { version = "0.4.19", features = ["serde"] }
+chrono = { version = "0.4.19", features = ["serde"], default-features = false }
lettre = "0.10.0-rc.4"
tracing = "0.1.32"
tracing-error = "0.2.0"
itertools = "0.10.3"
rand = "0.8.5"
-percent-encoding = "2.1.0"
serde = { version = "1.0.136", features = ["derive"] }
serde_json = { version = "1.0.79", features = ["preserve_order"] }
-thiserror = "1.0.30"
comrak = { version = "0.12.1", default-features = false }
once_cell = "1.10.0"
openssl = "0.10.38"
url = { version = "2.2.2", features = ["serde"] }
actix-web = { version = "4.0.1", default-features = false, features = ["rustls"] }
-actix-rt = { version = "2.7.0", default-features = false }
anyhow = "1.0.56"
-reqwest = { version = "0.11.10", features = ["json"] }
reqwest-middleware = "0.1.5"
strum = "0.24.0"
strum_macros = "0.24.0"
http = "0.2.6"
deser-hjson = "1.0.2"
smart-default = "0.6.0"
-webpage = { version = "1.4.0", default-features = false, features = ["serde"] }
jsonwebtoken = "8.0.1"
doku = "0.11.0"
uuid = { version = "0.8.2", features = ["serde", "v4"] }
-encoding = "0.2.33"
html2text = "0.3.1"
rosetta-i18n = "0.1.2"
parking_lot = "0.12.0"
pub mod apub;
pub mod email;
pub mod rate_limit;
-pub mod request;
pub mod settings;
pub mod claims;
+pub mod request;
#[cfg(test)]
mod test;
pub mod utils;
pub mod version;
-mod sensitive;
-
-pub use sensitive::Sensitive;
-
use actix_web::HttpResponse;
use http::StatusCode;
use std::{fmt, fmt::Display, time::Duration};
-use crate::{settings::structs::Settings, version::VERSION, LemmyError, REQWEST_TIMEOUT};
-use anyhow::anyhow;
-use encoding::{all::encodings, DecoderTrap};
-use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
-use reqwest_middleware::ClientWithMiddleware;
-use serde::{Deserialize, Serialize};
use std::future::Future;
-use thiserror::Error;
-use tracing::{error, info};
-use url::Url;
-use webpage::HTML;
-
-#[derive(Clone, Debug, Error)]
-#[error("Error sending request, {0}")]
-struct SendError(pub String);
-
-#[derive(Clone, Debug, Error)]
-#[error("Error receiving response, {0}")]
-pub struct RecvError(pub String);
#[tracing::instrument(skip_all)]
pub async fn retry<F, Fut, T>(f: F) -> Result<T, reqwest_middleware::Error>
response.expect("retry http request")
}
-
-#[derive(Deserialize, Serialize, Debug, PartialEq, Clone)]
-pub struct SiteMetadata {
- pub title: Option<String>,
- pub description: Option<String>,
- image: Option<Url>,
- pub html: Option<String>,
-}
-
-/// Fetches the post link html tags (like title, description, image, etc)
-#[tracing::instrument(skip_all)]
-pub async fn fetch_site_metadata(
- client: &ClientWithMiddleware,
- url: &Url,
-) -> Result<SiteMetadata, LemmyError> {
- info!("Fetching site metadata for url: {}", url);
- let response = client
- .get(url.as_str())
- .timeout(REQWEST_TIMEOUT)
- .send()
- .await?;
-
- // Can't use .text() here, because it only checks the content header, not the actual bytes
- // https://github.com/LemmyNet/lemmy/issues/1964
- let html_bytes = response
- .bytes()
- .await
- .map_err(|e| RecvError(e.to_string()))?
- .to_vec();
-
- let tags = html_to_site_metadata(&html_bytes)?;
-
- Ok(tags)
-}
-
-fn html_to_site_metadata(html_bytes: &[u8]) -> Result<SiteMetadata, LemmyError> {
- let html = String::from_utf8_lossy(html_bytes);
-
- // Make sure the first line is doctype html
- let first_line = html
- .trim_start()
- .lines()
- .into_iter()
- .next()
- .ok_or_else(|| LemmyError::from_message("No lines in html"))?
- .to_lowercase();
-
- if !first_line.starts_with("<!doctype html>") {
- return Err(LemmyError::from_message(
- "Site metadata page fetch is not DOCTYPE html",
- ));
- }
-
- let mut page = HTML::from_string(html.to_string(), None)?;
-
- // If the web page specifies that it isn't actually UTF-8, re-decode the received bytes with the
- // proper encoding. If the specified encoding cannot be found, fall back to the original UTF-8
- // version.
- if let Some(charset) = page.meta.get("charset") {
- if charset.to_lowercase() != "utf-8" {
- if let Some(encoding_ref) = encodings().iter().find(|e| e.name() == charset) {
- if let Ok(html_with_encoding) = encoding_ref.decode(html_bytes, DecoderTrap::Replace) {
- page = HTML::from_string(html_with_encoding, None)?;
- }
- }
- }
- }
-
- let page_title = page.title;
- let page_description = page.description;
-
- let og_description = page
- .opengraph
- .properties
- .get("description")
- .map(|t| t.to_string());
- let og_title = page
- .opengraph
- .properties
- .get("title")
- .map(|t| t.to_string());
- let og_image = page
- .opengraph
- .images
- .get(0)
- .and_then(|ogo| Url::parse(&ogo.url).ok());
-
- let title = og_title.or(page_title);
- let description = og_description.or(page_description);
- let image = og_image;
-
- Ok(SiteMetadata {
- title,
- description,
- image,
- html: None,
- })
-}
-
-#[derive(Deserialize, Debug, Clone)]
-pub(crate) struct PictrsResponse {
- files: Vec<PictrsFile>,
- msg: String,
-}
-
-#[derive(Deserialize, Debug, Clone)]
-pub(crate) struct PictrsFile {
- file: String,
- #[allow(dead_code)]
- delete_token: String,
-}
-
-#[tracing::instrument(skip_all)]
-pub(crate) async fn fetch_pictrs(
- client: &ClientWithMiddleware,
- settings: &Settings,
- image_url: &Url,
-) -> Result<PictrsResponse, LemmyError> {
- if let Some(pictrs_url) = settings.pictrs_url.to_owned() {
- is_image_content_type(client, image_url).await?;
-
- let fetch_url = format!(
- "{}/image/download?url={}",
- pictrs_url,
- utf8_percent_encode(image_url.as_str(), NON_ALPHANUMERIC) // TODO this might not be needed
- );
-
- let response = client
- .get(&fetch_url)
- .timeout(REQWEST_TIMEOUT)
- .send()
- .await?;
-
- let response: PictrsResponse = response
- .json()
- .await
- .map_err(|e| RecvError(e.to_string()))?;
-
- if response.msg == "ok" {
- Ok(response)
- } else {
- Err(anyhow!("{}", &response.msg).into())
- }
- } else {
- Err(anyhow!("pictrs_url not set up in config").into())
- }
-}
-
-/// Both are options, since the URL might be either an html page, or an image
-/// Returns the SiteMetadata, and a Pictrs URL, if there is a picture associated
-#[tracing::instrument(skip_all)]
-pub async fn fetch_site_data(
- client: &ClientWithMiddleware,
- settings: &Settings,
- url: Option<&Url>,
-) -> (Option<SiteMetadata>, Option<Url>) {
- match &url {
- Some(url) => {
- // Fetch metadata
- // Ignore errors, since it may be an image, or not have the data.
- // Warning, this may ignore SSL errors
- let metadata_option = fetch_site_metadata(client, url).await.ok();
-
- // Fetch pictrs thumbnail
- let pictrs_hash = match &metadata_option {
- Some(metadata_res) => match &metadata_res.image {
- // Metadata, with image
- // Try to generate a small thumbnail if there's a full sized one from post-links
- Some(metadata_image) => fetch_pictrs(client, settings, metadata_image)
- .await
- .map(|r| r.files[0].file.to_owned()),
- // Metadata, but no image
- None => fetch_pictrs(client, settings, url)
- .await
- .map(|r| r.files[0].file.to_owned()),
- },
- // No metadata, try to fetch the URL as an image
- None => fetch_pictrs(client, settings, url)
- .await
- .map(|r| r.files[0].file.to_owned()),
- };
-
- // The full urls are necessary for federation
- let pictrs_thumbnail = pictrs_hash
- .map(|p| {
- Url::parse(&format!(
- "{}/pictrs/image/{}",
- settings.get_protocol_and_hostname(),
- p
- ))
- .ok()
- })
- .ok()
- .flatten();
-
- (metadata_option, pictrs_thumbnail)
- }
- None => (None, None),
- }
-}
-
-#[tracing::instrument(skip_all)]
-async fn is_image_content_type(client: &ClientWithMiddleware, url: &Url) -> Result<(), LemmyError> {
- let response = client
- .get(url.as_str())
- .timeout(REQWEST_TIMEOUT)
- .send()
- .await?;
- if response
- .headers()
- .get("Content-Type")
- .ok_or_else(|| anyhow!("No Content-Type header"))?
- .to_str()?
- .starts_with("image/")
- {
- Ok(())
- } else {
- Err(anyhow!("Not an image type.").into())
- }
-}
-
-pub fn build_user_agent(settings: &Settings) -> String {
- format!(
- "Lemmy/{}; +{}",
- VERSION,
- settings.get_protocol_and_hostname()
- )
-}
-
-#[cfg(test)]
-mod tests {
- use crate::request::{build_user_agent, fetch_site_metadata};
- use url::Url;
-
- use super::SiteMetadata;
- use crate::settings::structs::Settings;
-
- // These helped with testing
- #[actix_rt::test]
- async fn test_site_metadata() {
- let settings = Settings::init().unwrap();
- let client = reqwest::Client::builder()
- .user_agent(build_user_agent(&settings))
- .build()
- .unwrap()
- .into();
- let sample_url = Url::parse("https://gitlab.com/IzzyOnDroid/repo/-/wikis/FAQ").unwrap();
- let sample_res = fetch_site_metadata(&client, &sample_url).await.unwrap();
- assert_eq!(
- SiteMetadata {
- title: Some("FAQ · Wiki · IzzyOnDroid / repo · GitLab".to_string()),
- description: Some(
- "The F-Droid compatible repo at https://apt.izzysoft.de/fdroid/".to_string()
- ),
- image: Some(
- Url::parse("https://gitlab.com/uploads/-/system/project/avatar/4877469/iod_logo.png")
- .unwrap()
- ),
- html: None,
- },
- sample_res
- );
-
- let youtube_url = Url::parse("https://www.youtube.com/watch?v=IquO_TcMZIQ").unwrap();
- let youtube_res = fetch_site_metadata(&client, &youtube_url).await.unwrap();
- assert_eq!(
- SiteMetadata {
- title: Some("A Hard Look at Rent and Rent Seeking with Michael Hudson & Pepe Escobar".to_string()),
- description: Some("An interactive discussion on wealth inequality and the “Great Game” on the control of natural resources.In this webinar organized jointly by the Henry George...".to_string()),
- image: Some(Url::parse("https://i.ytimg.com/vi/IquO_TcMZIQ/maxresdefault.jpg").unwrap()),
- html: None,
- }, youtube_res);
- }
-
- // #[test]
- // fn test_pictshare() {
- // let res = fetch_pictshare("https://upload.wikimedia.org/wikipedia/en/2/27/The_Mandalorian_logo.jpg");
- // assert!(res.is_ok());
- // let res_other = fetch_pictshare("https://upload.wikimedia.org/wikipedia/en/2/27/The_Mandalorian_logo.jpgaoeu");
- // assert!(res_other.is_err());
- // }
-}
[dependencies]
lemmy_utils = { version = "=0.16.3", path = "../utils" }
lemmy_api_common = { version = "=0.16.3", path = "../api_common" }
-lemmy_db_schema = { version = "=0.16.3", path = "../db_schema" }
-lemmy_db_views = { version = "=0.16.3", path = "../db_views" }
-lemmy_db_views_actor = { version = "=0.16.3", path = "../db_views_actor" }
+lemmy_db_schema = { version = "=0.16.3", path = "../db_schema", features = ["full"] }
+lemmy_db_views = { version = "=0.16.3", path = "../db_views", features = ["full"] }
+lemmy_db_views_actor = { version = "=0.16.3", path = "../db_views_actor", features = ["full"] }
reqwest-middleware = "0.1.5"
tracing = "0.1.32"
rand = "0.8.5"
tokio = "1.17.0"
strum = "0.24.0"
strum_macros = "0.24.0"
-chrono = { version = "0.4.19", features = ["serde"] }
+chrono = { version = "0.4.19", features = ["serde"], default-features = false }
actix-web = { version = "4.0.1", default-features = false, features = ["rustls"] }
actix-web-actors = { version = "4.1.0", default-features = false }
opentelemetry = "0.17.0"
OperationType,
};
use actix::{Actor, Context, Handler, ResponseFuture};
-use lemmy_db_schema::naive_now;
+use lemmy_db_schema::utils::naive_now;
use lemmy_utils::ConnectionId;
use opentelemetry::trace::TraceContextExt;
use rand::Rng;
use crate::chat_server::ChatServer;
use actix::Addr;
use background_jobs::QueueHandle;
-use lemmy_db_schema::{source::secret::Secret, DbPool};
+use lemmy_db_schema::{source::secret::Secret, utils::DbPool};
use lemmy_utils::{settings::structs::Settings, LemmyError};
use reqwest_middleware::ClientWithMiddleware;
use serde::Serialize;
OperationType,
};
use lemmy_api_common::{
- blocking,
- check_person_block,
comment::CommentResponse,
community::CommunityResponse,
- get_user_lang,
person::PrivateMessageResponse,
post::PostResponse,
- send_email_to_user,
+ utils::{blocking, check_person_block, get_user_lang, send_email_to_user},
};
use lemmy_db_schema::{
newtypes::{CommentId, CommunityId, LocalUserId, PersonId, PostId, PrivateMessageId},
},
traits::{Crud, DeleteableOrRemoveable},
};
-use lemmy_db_views::{
- comment_view::CommentView,
- local_user_view::LocalUserView,
- post_view::PostView,
- private_message_view::PrivateMessageView,
-};
-use lemmy_db_views_actor::community_view::CommunityView;
+use lemmy_db_views::structs::{CommentView, LocalUserView, PostView, PrivateMessageView};
+use lemmy_db_views_actor::structs::CommunityView;
use lemmy_utils::{utils::MentionData, ConnectionId, LemmyError};
#[tracing::instrument(skip_all)]
EndpointType,
};
use lemmy_db_schema::{
- naive_now,
source::{
comment::Comment,
community::{Community, CommunityForm},
site::{Site, SiteForm},
},
traits::Crud,
+ utils::naive_now,
};
use lemmy_utils::{apub::generate_actor_keypair, LemmyError};
use tracing::info;
};
use doku::json::{AutoComments, Formatting};
use lemmy_api::match_websocket_operation;
-use lemmy_api_common::{blocking, check_private_instance_and_federation_enabled};
+use lemmy_api_common::{
+ request::build_user_agent,
+ utils::{blocking, check_private_instance_and_federation_enabled},
+};
use lemmy_api_crud::match_websocket_operation_crud;
use lemmy_apub_lib::activity_queue::create_activity_queue;
-use lemmy_db_schema::{get_database_url_from_env, source::secret::Secret};
+use lemmy_db_schema::{source::secret::Secret, utils::get_database_url_from_env};
use lemmy_routes::{feeds, images, nodeinfo, webfinger};
use lemmy_server::{
api_routes,
};
use lemmy_utils::{
rate_limit::{rate_limiter::RateLimiter, RateLimit},
- request::build_user_agent,
settings::structs::Settings,
LemmyError,
REQWEST_TIMEOUT,
use clokwerk::{Scheduler, TimeUnits};
// Import week days and WeekDay
use diesel::{sql_query, PgConnection, RunQueryDsl};
-use lemmy_db_schema::{source::activity::Activity, DbPool};
+use lemmy_db_schema::{source::activity::Activity, utils::DbPool};
use lemmy_utils::LemmyError;
use std::{thread, time::Duration};
use tracing::info;