Compare commits
1 Commits
fix/issue-
...
feat/issue
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f7503ecd14 |
@@ -8,6 +8,7 @@ from telegram.ext import Application, CommandHandler, MessageHandler, filters
|
|||||||
|
|
||||||
from commands import (
|
from commands import (
|
||||||
cmd_add,
|
cmd_add,
|
||||||
|
cmd_admin,
|
||||||
cmd_bounty,
|
cmd_bounty,
|
||||||
cmd_delete,
|
cmd_delete,
|
||||||
cmd_edit,
|
cmd_edit,
|
||||||
@@ -41,6 +42,7 @@ def build_app() -> Application:
|
|||||||
app.add_handler(CommandHandler("delete", cmd_delete))
|
app.add_handler(CommandHandler("delete", cmd_delete))
|
||||||
app.add_handler(CommandHandler("track", cmd_track))
|
app.add_handler(CommandHandler("track", cmd_track))
|
||||||
app.add_handler(CommandHandler("untrack", cmd_untrack))
|
app.add_handler(CommandHandler("untrack", cmd_untrack))
|
||||||
|
app.add_handler(CommandHandler("admin", cmd_admin))
|
||||||
|
|
||||||
app.add_handler(MessageHandler(filters.COMMAND, cmd_help))
|
app.add_handler(MessageHandler(filters.COMMAND, cmd_help))
|
||||||
|
|
||||||
@@ -56,6 +58,7 @@ async def post_init(app: Application) -> None:
|
|||||||
("edit", "Edit a bounty"),
|
("edit", "Edit a bounty"),
|
||||||
("track", "Track a bounty"),
|
("track", "Track a bounty"),
|
||||||
("untrack", "Stop tracking"),
|
("untrack", "Stop tracking"),
|
||||||
|
("admin", "List room admins"),
|
||||||
("help", "Show help"),
|
("help", "Show help"),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -321,7 +321,23 @@ async def cmd_help(update: Update, ctx: ContextTypes.DEFAULT_TYPE) -> None:
|
|||||||
"/delete <id> — delete bounty\n"
|
"/delete <id> — delete bounty\n"
|
||||||
"/track <id> — track a bounty (groups only)\n"
|
"/track <id> — track a bounty (groups only)\n"
|
||||||
"/untrack <id> — stop tracking (groups only)\n"
|
"/untrack <id> — stop tracking (groups only)\n"
|
||||||
|
"/admin — list room admins\n"
|
||||||
"/start — re-initialize\n"
|
"/start — re-initialize\n"
|
||||||
"/help — this message",
|
"/help — this message",
|
||||||
disable_web_page_preview=True,
|
disable_web_page_preview=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def cmd_admin(update: Update, ctx: ContextTypes.DEFAULT_TYPE) -> None:
|
||||||
|
room_id = get_room_id(update)
|
||||||
|
admin_ids = BOUNTY_SERVICE.list_admins(room_id)
|
||||||
|
|
||||||
|
if not admin_ids:
|
||||||
|
await update.message.reply_text("No admins configured for this room.")
|
||||||
|
return
|
||||||
|
|
||||||
|
lines = [f"Room Admins:"]
|
||||||
|
for admin_id in admin_ids:
|
||||||
|
lines.append(f"- @{admin_id}")
|
||||||
|
|
||||||
|
await update.message.reply_text("\n".join(lines))
|
||||||
|
|||||||
41
cli/main.py
41
cli/main.py
@@ -127,40 +127,6 @@ def cmd_delete(args):
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
def cmd_recover(args):
|
|
||||||
"""List or recover soft-deleted bounties."""
|
|
||||||
bounty_service, _ = create_services()
|
|
||||||
room_id = args.group_id or args.user_id
|
|
||||||
user_id = args.user_id or 0
|
|
||||||
|
|
||||||
if not args.bounty_ids:
|
|
||||||
deleted = bounty_service.list_deleted_bounties(room_id)
|
|
||||||
if not deleted:
|
|
||||||
print("No recoverable bounties")
|
|
||||||
return
|
|
||||||
print("Recoverable bounties:")
|
|
||||||
for b in deleted:
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
deleted_str = datetime.fromtimestamp(b.deleted_at).strftime("%d %b %Y")
|
|
||||||
print(f" [#{b.id}] {b.text or '(no text)'} | Deleted {deleted_str}")
|
|
||||||
return
|
|
||||||
|
|
||||||
if not bounty_service.is_admin(room_id, user_id):
|
|
||||||
print("Error: Only admins can recover bounties.", file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
for bounty_id in args.bounty_ids:
|
|
||||||
try:
|
|
||||||
success, msg = bounty_service.recover_bounty(
|
|
||||||
room_id=room_id, bounty_id=bounty_id, user_id=user_id
|
|
||||||
)
|
|
||||||
print(msg)
|
|
||||||
except PermissionError as e:
|
|
||||||
print(f"Error: {e}", file=sys.stderr)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
|
|
||||||
def cmd_track(args):
|
def cmd_track(args):
|
||||||
"""Track a bounty."""
|
"""Track a bounty."""
|
||||||
_, tracking_service = create_services()
|
_, tracking_service = create_services()
|
||||||
@@ -230,9 +196,6 @@ def main():
|
|||||||
parser_untrack = subparsers.add_parser("untrack", help="Untrack a bounty")
|
parser_untrack = subparsers.add_parser("untrack", help="Untrack a bounty")
|
||||||
parser_untrack.add_argument("bounty_id", type=int, help="Bounty ID to untrack")
|
parser_untrack.add_argument("bounty_id", type=int, help="Bounty ID to untrack")
|
||||||
|
|
||||||
parser_recover = subparsers.add_parser("recover", help="List or recover soft-deleted bounties")
|
|
||||||
parser_recover.add_argument("bounty_ids", nargs="*", type=int, help="Bounty ID(s) to recover (optional)")
|
|
||||||
|
|
||||||
for sp in [
|
for sp in [
|
||||||
parser_add,
|
parser_add,
|
||||||
parser_list,
|
parser_list,
|
||||||
@@ -241,7 +204,6 @@ def main():
|
|||||||
parser_delete,
|
parser_delete,
|
||||||
parser_track,
|
parser_track,
|
||||||
parser_untrack,
|
parser_untrack,
|
||||||
parser_recover,
|
|
||||||
]:
|
]:
|
||||||
sp.add_argument(
|
sp.add_argument(
|
||||||
"--group-id", type=int, help="Group context (use group room ID)"
|
"--group-id", type=int, help="Group context (use group room ID)"
|
||||||
@@ -260,7 +222,7 @@ def main():
|
|||||||
print("Error: either --group-id or --user-id is required", file=sys.stderr)
|
print("Error: either --group-id or --user-id is required", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
if args.command in ("add", "list", "my", "update", "delete", "recover"):
|
if args.command in ("add", "list", "my", "update", "delete"):
|
||||||
if not (args.group_id or args.user_id):
|
if not (args.group_id or args.user_id):
|
||||||
print("Error: --group-id or --user-id required", file=sys.stderr)
|
print("Error: --group-id or --user-id required", file=sys.stderr)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@@ -276,7 +238,6 @@ def main():
|
|||||||
"delete": cmd_delete,
|
"delete": cmd_delete,
|
||||||
"track": cmd_track,
|
"track": cmd_track,
|
||||||
"untrack": cmd_untrack,
|
"untrack": cmd_untrack,
|
||||||
"recover": cmd_recover,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.command in command_map:
|
if args.command in command_map:
|
||||||
|
|||||||
@@ -210,33 +210,6 @@ class BountyService:
|
|||||||
self._storage.update_bounty(room_id, bounty)
|
self._storage.update_bounty(room_id, bounty)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def recover_bounty(
|
|
||||||
self, room_id: int, bounty_id: int, user_id: int
|
|
||||||
) -> tuple[bool, str]:
|
|
||||||
"""Recover a soft-deleted bounty. Only admins can recover.
|
|
||||||
|
|
||||||
Returns (success, message) tuple.
|
|
||||||
"""
|
|
||||||
all_bounties = self._storage.list_all_bounties(room_id, include_deleted=True)
|
|
||||||
bounty = None
|
|
||||||
for b in all_bounties:
|
|
||||||
if b.id == bounty_id:
|
|
||||||
bounty = b
|
|
||||||
break
|
|
||||||
|
|
||||||
if not bounty:
|
|
||||||
return False, f"Bounty #{bounty_id} not found."
|
|
||||||
|
|
||||||
if bounty.deleted_at is None:
|
|
||||||
return False, f"Bounty #{bounty_id} is not deleted."
|
|
||||||
|
|
||||||
if not self.is_admin(room_id, user_id):
|
|
||||||
raise PermissionError("Only admins can recover bounties.")
|
|
||||||
|
|
||||||
bounty.deleted_at = None
|
|
||||||
self._storage.update_bounty(room_id, bounty)
|
|
||||||
return True, f"Recovered bounty #{bounty_id}."
|
|
||||||
|
|
||||||
|
|
||||||
class TrackingService:
|
class TrackingService:
|
||||||
"""Service for tracking bounty operations."""
|
"""Service for tracking bounty operations."""
|
||||||
|
|||||||
Reference in New Issue
Block a user