feat: implement /recover command and fix /admin list

- Add /recover command for listing and recovering soft-deleted bounties
  - /recover - list recoverable bounties (admin only)
  - /recover <id> [<id>...] - recover specific bounties (admin only)
- Fix /admin list to show @username instead of admin_id
- Add recover_bounty and recover_bounties methods to BountyService
- Add get_deleted_bounty method to BountyService
- Clean up duplicate cmd_admin functions
- Add /recover to bot command menu
- Fixes #49 and #50
This commit is contained in:
shokollm
2026-04-04 14:29:19 +00:00
parent b554a81979
commit 6a933742cb
4 changed files with 163 additions and 104 deletions

View File

@@ -153,6 +153,44 @@ class BountyService:
all_bounties = self._storage.list_all_bounties(room_id, include_deleted=True)
return [b for b in all_bounties if b.deleted_at is not None]
def get_deleted_bounty(self, room_id: int, bounty_id: int) -> Bounty | None:
"""Get a specific soft-deleted bounty by ID."""
all_bounties = self._storage.list_all_bounties(room_id, include_deleted=True)
for b in all_bounties:
if b.id == bounty_id and b.deleted_at is not None:
return b
return None
def recover_bounty(self, room_id: int, bounty_id: int, user_id: int) -> str:
"""Recover a soft-deleted bounty. Admin only.
Returns: 'recovered', 'not_found', 'not_deleted', 'permission_denied'
"""
if not self.is_admin(room_id, user_id):
return "permission_denied"
bounty = self.get_deleted_bounty(room_id, bounty_id)
if not bounty:
return "not_found"
if bounty.deleted_at is None:
return "not_deleted"
bounty.deleted_at = None
self._storage.update_bounty(room_id, bounty)
return "recovered"
def recover_bounties(
self, room_id: int, bounty_ids: list[int], user_id: int
) -> dict[int, str]:
"""Recover multiple soft-deleted bounties. Admin only.
Returns dict of bounty_id -> result ('recovered', 'not_found', 'not_deleted', 'permission_denied')
"""
results = {}
for bounty_id in bounty_ids:
results[bounty_id] = self.recover_bounty(room_id, bounty_id, user_id)
return results
def get_bounty(self, room_id: int, bounty_id: int) -> Bounty | None:
"""Get a specific bounty by ID. Excludes soft-deleted bounties."""
bounty = self._storage.get_bounty(room_id, bounty_id)