Commit Graph

79 Commits

Author SHA1 Message Date
5502de96ad Merge pull request 'feat: implement /recover command and fix /admin list' (#83) from fix/issue-49-50-recover-admin-list into main 2026-04-04 16:42:07 +02:00
shokollm
6a933742cb 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
2026-04-04 14:29:19 +00:00
b554a81979 Merge pull request 'feat: human-readable date format with timezone awareness (#54)' (#80) from fix/issue-54-v2 into main 2026-04-04 15:37:20 +02:00
shokollm
350ecbf867 feat: human-readable date format with timezone awareness
Add format_due_date() for human-readable dates like "4 April 2026".
Update cmd_add to use timezone-aware date formatting.

Fixes #54
2026-04-04 20:36:38 +07:00
28241eaf61 Merge pull request 'feat(/admin): add /admin command for admin management' (#78) from fix/issue-52 into main 2026-04-04 15:32:44 +02:00
shokollm
8db5ba0ba4 Merge fix/issue-52 with conflict resolution 2026-04-04 20:32:06 +07:00
a727751978 Merge pull request 'feat: add multi-ID delete support with per-ID results' (#79) from fix/issue-47 into main 2026-04-04 15:28:36 +02:00
shokollm
90b0b564c2 feat: add multi-ID delete support with per-ID results
- Add delete_bounties() method to BountyService that returns individual
  results per bounty ID (deleted, not_found, permission_denied)
- Update cmd_delete to accept multiple IDs and show per-ID messages
- Add 3 tests for delete_bounties method

Example output:
/delete 1 2 3
 Bounty #1 deleted.
 Bounty #2 deleted.
 Bounty #3 not found.

Fixes #47
2026-04-04 13:06:56 +00:00
003c570cfb Merge pull request 'feat(/add): add admin-only and link uniqueness handling' (#77) from fix/issue-45-v3 into main 2026-04-04 12:59:48 +02:00
shokollm
bac6830fc3 feat(/add): add admin-only and link uniqueness handling
Wrap add_bounty call in try-except to handle PermissionError
and ValueError from admin check and link uniqueness check.

Fixes #45
2026-04-04 17:59:20 +07:00
2dd11a8b48 Merge pull request 'feat: remove "by user" from bounty list display' (#76) from fix/issue-55 into main 2026-04-04 12:53:36 +02:00
shokollm
2617d17e28 feat: remove "by user" from bounty list display
Removes created_by_user_id from format_bounty() output.
Fixes #55
2026-04-04 17:52:47 +07:00
b091153f10 Merge pull request 'feat: implement /admin add|remove @username command' (#75) from fix/issue-51-v2 into main 2026-04-04 12:18:31 +02:00
shokollm
ce864d9fdc feat: implement /admin add|remove @username command
- Add cmd_admin handler for /admin add|remove @username
- Add _find_user_id_by_username helper to resolve usernames from bounty creators
- Register admin command handler in bot.py
- Add 'admin' to bot command list
- Addresses issue #51
2026-04-04 08:20:35 +00:00
e805a6428a Merge pull request 'feat: implement /timezone command to get/set room timezone' (#72) from fix/issue-53 into main 2026-04-04 10:15:42 +02:00
shokollm
6da16e752b feat: implement /timezone command to get/set room timezone
Re-implement the timezone command that was reverted.

- Add cmd_timezone function with get/set functionality
- Validate timezone using zoneinfo (IANA format)
- Admin-only permission via service layer
- Update help text and bot command list
- Fix indentation bug in cmd_add (duplicate lines)

Fixes #53
2026-04-04 08:14:58 +00:00
e3b813661d Merge pull request 'feat(/bounty): add pagination, sorting, and filtering' (#62) from fix/issue-48-bounty-pagination into main 2026-04-04 10:09:29 +02:00
bdb0f3cd8b Merge pull request 'feat: implement /show command to display full bounty details' (#59) from fix/issue-44 into main 2026-04-04 10:09:28 +02:00
shokollm
649b1ffbd3 revert: remove timezone command and revert date format to simple YYYY-MM-DD
This reverts:
- cmd_timezone function (issue #67)
- format_due_date with human-readable dates (issue #68)
- Reverts date display back to time.strftime("%Y-%m-%d")
- Keeps /edit command with -link/-date flags (issue #46)
2026-04-04 15:05:29 +07:00
shokollm
b8f6b98836 Merge pull request #61 from fix/issue-46 2026-04-04 07:40:59 +00:00
shokollm
c005ee341a Revert "Merge pull request 'feat: add multi-ID delete support with per-ID results' (#63) from fix/issue-47 into main"
This reverts commit bd2627efe9, reversing
changes made to 42ed551554.
2026-04-04 07:24:03 +00:00
922858a81a Merge pull request 'feat: human-readable date format with timezone awareness' (#68) from fix/issue-54 into main 2026-04-04 09:20:43 +02:00
shokollm
f521a682c5 feat: human-readable date format with timezone awareness
- Add format_due_date() function that formats dates as '4 April 2026'
  or '4 April 2026 14:30 (Asia/Jakarta)' with timezone support
- Update format_bounty() to use timezone-aware date formatting
- Update cmd_bounty, cmd_my, cmd_add to pass room_id for timezone
- Dates now display in room's configured timezone
- Fixes #54
2026-04-04 07:19:18 +00:00
015df15bd5 Merge pull request 'feat: implement /timezone command to get/set room timezone' (#67) from feat/issue-53-timezone into main 2026-04-04 09:13:41 +02:00
shokollm
eed3ab33ae feat: implement /timezone command to get/set room timezone
- Add cmd_timezone handler for /timezone command
- Validate timezone using IANA format (zoneinfo.ZoneInfo)
- Use existing BountyService.get_timezone and set_timezone methods
- Admin-only permission via service layer
- Update help text and bot command list
- Fixes #53
2026-04-04 07:12:23 +00:00
bd2627efe9 Merge pull request 'feat: add multi-ID delete support with per-ID results' (#63) from fix/issue-47 into main 2026-04-04 08:54:55 +02:00
shokollm
8069ed6465 feat: add multi-ID delete support with per-ID results
- Add delete_bounties method to BountyService that returns individual
  results per bounty ID (deleted, not_found, permission_denied)
- Update cmd_delete to accept multiple IDs and show per-ID messages
- Add tests for delete_bounties

Example output:
/delete 1 2 3
 Bounty #1 deleted.
 Bounty #2 deleted.
 Bounty #3 not found.

Fixes #47
2026-04-04 06:39:11 +00:00
shokollm
d38d47fb79 feat(/bounty): add pagination, sorting, and filtering
- Default shows 5 bounties per page
- /bounty 10 - show 10 bounties
- /bounty all - show all active (exclude overdue >24h)
- /bounty all 10 - show 10 including expired

Filtering:
- Overdue >24h filtered out by default
- 'all' flag includes overdue

Sorting:
- Bounties with due date sorted by due_date_ts (earliest first)
- Bounties without due date shown last, sorted by created_at

Output format updated:
- Header shows 'Showing X of Y bounties'
- Description sliced to 40 chars when showing pagination info
- Date format changed to '4 Apr 2026' style

Fixes #48
2026-04-04 05:54:56 +00:00
shokollm
a06e1327fb feat(/edit): per-argument updates + clear syntax + admin-only
- Add -link and -date flags to /edit command for field clearing
- /edit <id> -link - clear link
- /edit <id> -date - clear date
- /edit <id> -link <url> - set link
- /edit <id> -date <date> - set date
- /edit <id> text -link - update text, clear link
- /edit <id> text <url> - update text and set link
- Parse_args now returns (text, link, due_date_ts, clear_link, clear_date)
- Update usage messages and help text
- Fixes #46
2026-04-04 05:51:56 +00:00
shokollm
780cba6301 feat: implement /show command to display full bounty details
- Add cmd_show function to display bounty details including:
  - ID and full text (not sliced)
  - Link if exists
  - Due date formatted with room timezone
  - Created by username
  - Created at timestamp
- Register show command handler in bot.py
- Add show command to help text and bot command list
- Fixes #44
2026-04-04 05:43:50 +00:00
42ed551554 Merge pull request 'feat: implement service layer for Phase 2' (#58) from fix/issue-43 into main 2026-04-04 07:36:09 +02:00
shokollm
af7774ef03 feat: implement service layer for Phase 2 - admin management, timezone, soft delete
BountyService:
- Add is_admin(), add_admin(), remove_admin(), list_admins()
- Add set_timezone(), get_timezone()
- Add check_link_unique(), list_deleted_bounties()
- Modify add_bounty() to check link uniqueness and require admin
- Modify update_bounty() to require admin permission (not creator)
- Modify delete_bounty() to perform soft delete (set deleted_at)
- get_bounty() now filters out soft-deleted bounties
- list_bounties() uses storage.list_bounties() which excludes soft-deleted

TrackingService:
- get_tracked_bounties() now filters out soft-deleted bounties

Tests updated to reflect new admin-only permissions and soft delete behavior.
2026-04-04 05:27:40 +00:00
0a64b4f310 Merge pull request 'feat: add list_bounties and list_all_bounties methods to storage adapter' (#57) from fix/issue-42 into main 2026-04-04 07:17:07 +02:00
shokollm
ed0d31bc04 feat: add list_bounties and list_all_bounties methods to storage adapter
Add filtering methods to JsonFileRoomStorage for Phase 2 soft delete support:
- list_bounties(room_id): returns only non-deleted bounties for normal queries
- list_all_bounties(room_id, include_deleted=True): returns all bounties for /recover

Update RoomStorage protocol to include the new methods.
Update mock classes in tests to pass isinstance checks.

Fixes #42
2026-04-04 05:12:19 +00:00
d413f6ce13 Merge pull request 'feat: Model updates - add deleted_at, timezone, admin_user_ids fields' (#56) from fix/issue-41 into main 2026-04-04 07:08:28 +02:00
shokollm
fee8504813 feat: add deleted_at, created_by_username to Bounty; timezone, admin_user_ids to RoomData
Issue #41: Model updates for Phase 2 features

Bounty model:
- Add deleted_at: int | None - timestamp when deleted (soft-delete)
- Add created_by_username: str | None - username for display purposes

RoomData model:
- Add timezone: str | None - room's timezone (e.g., "Asia/Jakarta")
- Add admin_user_ids: list[int] - list of admin user IDs

Storage adapter updated to handle new fields in load/save operations.
Tests added for new fields.
2026-04-04 04:59:58 +00:00
411e19e5d7 Merge pull request 'test: ensure tests package is importable' (#36) from fix/issue-15 into main 2026-04-03 21:10:27 +02:00
6dc3307e23 Merge pull request 'fix #16: cleanup - remove old/dead code and update docs' (#35) from fix/issue-16-cleanup into main 2026-04-03 21:09:59 +02:00
shokollm
1c55fe26b9 test: ensure tests package is importable
Add tests/__init__.py to make tests/ a proper Python package,
enabling cross-imports between test modules (e.g., test_services
importing from test_ports).

All 145 tests pass:
- tests/: 90 tests
- apps/telegram-bot/tests/: 55 tests
2026-04-03 15:12:59 +00:00
shokollm
99a80b0c62 fix #16: cleanup - remove old/dead code and update docs
- Delete apps/telegram-bot/storage.py (replaced by adapters/storage/json_file.py)
- Delete apps/telegram-bot/__init__.py (empty file)
- Delete apps/telegram-bot/requirements-dev.txt (dev deps in pyproject.toml)
- Update SPEC.md with new hexagonal architecture (core, adapters, apps)
- Update SPEC.md command reference: /update -> /edit
- Update README.md with new project structure and quick start
- Update CONTRIBUTING.md with new architecture and dev setup
2026-04-03 15:12:31 +00:00
50b09ef721 Merge pull request 'refactor(telegram-bot): add /edit command and make bot.py minimal entrypoint' (#34) from fix/issue-14 into main 2026-04-03 16:36:27 +02:00
shokollm
67d801d9de refactor(telegram-bot): add /edit command and make bot.py minimal entrypoint
- Add cmd_edit as alias for cmd_update
- Update bot.py to import commands directly instead of via module
- Register /edit command in bot and post_init commands list
- Clean up unused imports in bot.py

Fixes #14
2026-04-03 14:27:01 +00:00
f5cb28d45c Merge pull request 'refactor(commands): use core services instead of storage module' (#33) from fix/issue-13 into main 2026-04-03 16:14:24 +02:00
44bd0488c4 Merge pull request 'feat(cli): implement CLI for jigaido bounty tracker' (#32) from fix/issue-11 into main 2026-04-03 16:14:07 +02:00
shokollm
5e6a5f16b1 Add CLI unit tests for jigaido issue #11
- Tests mock dependencies and verify command existence, flag processing, and output format
- Tests use --group-id=-1001 format (equals sign) to avoid argparse treating -1001 as a flag
- All 17 tests passing
2026-04-03 13:18:48 +00:00
shokollm
0c36aa7b88 test(commands): add unit tests for command handlers
Add comprehensive unit tests for all command handlers:
- TestHelperFunctions: is_group, get_group_id, get_user_id, get_room_id
- TestCmdBounty: lists bounties, handles empty
- TestCmdMy: shows tracked in groups, personal in DM
- TestCmdAdd: add bounty success, validation
- TestCmdUpdate: update bounty, permission denied, invalid ID
- TestCmdDelete: delete bounty, invalid ID
- TestCmdTrack: track in group, reject in DM
- TestCmdUntrack: untrack in group, reject in DM
- TestCmdStart: group vs DM behavior
- TestCmdHelp: shows all commands

Also fix conftest.py to remove obsolete fresh_db fixture
that referenced non-existent db module.

All 55 tests pass.

Addresses han's feedback on PR #33
2026-04-03 13:11:18 +00:00
shokollm
5b1634ebca refactor(commands): use core services instead of storage module
Refactor commands.py to be thin Telegram wrappers around core services.

Changes:
- Replace 'import storage' with imports from core.services and adapters.storage
- Create module-level service instances (BountyService, TrackingService)
- Update format_bounty() to work with Bounty dataclass instead of dict
- Add get_room_id() helper for unified group/DM handling
- Each command handler is now a thin wrapper that:
  1. Extracts Telegram types (update, user_id, room_id)
  2. Calls appropriate core service
  3. Formats and sends response

Kept from original:
- parse_args()
- format_bounty()
- extract_args()

Commands now use services:
- cmd_bounty: BOUNTY_SERVICE.list_bounties()
- cmd_my: BOUNTY_SERVICE.list_bounties() or TRACKING_SERVICE.get_tracked_bounties()
- cmd_add: BOUNTY_SERVICE.add_bounty()
- cmd_update: BOUNTY_SERVICE.update_bounty()
- cmd_delete: BOUNTY_SERVICE.delete_bounty()
- cmd_track: TRACKING_SERVICE.track_bounty() (groups only)
- cmd_untrack: TRACKING_SERVICE.untrack_bounty() (groups only)

Fixes #13
2026-04-03 12:39:23 +00:00
shokollm
7202eeb1d2 feat(cli): implement CLI for jigaido bounty tracker
Create cli/main.py with the following commands:
- add <text> [--link url] [--due date] - Add a new bounty
- list - List all bounties in room
- my - List tracked bounties for user
- update <id> [text] [--link url] [--due date] [--clear-link] [--clear-due]
- delete <id> - Delete a bounty
- track <id> - Track a bounty
- untrack <id> - Untrack a bounty

Context flags:
- --group-id <id> - Group context
- --user-id <id> - User context

Requires either --group-id or --user-id for all commands.

Fixes #11
2026-04-03 12:37:55 +00:00
edbc924b98 Merge pull request 'feat(adapter): implement JSON file storage adapter for issue #9' (#27) from fix/issue-9 into main 2026-04-03 14:24:06 +02:00
2a9795a0c3 Merge pull request 'feat(core): implement services for issue #8' (#26) from fix/issue-8 into main 2026-04-03 14:23:32 +02:00