fpaste: add batch delete and --all with confirmation
This commit is contained in:
87
fpaste
87
fpaste
@@ -635,26 +635,73 @@ def cmd_get(args: argparse.Namespace, config: dict[str, Any]) -> None:
|
||||
|
||||
|
||||
def cmd_delete(args: argparse.Namespace, config: dict[str, Any]) -> None:
|
||||
"""Delete a paste."""
|
||||
"""Delete paste(s)."""
|
||||
require_auth(config)
|
||||
|
||||
paste_id = args.id.split("/")[-1]
|
||||
url = f"{config['server'].rstrip('/')}/{paste_id}"
|
||||
delete_all = getattr(args, "all", False)
|
||||
confirm_count = getattr(args, "confirm", None)
|
||||
paste_ids = [pid.split("/")[-1] for pid in (args.ids or [])]
|
||||
|
||||
status, _, _ = request(
|
||||
url, method="DELETE", headers=auth_headers(config), ssl_context=config.get("ssl_context")
|
||||
)
|
||||
# Validate arguments
|
||||
if delete_all and paste_ids:
|
||||
die("cannot specify both --all and paste IDs")
|
||||
if not delete_all and not paste_ids:
|
||||
die("specify paste ID(s) or use --all")
|
||||
|
||||
if status == 200:
|
||||
print(f"deleted: {paste_id}")
|
||||
elif status == 404:
|
||||
die(f"not found: {paste_id}")
|
||||
elif status == 403:
|
||||
die("permission denied (not owner)")
|
||||
elif status == 401:
|
||||
die("authentication failed")
|
||||
else:
|
||||
die(f"delete failed ({status})")
|
||||
if delete_all:
|
||||
# Fetch all pastes to get count and IDs
|
||||
url = f"{config['server'].rstrip('/')}/pastes?all=1&limit=1000"
|
||||
status, body, _ = request(
|
||||
url, headers=auth_headers(config), ssl_context=config.get("ssl_context")
|
||||
)
|
||||
if status == 401:
|
||||
die("authentication failed")
|
||||
if status != 200:
|
||||
die(f"failed to list pastes ({status})")
|
||||
|
||||
data = json.loads(body)
|
||||
pastes = data.get("pastes", [])
|
||||
total = len(pastes)
|
||||
|
||||
if total == 0:
|
||||
print("no pastes to delete")
|
||||
return
|
||||
|
||||
# Require confirmation with expected count
|
||||
if confirm_count is None:
|
||||
die(f"--all requires --confirm {total} (found {total} pastes)")
|
||||
if confirm_count != total:
|
||||
die(f"confirmation mismatch: expected {confirm_count}, found {total}")
|
||||
|
||||
paste_ids = [p["id"] for p in pastes]
|
||||
|
||||
# Delete pastes
|
||||
deleted = 0
|
||||
failed = 0
|
||||
for paste_id in paste_ids:
|
||||
url = f"{config['server'].rstrip('/')}/{paste_id}"
|
||||
status, _, _ = request(
|
||||
url,
|
||||
method="DELETE",
|
||||
headers=auth_headers(config),
|
||||
ssl_context=config.get("ssl_context"),
|
||||
)
|
||||
if status == 200:
|
||||
print(f"deleted: {paste_id}")
|
||||
deleted += 1
|
||||
elif status == 404:
|
||||
print(f"not found: {paste_id}", file=sys.stderr)
|
||||
failed += 1
|
||||
elif status == 403:
|
||||
print(f"permission denied: {paste_id}", file=sys.stderr)
|
||||
failed += 1
|
||||
else:
|
||||
print(f"failed ({status}): {paste_id}", file=sys.stderr)
|
||||
failed += 1
|
||||
|
||||
# Summary for batch operations
|
||||
if len(paste_ids) > 1:
|
||||
print(f"\n{deleted} deleted, {failed} failed")
|
||||
|
||||
|
||||
def cmd_info(args: argparse.Namespace, config: dict[str, Any]) -> None:
|
||||
@@ -1285,8 +1332,12 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
p_get.add_argument("-m", "--meta", action="store_true", help="show metadata only")
|
||||
|
||||
# delete
|
||||
p_delete = subparsers.add_parser("delete", aliases=["d", "rm"], help="delete paste")
|
||||
p_delete.add_argument("id", help="paste ID or URL")
|
||||
p_delete = subparsers.add_parser("delete", aliases=["d", "rm"], help="delete paste(s)")
|
||||
p_delete.add_argument("ids", nargs="*", metavar="ID", help="paste ID(s) or URL(s)")
|
||||
p_delete.add_argument("-a", "--all", action="store_true", help="delete all pastes (admin)")
|
||||
p_delete.add_argument(
|
||||
"-c", "--confirm", type=int, metavar="N", help="confirm expected delete count"
|
||||
)
|
||||
|
||||
# info
|
||||
subparsers.add_parser("info", aliases=["i"], help="show server info")
|
||||
|
||||
Reference in New Issue
Block a user