fpaste: add --all flag and expiry countdown to list

This commit is contained in:
Username
2025-12-21 21:43:48 +01:00
parent 40873434c3
commit 3fe631f6b9

48
fpaste
View File

@@ -10,6 +10,7 @@ import json
import os
import ssl
import sys
import time
import urllib.error
import urllib.request
from datetime import UTC, datetime, timedelta
@@ -336,6 +337,28 @@ def format_timestamp(ts: int | float) -> str:
return dt.strftime("%Y-%m-%d %H:%M")
def format_time_remaining(expires_at: int | float | None) -> str:
"""Format time remaining until expiry."""
if not expires_at:
return ""
now = time.time()
remaining = expires_at - now
if remaining <= 0:
return "expired"
if remaining < 60:
return f"{int(remaining)}s"
if remaining < 3600:
return f"{int(remaining / 60)}m"
if remaining < 86400:
hours = int(remaining / 3600)
return f"{hours}h"
days = int(remaining / 86400)
if days >= 365:
years = days // 365
return f"{years}y"
return f"{days}d"
def parse_date(date_str: str) -> int:
"""Parse date string to Unix timestamp."""
if not date_str:
@@ -359,22 +382,27 @@ def get_extension_for_mime(mime_type: str) -> str:
return MIME_EXTENSIONS.get(mime_type, ".bin")
def format_paste_row(paste: dict[str, Any]) -> str:
def format_paste_row(paste: dict[str, Any], show_owner: bool = False) -> str:
"""Format a paste as a table row."""
paste_id = paste["id"]
mime_type = paste.get("mime_type", "unknown")[:16]
size = format_size(paste.get("size", 0))
created = format_timestamp(paste.get("created_at", 0))
# Time remaining until expiry
expires = format_time_remaining(paste.get("expires_at"))
flags = []
if paste.get("burn_after_read"):
flags.append("burn")
if paste.get("password_protected"):
flags.append("pass")
if paste.get("expires_at"):
flags.append("exp")
return f"{paste_id:<12} {mime_type:<16} {size:>6} {created:<16} {' '.join(flags)}"
flags_str = " ".join(flags)
row = f"{paste_id:<12} {mime_type:<16} {size:>6} {created:<16} {expires:<8} {flags_str}"
if show_owner and paste.get("owner"):
row += f" {paste['owner'][:12]}"
return row
def print_paste_list(
@@ -392,9 +420,14 @@ def print_paste_list(
print("no pastes found")
return
print(f"{'ID':<12} {'TYPE':<16} {'SIZE':>6} {'CREATED':<16} FLAGS")
# Check if owner data is present (admin view)
show_owner = any(paste.get("owner") for paste in pastes)
header = f"{'ID':<12} {'TYPE':<16} {'SIZE':>6} {'CREATED':<16} {'EXPIRES':<8} FLAGS"
if show_owner:
header += " OWNER"
print(header)
for paste in pastes:
print(format_paste_row(paste))
print(format_paste_row(paste, show_owner=show_owner))
print(f"\n{summary}")
@@ -653,6 +686,8 @@ def cmd_list(args: argparse.Namespace, config: dict[str, Any]) -> None:
require_auth(config)
params = []
if getattr(args, "all", False):
params.append("all=1")
if args.limit:
params.append(f"limit={args.limit}")
if args.offset:
@@ -1258,6 +1293,7 @@ def build_parser() -> argparse.ArgumentParser:
# list
p_list = subparsers.add_parser("list", aliases=["ls"], help="list your pastes")
p_list.add_argument("-a", "--all", action="store_true", help="list all pastes (admin only)")
p_list.add_argument("-l", "--limit", type=int, metavar="N", help="max pastes (default: 50)")
p_list.add_argument("-o", "--offset", type=int, metavar="N", help="skip first N pastes")
p_list.add_argument("--json", action="store_true", help="output as JSON")