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::DeleteExtraneousPosts(cmd) => cmd.execute(&config, db_client).await.unwrap(),
|
||||||
SubCommand::DeleteUnusedAttachments(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::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::UpdateCurrentBlock(cmd) => cmd.execute(&config, db_client).await.unwrap(),
|
||||||
SubCommand::ResetSubscriptions(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(),
|
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::posts::queries::{delete_post, find_extraneous_posts, get_post_by_id};
|
||||||
use crate::models::profiles::queries::{
|
use crate::models::profiles::queries::{
|
||||||
delete_profile,
|
delete_profile,
|
||||||
|
find_empty_profiles,
|
||||||
get_profile_by_id,
|
get_profile_by_id,
|
||||||
get_profile_by_remote_actor_id,
|
get_profile_by_remote_actor_id,
|
||||||
};
|
};
|
||||||
|
@ -59,6 +60,7 @@ pub enum SubCommand {
|
||||||
DeleteExtraneousPosts(DeleteExtraneousPosts),
|
DeleteExtraneousPosts(DeleteExtraneousPosts),
|
||||||
DeleteUnusedAttachments(DeleteUnusedAttachments),
|
DeleteUnusedAttachments(DeleteUnusedAttachments),
|
||||||
DeleteOrphanedFiles(DeleteOrphanedFiles),
|
DeleteOrphanedFiles(DeleteOrphanedFiles),
|
||||||
|
DeleteEmptyProfiles(DeleteEmptyProfiles),
|
||||||
UpdateCurrentBlock(UpdateCurrentBlock),
|
UpdateCurrentBlock(UpdateCurrentBlock),
|
||||||
ResetSubscriptions(ResetSubscriptions),
|
ResetSubscriptions(ResetSubscriptions),
|
||||||
CreateMoneroWallet(CreateMoneroWallet),
|
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
|
/// Update blockchain synchronization starting block
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
pub struct UpdateCurrentBlock {
|
pub struct UpdateCurrentBlock {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use chrono::{DateTime, Utc};
|
||||||
use tokio_postgres::GenericClient;
|
use tokio_postgres::GenericClient;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
@ -573,6 +574,69 @@ pub async fn update_post_count(
|
||||||
Ok(profile)
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use serial_test::serial;
|
use serial_test::serial;
|
||||||
|
@ -744,4 +808,13 @@ mod tests {
|
||||||
assert_eq!(profiles.len(), 1);
|
assert_eq!(profiles.len(), 1);
|
||||||
assert_eq!(profiles[0].id, profile.id);
|
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