Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions crates/buzz-admin/src/user_deletions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,33 @@ pub async fn run(command: UserDeletionsCommand) -> anyhow::Result<i32> {
mod tests {
use clap::Parser;

#[test]
fn batch_preview_requires_read_only_scope_and_valid_keys() {
let args = [
"buzz-admin",
"user-deletions",
"preview-batches",
"--pubkey",
"79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
"--community",
"00000000-0000-0000-0000-000000000001",
"--read-only",
];
assert!(crate::Cli::try_parse_from(args).is_ok());
assert!(crate::Cli::try_parse_from(&args[..7]).is_err());
for extra in [
["--batch-size", "0"],
["--batch-size", "101"],
["--pubkey", "demo"],
["--max-items", "0"],
["--max-items", "1000001"],
["--relay-pubkey", "invalid"],
] {
assert!(crate::Cli::try_parse_from(args.into_iter().chain(extra)).is_err());
}
assert!(crate::Cli::try_parse_from(args.into_iter().chain(["--execute"])).is_err());
}

#[test]
fn user_workflow_commands_are_registered() {
for args in [
Expand Down
2 changes: 2 additions & 0 deletions crates/buzz-db/src/store/user_deletion/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use crate::Db;
use sqlx::PgPool;
mod discovery;
mod inventory;
/// Read-only, ordered previews of human content cleanup batches.
pub mod preview;
mod requests;
pub use discovery::normalize_user_deletion_pubkey;
pub use inventory::UserDeletionInventory;
Expand Down
12 changes: 12 additions & 0 deletions crates/buzz-db/src/store/user_deletion/preview/authored.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
-- Scope shared by source selection and the excluded-kind inventory.
-- Relay attribution is opt-in: only the supplied trusted signer may use actor/p.
SELECT e.* FROM events e
WHERE e.community_id = $1 AND e.pubkey IN (decode($2, 'hex'), decode($3, 'hex'))
AND CASE WHEN e.pubkey = decode($3, 'hex') THEN COALESCE(
(SELECT CASE WHEN t->>1 ~ '^[0-9a-fA-F]{64}$' THEN decode(t->>1, 'hex') END
FROM jsonb_array_elements(e.tags) t WHERE t->>0 = 'actor' AND t->>1 IS NOT NULL LIMIT 1),
(SELECT decode(t->>1, 'hex') FROM jsonb_array_elements(e.tags) t
WHERE t->>0 = 'p' AND t->>1 ~ '^[0-9a-fA-F]{64}$' LIMIT 1), e.pubkey)
ELSE e.pubkey END = decode($2, 'hex')
-- Notes/articles use direct authorship, not relay attribution.
AND (e.kind NOT IN (1, 30023) OR e.pubkey = decode($2, 'hex'))
Loading
Loading