mirror of
https://github.com/LemmyNet/lemmy.git
synced 2025-09-03 11:43:51 +00:00
Remove unused items (#5870)
* Remove some unused functions * shear * remove more * full feature * remove more * some more * mroe
This commit is contained in:
parent
72d254b4db
commit
f65875c27a
28 changed files with 36 additions and 293 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -3962,7 +3962,6 @@ dependencies = [
|
||||||
"moka",
|
"moka",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"regex",
|
"regex",
|
||||||
"reqwest-middleware",
|
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"smart-default",
|
"smart-default",
|
||||||
|
|
16
Cargo.toml
16
Cargo.toml
|
@ -42,16 +42,11 @@ default = []
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
"crates/api/api",
|
|
||||||
"crates/api/api_crud",
|
|
||||||
"crates/api/api_common",
|
|
||||||
"crates/api/api_utils",
|
|
||||||
"crates/apub",
|
|
||||||
"crates/apub_objects",
|
|
||||||
"crates/utils",
|
"crates/utils",
|
||||||
"crates/db_schema",
|
"crates/db_schema",
|
||||||
"crates/db_schema_file",
|
"crates/db_schema_file",
|
||||||
"crates/db_schema_setup",
|
"crates/db_schema_setup",
|
||||||
|
"crates/email",
|
||||||
"crates/db_views/private_message",
|
"crates/db_views/private_message",
|
||||||
"crates/db_views/local_user",
|
"crates/db_views/local_user",
|
||||||
"crates/db_views/local_image",
|
"crates/db_views/local_image",
|
||||||
|
@ -73,9 +68,14 @@ members = [
|
||||||
"crates/db_views/report_combined",
|
"crates/db_views/report_combined",
|
||||||
"crates/db_views/search_combined",
|
"crates/db_views/search_combined",
|
||||||
"crates/db_views/site",
|
"crates/db_views/site",
|
||||||
"crates/routes",
|
"crates/api/api",
|
||||||
|
"crates/api/api_crud",
|
||||||
|
"crates/api/api_common",
|
||||||
|
"crates/api/api_utils",
|
||||||
|
"crates/apub",
|
||||||
|
"crates/apub_objects",
|
||||||
"crates/federate",
|
"crates/federate",
|
||||||
"crates/email",
|
"crates/routes",
|
||||||
]
|
]
|
||||||
|
|
||||||
[workspace.lints.clippy]
|
[workspace.lints.clippy]
|
||||||
|
|
|
@ -18,6 +18,9 @@ doctest = false
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
|
[features]
|
||||||
|
full = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
lemmy_db_views_comment = { workspace = true, features = ["full"] }
|
lemmy_db_views_comment = { workspace = true, features = ["full"] }
|
||||||
lemmy_db_views_community = { workspace = true, features = ["full"] }
|
lemmy_db_views_community = { workspace = true, features = ["full"] }
|
||||||
|
|
|
@ -18,6 +18,7 @@ doctest = false
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
full = []
|
||||||
ts-rs = [
|
ts-rs = [
|
||||||
"lemmy_utils/ts-rs",
|
"lemmy_utils/ts-rs",
|
||||||
"lemmy_db_schema/ts-rs",
|
"lemmy_db_schema/ts-rs",
|
||||||
|
|
|
@ -13,6 +13,9 @@ rust-version.workspace = true
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
|
[features]
|
||||||
|
full = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
lemmy_db_views_comment = { workspace = true, features = ["full"] }
|
lemmy_db_views_comment = { workspace = true, features = ["full"] }
|
||||||
lemmy_db_views_community = { workspace = true, features = ["full"] }
|
lemmy_db_views_community = { workspace = true, features = ["full"] }
|
||||||
|
|
|
@ -332,12 +332,6 @@ impl PictrsFile {
|
||||||
self.file
|
self.file
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
pub fn delete_url(&self, protocol_and_hostname: &str) -> Result<Url, url::ParseError> {
|
|
||||||
Url::parse(&format!(
|
|
||||||
"{protocol_and_hostname}/api/v4/image/{}",
|
|
||||||
self.file
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stores extra details about a Pictrs image.
|
/// Stores extra details about a Pictrs image.
|
||||||
|
|
|
@ -206,19 +206,6 @@ pub fn check_local_user_deleted(local_user_view: &LocalUserView) -> LemmyResult<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_person_valid(person_view: &PersonView) -> LemmyResult<()> {
|
|
||||||
// Check for a site ban
|
|
||||||
if person_view.creator_banned {
|
|
||||||
Err(LemmyErrorType::SiteBan)?
|
|
||||||
}
|
|
||||||
// check for account deletion
|
|
||||||
else if person_view.person.deleted {
|
|
||||||
Err(LemmyErrorType::Deleted)?
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check if the user's email is verified if email verification is turned on
|
/// Check if the user's email is verified if email verification is turned on
|
||||||
/// However, skip checking verification if the user is an admin
|
/// However, skip checking verification if the user is an admin
|
||||||
pub fn check_email_verified(
|
pub fn check_email_verified(
|
||||||
|
|
|
@ -18,7 +18,7 @@ pub mod search;
|
||||||
///
|
///
|
||||||
/// In case the requesting user is logged in and the object was not found locally, it is attempted
|
/// In case the requesting user is logged in and the object was not found locally, it is attempted
|
||||||
/// to fetch via webfinger from the original instance.
|
/// to fetch via webfinger from the original instance.
|
||||||
pub async fn resolve_ap_identifier<ActorType, DbActor>(
|
pub(crate) async fn resolve_ap_identifier<ActorType, DbActor>(
|
||||||
identifier: &str,
|
identifier: &str,
|
||||||
context: &Data<LemmyContext>,
|
context: &Data<LemmyContext>,
|
||||||
local_user_view: &Option<LocalUserView>,
|
local_user_view: &Option<LocalUserView>,
|
||||||
|
|
|
@ -45,7 +45,7 @@ pub(crate) struct CommunityPath {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Clone)]
|
#[derive(Deserialize, Clone)]
|
||||||
pub struct CommunityIsFollowerQuery {
|
pub(crate) struct CommunityIsFollowerQuery {
|
||||||
is_follower: Option<ObjectId<SiteOrMultiOrCommunityOrUser>>,
|
is_follower: Option<ObjectId<SiteOrMultiOrCommunityOrUser>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,13 +84,13 @@ impl ReceiveActivityHook<SharedInboxActivities, UserOrCommunity, LemmyContext> f
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct ActivityQuery {
|
struct ActivityQuery {
|
||||||
type_: String,
|
type_: String,
|
||||||
id: String,
|
id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the ActivityPub json representation of a local activity over HTTP.
|
/// Return the ActivityPub json representation of a local activity over HTTP.
|
||||||
pub(crate) async fn get_activity(
|
async fn get_activity(
|
||||||
info: web::Path<ActivityQuery>,
|
info: web::Path<ActivityQuery>,
|
||||||
context: Data<LemmyContext>,
|
context: Data<LemmyContext>,
|
||||||
) -> LemmyResult<HttpResponse> {
|
) -> LemmyResult<HttpResponse> {
|
||||||
|
|
|
@ -15,7 +15,7 @@ use lemmy_utils::{
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
pub struct PersonQuery {
|
pub(crate) struct PersonQuery {
|
||||||
user_name: String,
|
user_name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -251,7 +251,7 @@ impl InCommunity for Page {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Only allows deserialization if the field is missing or null. If it is present, throws an error.
|
/// Only allows deserialization if the field is missing or null. If it is present, throws an error.
|
||||||
pub fn deserialize_not_present<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
|
fn deserialize_not_present<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
|
||||||
where
|
where
|
||||||
D: Deserializer<'de>,
|
D: Deserializer<'de>,
|
||||||
{
|
{
|
||||||
|
|
|
@ -34,7 +34,7 @@ pub struct Mention {
|
||||||
pub kind: MentionType,
|
pub kind: MentionType,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct MentionsAndAddresses {
|
pub(crate) struct MentionsAndAddresses {
|
||||||
pub ccs: Vec<Url>,
|
pub ccs: Vec<Url>,
|
||||||
pub tags: Vec<MentionOrValue>,
|
pub tags: Vec<MentionOrValue>,
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ pub struct MentionsAndAddresses {
|
||||||
/// This takes a comment, and builds a list of to_addresses, inboxes,
|
/// This takes a comment, and builds a list of to_addresses, inboxes,
|
||||||
/// and mention tags, so they know where to be sent to.
|
/// and mention tags, so they know where to be sent to.
|
||||||
/// Addresses are the persons / addresses that go in the cc field.
|
/// Addresses are the persons / addresses that go in the cc field.
|
||||||
pub async fn collect_non_local_mentions(
|
pub(crate) async fn collect_non_local_mentions(
|
||||||
comment: &ApubComment,
|
comment: &ApubComment,
|
||||||
context: &Data<LemmyContext>,
|
context: &Data<LemmyContext>,
|
||||||
) -> LemmyResult<MentionsAndAddresses> {
|
) -> LemmyResult<MentionsAndAddresses> {
|
||||||
|
|
|
@ -349,38 +349,6 @@ impl CommunityActions {
|
||||||
.with_lemmy_type(LemmyErrorType::NotFound)
|
.with_lemmy_type(LemmyErrorType::NotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks to make sure the acting moderator was added earlier than the target moderator
|
|
||||||
pub async fn is_higher_mod_check(
|
|
||||||
pool: &mut DbPool<'_>,
|
|
||||||
for_community_id: CommunityId,
|
|
||||||
mod_person_id: PersonId,
|
|
||||||
target_person_ids: Vec<PersonId>,
|
|
||||||
) -> LemmyResult<()> {
|
|
||||||
let conn = &mut get_conn(pool).await?;
|
|
||||||
|
|
||||||
// Build the list of persons
|
|
||||||
let mut persons = target_person_ids;
|
|
||||||
persons.push(mod_person_id);
|
|
||||||
persons.dedup();
|
|
||||||
|
|
||||||
let res = community_actions::table
|
|
||||||
.filter(community_actions::became_moderator_at.is_not_null())
|
|
||||||
.filter(community_actions::community_id.eq(for_community_id))
|
|
||||||
.filter(community_actions::person_id.eq_any(persons))
|
|
||||||
.order_by(community_actions::became_moderator_at)
|
|
||||||
.select(community_actions::person_id)
|
|
||||||
// This does a limit 1 select first
|
|
||||||
.first::<PersonId>(conn)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// If the first result sorted by published is the acting mod
|
|
||||||
if res == mod_person_id {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(LemmyErrorType::NotHigherMod)?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check if we should accept activity in remote community. This requires either:
|
/// Check if we should accept activity in remote community. This requires either:
|
||||||
/// - Local follower of the community
|
/// - Local follower of the community
|
||||||
/// - Local post or comment in the community
|
/// - Local post or comment in the community
|
||||||
|
@ -848,16 +816,6 @@ mod tests {
|
||||||
let moderator_person_ids = vec![inserted_bobby.id, inserted_artemis.id];
|
let moderator_person_ids = vec![inserted_bobby.id, inserted_artemis.id];
|
||||||
|
|
||||||
// Make sure bobby is marked as a higher mod than artemis, and vice versa
|
// Make sure bobby is marked as a higher mod than artemis, and vice versa
|
||||||
let bobby_higher_check = CommunityActions::is_higher_mod_check(
|
|
||||||
pool,
|
|
||||||
inserted_community.id,
|
|
||||||
inserted_bobby.id,
|
|
||||||
moderator_person_ids.clone(),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
assert!(bobby_higher_check.is_ok());
|
|
||||||
|
|
||||||
// Also check the other is_higher_mod_or_admin function just in case
|
|
||||||
let bobby_higher_check_2 = LocalUser::is_higher_mod_or_admin_check(
|
let bobby_higher_check_2 = LocalUser::is_higher_mod_or_admin_check(
|
||||||
pool,
|
pool,
|
||||||
inserted_community.id,
|
inserted_community.id,
|
||||||
|
@ -868,7 +826,7 @@ mod tests {
|
||||||
assert!(bobby_higher_check_2.is_ok());
|
assert!(bobby_higher_check_2.is_ok());
|
||||||
|
|
||||||
// This should throw an error, since artemis was added later
|
// This should throw an error, since artemis was added later
|
||||||
let artemis_higher_check = CommunityActions::is_higher_mod_check(
|
let artemis_higher_check = LocalUser::is_higher_mod_or_admin_check(
|
||||||
pool,
|
pool,
|
||||||
inserted_community.id,
|
inserted_community.id,
|
||||||
inserted_artemis.id,
|
inserted_artemis.id,
|
||||||
|
|
|
@ -517,25 +517,6 @@ impl PostActions {
|
||||||
.await
|
.await
|
||||||
.with_lemmy_type(LemmyErrorType::CouldntUpdateReadComments)
|
.with_lemmy_type(LemmyErrorType::CouldntUpdateReadComments)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn remove_read_comments(
|
|
||||||
pool: &mut DbPool<'_>,
|
|
||||||
person_id: PersonId,
|
|
||||||
post_id: PostId,
|
|
||||||
) -> LemmyResult<UpleteCount> {
|
|
||||||
let conn = &mut get_conn(pool).await?;
|
|
||||||
|
|
||||||
uplete(
|
|
||||||
post_actions::table
|
|
||||||
.filter(post_actions::post_id.eq(post_id))
|
|
||||||
.filter(post_actions::person_id.eq(person_id)),
|
|
||||||
)
|
|
||||||
.set_null(post_actions::read_comments_amount)
|
|
||||||
.set_null(post_actions::read_comments_at)
|
|
||||||
.get_result(conn)
|
|
||||||
.await
|
|
||||||
.with_lemmy_type(LemmyErrorType::CouldntUpdateReadComments)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PostActions {
|
impl PostActions {
|
||||||
|
|
|
@ -33,10 +33,7 @@ pub mod utils;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use strum::{Display, EnumString};
|
use strum::{Display, EnumString};
|
||||||
#[cfg(feature = "full")]
|
#[cfg(feature = "full")]
|
||||||
use {
|
use {diesel::query_source::AliasedField, lemmy_db_schema_file::schema::person};
|
||||||
diesel::query_source::AliasedField,
|
|
||||||
lemmy_db_schema_file::schema::{community_actions, instance_actions, person},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default, Hash,
|
EnumString, Display, Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Default, Hash,
|
||||||
|
@ -236,47 +233,3 @@ pub type Person2AliasAllColumnsTuple = (
|
||||||
AliasedField<aliases::Person2, person::comment_count>,
|
AliasedField<aliases::Person2, person::comment_count>,
|
||||||
AliasedField<aliases::Person2, person::comment_score>,
|
AliasedField<aliases::Person2, person::comment_score>,
|
||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(feature = "full")]
|
|
||||||
/// A helper tuple for creator community actions
|
|
||||||
pub type CreatorCommunityActionsAllColumnsTuple = (
|
|
||||||
AliasedField<aliases::CreatorCommunityActions, community_actions::community_id>,
|
|
||||||
AliasedField<aliases::CreatorCommunityActions, community_actions::person_id>,
|
|
||||||
AliasedField<aliases::CreatorCommunityActions, community_actions::followed_at>,
|
|
||||||
AliasedField<aliases::CreatorCommunityActions, community_actions::follow_state>,
|
|
||||||
AliasedField<aliases::CreatorCommunityActions, community_actions::follow_approver_id>,
|
|
||||||
AliasedField<aliases::CreatorCommunityActions, community_actions::blocked_at>,
|
|
||||||
AliasedField<aliases::CreatorCommunityActions, community_actions::became_moderator_at>,
|
|
||||||
AliasedField<aliases::CreatorCommunityActions, community_actions::received_ban_at>,
|
|
||||||
AliasedField<aliases::CreatorCommunityActions, community_actions::ban_expires_at>,
|
|
||||||
);
|
|
||||||
|
|
||||||
#[cfg(feature = "full")]
|
|
||||||
/// A helper tuple for creator home instance actions.
|
|
||||||
pub type CreatorHomeInstanceActionsAllColumnsTuple = (
|
|
||||||
AliasedField<aliases::CreatorHomeInstanceActions, instance_actions::person_id>,
|
|
||||||
AliasedField<aliases::CreatorHomeInstanceActions, instance_actions::instance_id>,
|
|
||||||
AliasedField<aliases::CreatorHomeInstanceActions, instance_actions::blocked_at>,
|
|
||||||
AliasedField<aliases::CreatorHomeInstanceActions, instance_actions::received_ban_at>,
|
|
||||||
AliasedField<aliases::CreatorHomeInstanceActions, instance_actions::ban_expires_at>,
|
|
||||||
);
|
|
||||||
|
|
||||||
#[cfg(feature = "full")]
|
|
||||||
/// A helper tuple for creator local instance actions.
|
|
||||||
pub type CreatorLocalInstanceActionsAllColumnsTuple = (
|
|
||||||
AliasedField<aliases::CreatorLocalInstanceActions, instance_actions::person_id>,
|
|
||||||
AliasedField<aliases::CreatorLocalInstanceActions, instance_actions::instance_id>,
|
|
||||||
AliasedField<aliases::CreatorLocalInstanceActions, instance_actions::blocked_at>,
|
|
||||||
AliasedField<aliases::CreatorLocalInstanceActions, instance_actions::received_ban_at>,
|
|
||||||
AliasedField<aliases::CreatorLocalInstanceActions, instance_actions::ban_expires_at>,
|
|
||||||
);
|
|
||||||
|
|
||||||
#[cfg(feature = "full")]
|
|
||||||
/// A helper tuple for creator home instance actions.
|
|
||||||
pub type CreatorCommunityInstanceActionsAllColumnsTuple = (
|
|
||||||
AliasedField<aliases::CreatorCommunityInstanceActions, instance_actions::person_id>,
|
|
||||||
AliasedField<aliases::CreatorCommunityInstanceActions, instance_actions::instance_id>,
|
|
||||||
AliasedField<aliases::CreatorCommunityInstanceActions, instance_actions::blocked_at>,
|
|
||||||
AliasedField<aliases::CreatorCommunityInstanceActions, instance_actions::received_ban_at>,
|
|
||||||
AliasedField<aliases::CreatorCommunityInstanceActions, instance_actions::ban_expires_at>,
|
|
||||||
);
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ use chrono::TimeDelta;
|
||||||
use deadpool::Runtime;
|
use deadpool::Runtime;
|
||||||
use diesel::{
|
use diesel::{
|
||||||
dsl,
|
dsl,
|
||||||
expression::AsExpression,
|
|
||||||
helper_types::AsExprOf,
|
helper_types::AsExprOf,
|
||||||
pg::{data_types::PgInterval, Pg},
|
pg::{data_types::PgInterval, Pg},
|
||||||
query_builder::{Query, QueryFragment},
|
query_builder::{Query, QueryFragment},
|
||||||
|
@ -36,7 +35,6 @@ use lemmy_utils::{
|
||||||
settings::{structs::Settings, SETTINGS},
|
settings::{structs::Settings, SETTINGS},
|
||||||
utils::validation::clean_url,
|
utils::validation::clean_url,
|
||||||
};
|
};
|
||||||
use regex::Regex;
|
|
||||||
use rustls::{
|
use rustls::{
|
||||||
client::danger::{
|
client::danger::{
|
||||||
DangerousClientConfigBuilder,
|
DangerousClientConfigBuilder,
|
||||||
|
@ -52,7 +50,7 @@ use rustls::{
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
sync::{Arc, LazyLock, OnceLock},
|
sync::{Arc, OnceLock},
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
@ -238,7 +236,7 @@ impl<T> Commented<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds `text` to the comment if `condition` is true
|
/// Adds `text` to the comment if `condition` is true
|
||||||
pub fn text_if(mut self, text: &str, condition: bool) -> Self {
|
fn text_if(mut self, text: &str, condition: bool) -> Self {
|
||||||
if condition {
|
if condition {
|
||||||
if !self.comment.is_empty() {
|
if !self.comment.is_empty() {
|
||||||
self.comment.push_str(", ");
|
self.comment.push_str(", ");
|
||||||
|
@ -304,10 +302,6 @@ pub fn limit_fetch(limit: Option<i64>) -> LemmyResult<i64> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_email_regex(test: &str) -> bool {
|
|
||||||
EMAIL_REGEX.is_match(test)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Takes an API optional text input, and converts it to an optional diesel DB update.
|
/// Takes an API optional text input, and converts it to an optional diesel DB update.
|
||||||
pub fn diesel_string_update(opt: Option<&str>) -> Option<Option<String>> {
|
pub fn diesel_string_update(opt: Option<&str>) -> Option<Option<String>> {
|
||||||
match opt {
|
match opt {
|
||||||
|
@ -520,12 +514,6 @@ pub fn build_db_pool_for_tests() -> ActualDbPool {
|
||||||
build_db_pool().expect("db pool missing")
|
build_db_pool().expect("db pool missing")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::expect_used)]
|
|
||||||
static EMAIL_REGEX: LazyLock<Regex> = LazyLock::new(|| {
|
|
||||||
Regex::new(r"^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$")
|
|
||||||
.expect("compile email regex")
|
|
||||||
});
|
|
||||||
|
|
||||||
pub mod functions {
|
pub mod functions {
|
||||||
use diesel::sql_types::{BigInt, Text, Timestamptz};
|
use diesel::sql_types::{BigInt, Text, Timestamptz};
|
||||||
|
|
||||||
|
@ -539,13 +527,6 @@ pub mod functions {
|
||||||
fn scaled_rank(score: BigInt, time: Timestamptz, interactions_month: BigInt) -> Double;
|
fn scaled_rank(score: BigInt, time: Timestamptz, interactions_month: BigInt) -> Double;
|
||||||
}
|
}
|
||||||
|
|
||||||
define_sql_function! {
|
|
||||||
#[sql_name = "r.controversy_rank"]
|
|
||||||
fn controversy_rank(upvotes: BigInt, downvotes: BigInt, score: BigInt) -> Double;
|
|
||||||
}
|
|
||||||
|
|
||||||
define_sql_function!(fn reverse_timestamp_sort(time: Timestamptz) -> BigInt);
|
|
||||||
|
|
||||||
define_sql_function!(fn lower(x: Text) -> Text);
|
define_sql_function!(fn lower(x: Text) -> Text);
|
||||||
|
|
||||||
define_sql_function!(fn random() -> Text);
|
define_sql_function!(fn random() -> Text);
|
||||||
|
@ -574,31 +555,11 @@ pub fn seconds_to_pg_interval(seconds: i32) -> PgInterval {
|
||||||
PgInterval::from_microseconds(i64::from(seconds) * 1_000_000)
|
PgInterval::from_microseconds(i64::from(seconds) * 1_000_000)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait alias for a type that can be converted to an SQL tuple using `IntoSql::into_sql`
|
|
||||||
pub trait AsRecord: Expression + AsExpression<sql_types::Record<Self::SqlType>>
|
|
||||||
where
|
|
||||||
Self::SqlType: 'static,
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Expression + AsExpression<sql_types::Record<T::SqlType>>> AsRecord for T where
|
|
||||||
T::SqlType: 'static
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Output of `IntoSql::into_sql` for a type that implements `AsRecord`
|
/// Output of `IntoSql::into_sql` for a type that implements `AsRecord`
|
||||||
pub type AsRecordOutput<T> = dsl::AsExprOf<T, sql_types::Record<<T as Expression>::SqlType>>;
|
pub type AsRecordOutput<T> = dsl::AsExprOf<T, sql_types::Record<<T as Expression>::SqlType>>;
|
||||||
|
|
||||||
pub type ResultFuture<'a, T> = BoxFuture<'a, Result<T, DieselError>>;
|
pub type ResultFuture<'a, T> = BoxFuture<'a, Result<T, DieselError>>;
|
||||||
|
|
||||||
pub trait ReadFn<'a, T, Args>: Fn(DbConn<'a>, Args) -> ResultFuture<'a, T> {}
|
|
||||||
|
|
||||||
impl<'a, T, Args, F: Fn(DbConn<'a>, Args) -> ResultFuture<'a, T>> ReadFn<'a, T, Args> for F {}
|
|
||||||
|
|
||||||
pub trait ListFn<'a, T, Args>: Fn(DbConn<'a>, Args) -> ResultFuture<'a, Vec<T>> {}
|
|
||||||
|
|
||||||
impl<'a, T, Args, F: Fn(DbConn<'a>, Args) -> ResultFuture<'a, Vec<T>>> ListFn<'a, T, Args> for F {}
|
|
||||||
|
|
||||||
pub fn paginate<Q, C>(
|
pub fn paginate<Q, C>(
|
||||||
query: Q,
|
query: Q,
|
||||||
sort_direction: SortDirection,
|
sort_direction: SortDirection,
|
||||||
|
@ -664,12 +625,6 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_email() {
|
|
||||||
assert!(is_email_regex("gush@gmail.com"));
|
|
||||||
assert!(!is_email_regex("nada_neutho"));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_diesel_option_overwrite() {
|
fn test_diesel_option_overwrite() {
|
||||||
assert_eq!(diesel_string_update(None), None);
|
assert_eq!(diesel_string_update(None), None);
|
||||||
|
|
|
@ -63,22 +63,6 @@ impl CommunityFollowerView {
|
||||||
.with_lemmy_type(LemmyErrorType::NotFound)
|
.with_lemmy_type(LemmyErrorType::NotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_community_follower_inboxes(
|
|
||||||
pool: &mut DbPool<'_>,
|
|
||||||
community_id: CommunityId,
|
|
||||||
) -> LemmyResult<Vec<DbUrl>> {
|
|
||||||
let conn = &mut get_conn(pool).await?;
|
|
||||||
let res = Self::joins()
|
|
||||||
.filter(community_actions::community_id.eq(community_id))
|
|
||||||
.filter(not(person::local))
|
|
||||||
.select(person::inbox_url)
|
|
||||||
.distinct()
|
|
||||||
.load::<DbUrl>(conn)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn count_community_followers(
|
pub async fn count_community_followers(
|
||||||
pool: &mut DbPool<'_>,
|
pool: &mut DbPool<'_>,
|
||||||
community_id: CommunityId,
|
community_id: CommunityId,
|
||||||
|
|
|
@ -18,6 +18,9 @@ doctest = false
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
|
[features]
|
||||||
|
full = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
lemmy_utils = { workspace = true, features = ["full"] }
|
lemmy_utils = { workspace = true, features = ["full"] }
|
||||||
lemmy_db_schema = { workspace = true, features = ["full"] }
|
lemmy_db_schema = { workspace = true, features = ["full"] }
|
||||||
|
|
|
@ -26,7 +26,7 @@ const CLEANUP_INTERVAL_SECS: u32 = 120;
|
||||||
/// Smaller than `std::time::Instant` because it uses a smaller integer for seconds and doesn't
|
/// Smaller than `std::time::Instant` because it uses a smaller integer for seconds and doesn't
|
||||||
/// store nanoseconds
|
/// store nanoseconds
|
||||||
#[derive(PartialEq, Debug, Clone, Copy, Hash)]
|
#[derive(PartialEq, Debug, Clone, Copy, Hash)]
|
||||||
pub struct InstantSecs {
|
struct InstantSecs {
|
||||||
pub secs: u32,
|
pub secs: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,6 @@ workspace = true
|
||||||
full = [
|
full = [
|
||||||
"diesel",
|
"diesel",
|
||||||
"actix-web",
|
"actix-web",
|
||||||
"reqwest-middleware",
|
|
||||||
"tracing",
|
"tracing",
|
||||||
"actix-web",
|
"actix-web",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
@ -60,7 +59,6 @@ serde_json = { workspace = true, optional = true }
|
||||||
url = { workspace = true, optional = true }
|
url = { workspace = true, optional = true }
|
||||||
actix-web = { workspace = true, optional = true }
|
actix-web = { workspace = true, optional = true }
|
||||||
anyhow = { workspace = true, optional = true }
|
anyhow = { workspace = true, optional = true }
|
||||||
reqwest-middleware = { workspace = true, optional = true }
|
|
||||||
strum = { workspace = true }
|
strum = { workspace = true }
|
||||||
futures = { workspace = true, optional = true }
|
futures = { workspace = true, optional = true }
|
||||||
diesel = { workspace = true, optional = true, features = ["chrono"] }
|
diesel = { workspace = true, optional = true, features = ["chrono"] }
|
||||||
|
|
|
@ -7,7 +7,7 @@ use actix_web::middleware::DefaultHeaders;
|
||||||
/// * 3 days = 60s * 60m * 24h * 3d = `259200` seconds
|
/// * 3 days = 60s * 60m * 24h * 3d = `259200` seconds
|
||||||
///
|
///
|
||||||
/// Mastodon & other activitypub server defaults to 3d
|
/// Mastodon & other activitypub server defaults to 3d
|
||||||
pub fn cache_header(seconds: usize) -> DefaultHeaders {
|
fn cache_header(seconds: usize) -> DefaultHeaders {
|
||||||
DefaultHeaders::new().add(("Cache-Control", format!("public, max-age={seconds}")))
|
DefaultHeaders::new().add(("Cache-Control", format!("public, max-age={seconds}")))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ cfg_if! {
|
||||||
if #[cfg(feature = "full")] {
|
if #[cfg(feature = "full")] {
|
||||||
pub mod cache_header;
|
pub mod cache_header;
|
||||||
pub mod rate_limit;
|
pub mod rate_limit;
|
||||||
pub mod request;
|
|
||||||
pub mod response;
|
pub mod response;
|
||||||
pub mod settings;
|
pub mod settings;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
use std::future::Future;
|
|
||||||
|
|
||||||
pub async fn retry<F, Fut, T>(f: F) -> Result<T, reqwest_middleware::Error>
|
|
||||||
where
|
|
||||||
F: Fn() -> Fut,
|
|
||||||
Fut: Future<Output = Result<T, reqwest_middleware::Error>>,
|
|
||||||
{
|
|
||||||
retry_custom(|| async { Ok((f)().await) }).await
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::expect_used)]
|
|
||||||
async fn retry_custom<F, Fut, T>(f: F) -> Result<T, reqwest_middleware::Error>
|
|
||||||
where
|
|
||||||
F: Fn() -> Fut,
|
|
||||||
Fut: Future<Output = Result<Result<T, reqwest_middleware::Error>, reqwest_middleware::Error>>,
|
|
||||||
{
|
|
||||||
let mut response: Option<Result<T, reqwest_middleware::Error>> = None;
|
|
||||||
|
|
||||||
for _ in 0u8..3 {
|
|
||||||
match (f)().await? {
|
|
||||||
Ok(t) => return Ok(t),
|
|
||||||
Err(reqwest_middleware::Error::Reqwest(e)) => {
|
|
||||||
if e.is_timeout() {
|
|
||||||
response = Some(Err(reqwest_middleware::Error::Reqwest(e)));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
return Err(reqwest_middleware::Error::Reqwest(e));
|
|
||||||
}
|
|
||||||
Err(otherwise) => {
|
|
||||||
return Err(otherwise);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
response.expect("retry http request")
|
|
||||||
}
|
|
|
@ -1,7 +1,6 @@
|
||||||
use crate::{error::LemmyResult, location_info};
|
use crate::{error::LemmyResult, location_info};
|
||||||
use anyhow::{anyhow, Context};
|
use anyhow::{anyhow, Context};
|
||||||
use deser_hjson::from_str;
|
use deser_hjson::from_str;
|
||||||
use regex::Regex;
|
|
||||||
use std::{env, fs, sync::LazyLock};
|
use std::{env, fs, sync::LazyLock};
|
||||||
use structs::{PictrsConfig, Settings};
|
use structs::{PictrsConfig, Settings};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
@ -23,15 +22,6 @@ pub static SETTINGS: LazyLock<Settings> = LazyLock::new(|| {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
#[allow(clippy::expect_used)]
|
|
||||||
static WEBFINGER_REGEX: LazyLock<Regex> = LazyLock::new(|| {
|
|
||||||
Regex::new(&format!(
|
|
||||||
"^acct:([a-zA-Z0-9_]{{3,}})@{}$",
|
|
||||||
SETTINGS.hostname
|
|
||||||
))
|
|
||||||
.expect("compile webfinger regex")
|
|
||||||
});
|
|
||||||
|
|
||||||
impl Settings {
|
impl Settings {
|
||||||
/// Reads config from configuration file.
|
/// Reads config from configuration file.
|
||||||
///
|
///
|
||||||
|
@ -59,7 +49,7 @@ impl Settings {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns either "http" or "https", depending on tls_enabled setting
|
/// Returns either "http" or "https", depending on tls_enabled setting
|
||||||
pub fn get_protocol_string(&self) -> &'static str {
|
fn get_protocol_string(&self) -> &'static str {
|
||||||
if self.tls_enabled {
|
if self.tls_enabled {
|
||||||
"https"
|
"https"
|
||||||
} else {
|
} else {
|
||||||
|
@ -88,10 +78,6 @@ impl Settings {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn webfinger_regex(&self) -> Regex {
|
|
||||||
WEBFINGER_REGEX.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn pictrs(&self) -> LemmyResult<PictrsConfig> {
|
pub fn pictrs(&self) -> LemmyResult<PictrsConfig> {
|
||||||
self
|
self
|
||||||
.pictrs
|
.pictrs
|
||||||
|
|
|
@ -91,7 +91,7 @@ fn find_urls<T: NodeValue + UrlAndTitle>(src: &str) -> Vec<(usize, usize)> {
|
||||||
links_offsets
|
links_offsets
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait UrlAndTitle {
|
trait UrlAndTitle {
|
||||||
fn url_len(&self) -> usize;
|
fn url_len(&self) -> usize;
|
||||||
fn title_len(&self) -> usize;
|
fn title_len(&self) -> usize;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,19 +20,6 @@ static MARKDOWN_PARSER: LazyLock<MarkdownIt> = LazyLock::new(|| {
|
||||||
parser
|
parser
|
||||||
});
|
});
|
||||||
|
|
||||||
/// Replace special HTML characters in API parameters to prevent XSS attacks.
|
|
||||||
///
|
|
||||||
/// Taken from https://github.com/OWASP/CheatSheetSeries/blob/master/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.md#output-encoding-for-html-contexts
|
|
||||||
///
|
|
||||||
/// `>` is left in place because it is interpreted as markdown quote.
|
|
||||||
pub fn sanitize_html(text: &str) -> String {
|
|
||||||
text
|
|
||||||
.replace('&', "&")
|
|
||||||
.replace('<', "<")
|
|
||||||
.replace('\"', """)
|
|
||||||
.replace('\'', "'")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn markdown_to_html(text: &str) -> String {
|
pub fn markdown_to_html(text: &str) -> String {
|
||||||
MARKDOWN_PARSER.parse(text).xrender()
|
MARKDOWN_PARSER.parse(text).xrender()
|
||||||
}
|
}
|
||||||
|
@ -231,16 +218,4 @@ mod tests {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_sanitize_html() {
|
|
||||||
let sanitized = sanitize_html("<script>alert('xss');</script> hello &\"'");
|
|
||||||
let expected = "<script>alert('xss');</script> hello &"'";
|
|
||||||
assert_eq!(expected, sanitized);
|
|
||||||
|
|
||||||
let sanitized =
|
|
||||||
sanitize_html("Polling the group: what do y'all know about the Orion browser from Kagi?");
|
|
||||||
let expected = "Polling the group: what do y'all know about the Orion browser from Kagi?";
|
|
||||||
assert_eq!(expected, sanitized);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -286,7 +286,7 @@ pub fn check_blocking_keywords_are_valid(blocking_keywords: &Vec<String>) -> Lem
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_url_str_without_scheme(url_str: &str) -> LemmyResult<String> {
|
fn build_url_str_without_scheme(url_str: &str) -> LemmyResult<String> {
|
||||||
// Parse and check for errors
|
// Parse and check for errors
|
||||||
let mut url = Url::parse(url_str).or_else(|e| {
|
let mut url = Url::parse(url_str).or_else(|e| {
|
||||||
if e == ParseError::RelativeUrlWithoutBase {
|
if e == ParseError::RelativeUrlWithoutBase {
|
||||||
|
@ -317,7 +317,7 @@ pub fn build_url_str_without_scheme(url_str: &str) -> LemmyResult<String> {
|
||||||
|
|
||||||
// Shorten a string to n chars, being mindful of unicode grapheme
|
// Shorten a string to n chars, being mindful of unicode grapheme
|
||||||
// boundaries
|
// boundaries
|
||||||
pub fn truncate_for_db(text: &str, len: usize) -> String {
|
fn truncate_for_db(text: &str, len: usize) -> String {
|
||||||
if text.chars().count() <= len {
|
if text.chars().count() <= len {
|
||||||
text.to_string()
|
text.to_string()
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue