Add delete-empty-profiles CLI command
This commit is contained in:
parent
ec03476b58
commit
8045b9f543
3 changed files with 100 additions and 0 deletions
|
@ -32,6 +32,7 @@ async fn main() {
|
|||
SubCommand::DeleteExtraneousPosts(cmd) => cmd.execute(&config, db_client).await.unwrap(),
|
||||
SubCommand::DeleteUnusedAttachments(cmd) => cmd.execute(&config, db_client).await.unwrap(),
|
||||
SubCommand::DeleteOrphanedFiles(cmd) => cmd.execute(&config, db_client).await.unwrap(),
|
||||
SubCommand::DeleteEmptyProfiles(cmd) => cmd.execute(&config, db_client).await.unwrap(),
|
||||
SubCommand::UpdateCurrentBlock(cmd) => cmd.execute(&config, db_client).await.unwrap(),
|
||||
SubCommand::ResetSubscriptions(cmd) => cmd.execute(&config, db_client).await.unwrap(),
|
||||
SubCommand::CreateMoneroWallet(cmd) => cmd.execute(&config).await.unwrap(),
|
||||
|
|
26
src/cli.rs
26
src/cli.rs
|
@ -17,6 +17,7 @@ use crate::models::cleanup::find_orphaned_files;
|
|||
use crate::models::posts::queries::{delete_post, find_extraneous_posts, get_post_by_id};
|
||||
use crate::models::profiles::queries::{
|
||||
delete_profile,
|
||||
find_empty_profiles,
|
||||
get_profile_by_id,
|
||||
get_profile_by_remote_actor_id,
|
||||
};
|
||||
|
@ -59,6 +60,7 @@ pub enum SubCommand {
|
|||
DeleteExtraneousPosts(DeleteExtraneousPosts),
|
||||
DeleteUnusedAttachments(DeleteUnusedAttachments),
|
||||
DeleteOrphanedFiles(DeleteOrphanedFiles),
|
||||
DeleteEmptyProfiles(DeleteEmptyProfiles),
|
||||
UpdateCurrentBlock(UpdateCurrentBlock),
|
||||
ResetSubscriptions(ResetSubscriptions),
|
||||
CreateMoneroWallet(CreateMoneroWallet),
|
||||
|
@ -316,6 +318,30 @@ impl DeleteOrphanedFiles {
|
|||
}
|
||||
}
|
||||
|
||||
/// Delete empty remote profiles
|
||||
#[derive(Parser)]
|
||||
pub struct DeleteEmptyProfiles {
|
||||
days: i64,
|
||||
}
|
||||
|
||||
impl DeleteEmptyProfiles {
|
||||
pub async fn execute(
|
||||
&self,
|
||||
config: &Config,
|
||||
db_client: &mut impl GenericClient,
|
||||
) -> Result<(), Error> {
|
||||
let updated_before = Utc::now() - Duration::days(self.days);
|
||||
let profiles = find_empty_profiles(db_client, &updated_before).await?;
|
||||
for profile_id in profiles {
|
||||
let profile = get_profile_by_id(db_client, &profile_id).await?;
|
||||
let deletion_queue = delete_profile(db_client, &profile.id).await?;
|
||||
deletion_queue.process(config).await;
|
||||
println!("profile {} deleted", profile.acct);
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Update blockchain synchronization starting block
|
||||
#[derive(Parser)]
|
||||
pub struct UpdateCurrentBlock {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use chrono::{DateTime, Utc};
|
||||
use tokio_postgres::GenericClient;
|
||||
use uuid::Uuid;
|
||||
|
||||
|
@ -573,6 +574,69 @@ pub async fn update_post_count(
|
|||
Ok(profile)
|
||||
}
|
||||
|
||||
/// Finds all empty remote profiles
|
||||
/// (without any posts, reactions, relationships)
|
||||
/// updated before the specified date
|
||||
pub async fn find_empty_profiles(
|
||||
db_client: &impl GenericClient,
|
||||
updated_before: &DateTime<Utc>,
|
||||
) -> Result<Vec<Uuid>, DatabaseError> {
|
||||
let rows = db_client.query(
|
||||
"
|
||||
SELECT actor_profile.id
|
||||
FROM actor_profile
|
||||
WHERE
|
||||
actor_profile.hostname IS NOT NULL
|
||||
AND actor_profile.updated_at < $1
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM relationship
|
||||
WHERE
|
||||
source_id = actor_profile.id
|
||||
OR target_id = actor_profile.id
|
||||
)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM follow_request
|
||||
WHERE
|
||||
source_id = actor_profile.id
|
||||
OR target_id = actor_profile.id
|
||||
)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM post
|
||||
WHERE author_id = actor_profile.id
|
||||
)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM post_reaction
|
||||
WHERE author_id = actor_profile.id
|
||||
)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM media_attachment
|
||||
WHERE owner_id = actor_profile.id
|
||||
)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM mention
|
||||
WHERE profile_id = actor_profile.id
|
||||
)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM notification
|
||||
WHERE sender_id = actor_profile.id
|
||||
)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM invoice
|
||||
WHERE sender_id = actor_profile.id
|
||||
)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM subscription
|
||||
WHERE sender_id = actor_profile.id
|
||||
)
|
||||
",
|
||||
&[&updated_before],
|
||||
).await?;
|
||||
let ids: Vec<Uuid> = rows.iter()
|
||||
.map(|row| row.try_get("id"))
|
||||
.collect::<Result<_, _>>()?;
|
||||
Ok(ids)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use serial_test::serial;
|
||||
|
@ -744,4 +808,13 @@ mod tests {
|
|||
assert_eq!(profiles.len(), 1);
|
||||
assert_eq!(profiles[0].id, profile.id);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn test_find_empty_profiles() {
|
||||
let db_client = &mut create_test_database().await;
|
||||
let updated_before = Utc::now();
|
||||
let profiles = find_empty_profiles(db_client, &updated_before).await.unwrap();
|
||||
assert_eq!(profiles.is_empty(), true);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue