Remove unused items (#5870)

* Remove some unused functions

* shear

* remove more

* full feature

* remove more

* some more

* mroe
This commit is contained in:
Nutomic 2025-07-18 14:21:43 +00:00 committed by GitHub
parent 72d254b4db
commit f65875c27a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 36 additions and 293 deletions

1
Cargo.lock generated
View file

@ -3962,7 +3962,6 @@ dependencies = [
"moka",
"pretty_assertions",
"regex",
"reqwest-middleware",
"serde",
"serde_json",
"smart-default",

View file

@ -42,16 +42,11 @@ default = []
[workspace]
members = [
"crates/api/api",
"crates/api/api_crud",
"crates/api/api_common",
"crates/api/api_utils",
"crates/apub",
"crates/apub_objects",
"crates/utils",
"crates/db_schema",
"crates/db_schema_file",
"crates/db_schema_setup",
"crates/email",
"crates/db_views/private_message",
"crates/db_views/local_user",
"crates/db_views/local_image",
@ -73,9 +68,14 @@ members = [
"crates/db_views/report_combined",
"crates/db_views/search_combined",
"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/email",
"crates/routes",
]
[workspace.lints.clippy]

View file

@ -18,6 +18,9 @@ doctest = false
[lints]
workspace = true
[features]
full = []
[dependencies]
lemmy_db_views_comment = { workspace = true, features = ["full"] }
lemmy_db_views_community = { workspace = true, features = ["full"] }

View file

@ -18,6 +18,7 @@ doctest = false
workspace = true
[features]
full = []
ts-rs = [
"lemmy_utils/ts-rs",
"lemmy_db_schema/ts-rs",

View file

@ -13,6 +13,9 @@ rust-version.workspace = true
[lints]
workspace = true
[features]
full = []
[dependencies]
lemmy_db_views_comment = { workspace = true, features = ["full"] }
lemmy_db_views_community = { workspace = true, features = ["full"] }

View file

@ -332,12 +332,6 @@ impl PictrsFile {
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.

View file

@ -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
/// However, skip checking verification if the user is an admin
pub fn check_email_verified(

View file

@ -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
/// 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,
context: &Data<LemmyContext>,
local_user_view: &Option<LocalUserView>,

View file

@ -45,7 +45,7 @@ pub(crate) struct CommunityPath {
}
#[derive(Deserialize, Clone)]
pub struct CommunityIsFollowerQuery {
pub(crate) struct CommunityIsFollowerQuery {
is_follower: Option<ObjectId<SiteOrMultiOrCommunityOrUser>>,
}

View file

@ -84,13 +84,13 @@ impl ReceiveActivityHook<SharedInboxActivities, UserOrCommunity, LemmyContext> f
}
#[derive(Deserialize)]
pub struct ActivityQuery {
struct ActivityQuery {
type_: String,
id: String,
}
/// 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>,
context: Data<LemmyContext>,
) -> LemmyResult<HttpResponse> {

View file

@ -15,7 +15,7 @@ use lemmy_utils::{
use serde::Deserialize;
#[derive(Deserialize)]
pub struct PersonQuery {
pub(crate) struct PersonQuery {
user_name: String,
}

View file

@ -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.
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
D: Deserializer<'de>,
{

View file

@ -34,7 +34,7 @@ pub struct Mention {
pub kind: MentionType,
}
pub struct MentionsAndAddresses {
pub(crate) struct MentionsAndAddresses {
pub ccs: Vec<Url>,
pub tags: Vec<MentionOrValue>,
}
@ -42,7 +42,7 @@ pub struct MentionsAndAddresses {
/// This takes a comment, and builds a list of to_addresses, inboxes,
/// and mention tags, so they know where to be sent to.
/// 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,
context: &Data<LemmyContext>,
) -> LemmyResult<MentionsAndAddresses> {

View file

@ -349,38 +349,6 @@ impl CommunityActions {
.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:
/// - Local follower of 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];
// 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(
pool,
inserted_community.id,
@ -868,7 +826,7 @@ mod tests {
assert!(bobby_higher_check_2.is_ok());
// 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,
inserted_community.id,
inserted_artemis.id,

View file

@ -517,25 +517,6 @@ impl PostActions {
.await
.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 {

View file

@ -33,10 +33,7 @@ pub mod utils;
use serde::{Deserialize, Serialize};
use strum::{Display, EnumString};
#[cfg(feature = "full")]
use {
diesel::query_source::AliasedField,
lemmy_db_schema_file::schema::{community_actions, instance_actions, person},
};
use {diesel::query_source::AliasedField, lemmy_db_schema_file::schema::person};
#[derive(
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_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>,
);

View file

@ -5,7 +5,6 @@ use chrono::TimeDelta;
use deadpool::Runtime;
use diesel::{
dsl,
expression::AsExpression,
helper_types::AsExprOf,
pg::{data_types::PgInterval, Pg},
query_builder::{Query, QueryFragment},
@ -36,7 +35,6 @@ use lemmy_utils::{
settings::{structs::Settings, SETTINGS},
utils::validation::clean_url,
};
use regex::Regex;
use rustls::{
client::danger::{
DangerousClientConfigBuilder,
@ -52,7 +50,7 @@ use rustls::{
};
use std::{
ops::{Deref, DerefMut},
sync::{Arc, LazyLock, OnceLock},
sync::{Arc, OnceLock},
time::Duration,
};
use tracing::error;
@ -238,7 +236,7 @@ impl<T> Commented<T> {
}
/// 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 !self.comment.is_empty() {
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.
pub fn diesel_string_update(opt: Option<&str>) -> Option<Option<String>> {
match opt {
@ -520,12 +514,6 @@ pub fn build_db_pool_for_tests() -> ActualDbPool {
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 {
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;
}
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 random() -> Text);
@ -574,31 +555,11 @@ pub fn seconds_to_pg_interval(seconds: i32) -> PgInterval {
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`
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 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>(
query: Q,
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]
fn test_diesel_option_overwrite() {
assert_eq!(diesel_string_update(None), None);

View file

@ -63,22 +63,6 @@ impl CommunityFollowerView {
.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(
pool: &mut DbPool<'_>,
community_id: CommunityId,

View file

@ -18,6 +18,9 @@ doctest = false
[lints]
workspace = true
[features]
full = []
[dependencies]
lemmy_utils = { workspace = true, features = ["full"] }
lemmy_db_schema = { workspace = true, features = ["full"] }

View file

@ -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
/// store nanoseconds
#[derive(PartialEq, Debug, Clone, Copy, Hash)]
pub struct InstantSecs {
struct InstantSecs {
pub secs: u32,
}

View file

@ -26,7 +26,6 @@ workspace = true
full = [
"diesel",
"actix-web",
"reqwest-middleware",
"tracing",
"actix-web",
"serde_json",
@ -60,7 +59,6 @@ serde_json = { workspace = true, optional = true }
url = { workspace = true, optional = true }
actix-web = { workspace = true, optional = true }
anyhow = { workspace = true, optional = true }
reqwest-middleware = { workspace = true, optional = true }
strum = { workspace = true }
futures = { workspace = true, optional = true }
diesel = { workspace = true, optional = true, features = ["chrono"] }

View file

@ -7,7 +7,7 @@ use actix_web::middleware::DefaultHeaders;
/// * 3 days = 60s * 60m * 24h * 3d = `259200` seconds
///
/// 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}")))
}

View file

@ -5,7 +5,6 @@ cfg_if! {
if #[cfg(feature = "full")] {
pub mod cache_header;
pub mod rate_limit;
pub mod request;
pub mod response;
pub mod settings;
pub mod utils;

View file

@ -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")
}

View file

@ -1,7 +1,6 @@
use crate::{error::LemmyResult, location_info};
use anyhow::{anyhow, Context};
use deser_hjson::from_str;
use regex::Regex;
use std::{env, fs, sync::LazyLock};
use structs::{PictrsConfig, Settings};
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 {
/// Reads config from configuration file.
///
@ -59,7 +49,7 @@ impl Settings {
}
/// 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 {
"https"
} else {
@ -88,10 +78,6 @@ impl Settings {
)
}
pub fn webfinger_regex(&self) -> Regex {
WEBFINGER_REGEX.clone()
}
pub fn pictrs(&self) -> LemmyResult<PictrsConfig> {
self
.pictrs

View file

@ -91,7 +91,7 @@ fn find_urls<T: NodeValue + UrlAndTitle>(src: &str) -> Vec<(usize, usize)> {
links_offsets
}
pub trait UrlAndTitle {
trait UrlAndTitle {
fn url_len(&self) -> usize;
fn title_len(&self) -> usize;
}

View file

@ -20,19 +20,6 @@ static MARKDOWN_PARSER: LazyLock<MarkdownIt> = LazyLock::new(|| {
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('&', "&amp;")
.replace('<', "&lt;")
.replace('\"', "&quot;")
.replace('\'', "&#x27;")
}
pub fn markdown_to_html(text: &str) -> String {
MARKDOWN_PARSER.parse(text).xrender()
}
@ -231,16 +218,4 @@ mod tests {
Ok(())
}
#[test]
fn test_sanitize_html() {
let sanitized = sanitize_html("<script>alert('xss');</script> hello &\"'");
let expected = "&lt;script>alert(&#x27;xss&#x27;);&lt;/script> hello &amp;&quot;&#x27;";
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&#x27;all know about the Orion browser from Kagi?";
assert_eq!(expected, sanitized);
}
}

View file

@ -286,7 +286,7 @@ pub fn check_blocking_keywords_are_valid(blocking_keywords: &Vec<String>) -> Lem
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
let mut url = Url::parse(url_str).or_else(|e| {
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
// 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 {
text.to_string()
} else {