Commit Graph

26 Commits

Author SHA1 Message Date
shokollm
4885be0752 fix: cleanup codebase and sync SPEC with actual permissions
Phase 1: Ruff lint fixes
- Remove unused imports across all files
- Remove unused variables (now_utc, tz, ctx)
- Fix f-string without placeholders
- Fix E402 import order with noqa comments

Phase 2: Remove confusing hard delete from storage
- Removed delete_bounty() from RoomStorage Protocol (never used by app)
- Removed delete_bounty() from JsonFileRoomStorage (was hard delete)
- Removed corresponding tests (hard delete was never used)

Phase 3: Sync SPEC.md with actual code behavior
- Updated overview: admins can add/edit/delete (not 'anyone' + 'creator')
- Updated command table: /add, /edit, /delete are admin only
- Updated error handling messages

Test results: 96 passed (2 hard delete tests removed)
2026-04-09 10:01:02 +00:00
shokollm
8494b4621c feat: switch admin identification from user_id to username
- Replace admin_user_ids (list[int]) with admin_usernames (list[str])
- Update all service methods to use username for permission checks
- Add delete button to bot responses for message cleanup
- Update tests to match new implementation

Note: Breaking change - existing data files need fresh start
2026-04-09 08:02:36 +00:00
shokollm
408318d323 feat: bot reads JIGAIDO_BOT_TOKEN from config file
- config.py: Added _resolve_bot_token() to read from config file
- bot.py: Uses config.config.bot_token instead of env var directly
- test_config.py: Added test for config file token reading
2026-04-04 15:16:55 +00: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
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
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
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
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
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
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
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
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
shokollm
d889d0e8ab fix(adapter): add unit tests + reorganize data directories
- Add tests/test_json_file.py with unit tests for JsonFileRoomStorage and JsonFileTrackingStorage
- Reorganize data directories per han's feedback:
  - Rooms: ~/.jigaido/data/room/<room_id>.json (was ~/.jigaido/data/<room_id>.json)
  - Tracking: ~/.jigaido/data/tracking/<room_id>_<user_id>.json (was ~/.jigaido/tracking/...)
- Note: duplicate tracking is handled at TrackingService layer (returns False if already tracking), adapter allows duplicates by design
2026-04-03 11:38:42 +00:00
shokollm
3feab1d469 test(services): add unit tests for BountyService and TrackingService
- Test BountyService: add_bounty, list_bounties, get_bounty, update_bounty, delete_bounty
- Test TrackingService: track_bounty, untrack_bounty, get_tracked_bounties
- Test edge cases: permission errors, not found, duplicate tracking
2026-04-03 11:36:07 +00:00
shokollm
e691abce60 Revert "Merge feat/issue-6-storage-ports: JSON file storage adapter for issue #9"
This reverts commit 9e3641a850, reversing
changes made to 8aebb763ee.
2026-04-03 08:36:04 +00:00
shokollm
9e3641a850 Merge feat/issue-6-storage-ports: JSON file storage adapter for issue #9 2026-04-03 08:26:10 +00:00
shokollm
af8eb90563 feat(adapter): implement JSON file storage adapter
Add JsonFileRoomStorage and JsonFileTrackingStorage implementations
that implement the RoomStorage and TrackingStorage ports.

- Stores room data at ~/.jigaido/data/<room_id>.json
- Stores tracking data at ~/.jigaido/tracking/<room_id>_<user_id>.json
- Implements all port methods: load, save, add_bounty, update_bounty,
  delete_bounty, get_bounty for rooms; load, save, track_bounty,
  untrack_bounty for tracking

Fixes #9
2026-04-03 08:06:51 +00:00
8aebb763ee Merge pull request 'Add core/ports.py - Storage interfaces' (#20) from feat/issue-6-storage-ports into main 2026-04-03 08:58:30 +02:00
shokollm
a237810dd2 Remove ensure_room/ensure_tracking from Protocol - tests prove not needed
Tests with SimpleRoomStorage and SimpleTrackingStorage (without ensure_*)
show that add_bounty() and track_bounty() work fine without explicit
ensure methods - they create rooms/tracking internally.

This simplifies the Protocol to only essential methods.
2026-04-03 06:48:52 +00:00
shokollm
43603659de Address PR #20 feedback:
- Removed PersonalStorage (redundant - RoomStorage handles both via room_id)
- Added ensure_room() and ensure_tracking() methods for explicit creation
- Added @runtime_checkable to Protocols for isinstance checks
- Added tests/test_ports.py with 11 unit tests for storage protocols
2026-04-02 23:57:49 +00:00
ddd44cb593 Merge pull request 'feat(core): implement domain dataclasses for issue #5' (#19) from feat/issue-5-core-models into main 2026-04-03 00:37:30 +02:00
shokollm
b2854393ae Address PR #19 review feedback round 3:
- TrackingData.group_id renamed to room_id (works for both group and DM)
- Removed room_id from TrackedBounty (it's just a lightweight pointer)
2026-04-02 22:34:19 +00:00
shokollm
330203e6ef Address PR #19 review feedback round 2:
- Bounty.created_by_user_id is now non-optional (always required)
- Removed is_group from RoomData (negative room_id is self-documenting)
- Added room_id to TrackedBounty to track which room bounty was tracked from
- Added clarifying docstrings explaining TrackingData vs TrackedBounty
- Updated tests to match new model structure
2026-04-02 22:24:12 +00:00
shokollm
f1ef33451c Address PR #19 review feedback: simplify models
- Remove GroupBounty/PersonalBounty subclasses, use Bounty with optional created_by_user_id
- Combine UserData/GroupData into RoomData with room_id and is_group fields
- Add group_id field to TrackingData (supports negative Telegram group IDs)
- Add test_bounty_comparison_not_equal for verifying different bounties are not equal
- Update core/__init__.py exports
2026-04-02 21:47:26 +00:00
shokollm
9b8b15414f feat(config): implement configuration management for issue #7
- Create config.py with Config class
- Config precedence: ENV > config file > defaults
- data_dir: JIGAIDO_DATA_DIR env or ~/.jigaido/config.json or default
- bot_token: JIGAIDO_BOT_TOKEN env var
- ensure_data_dir() method to create data directory
- Add tests/test_config.py with 7 passing tests

Fixes #7
2026-04-02 20:16:41 +00:00
shokollm
db09a518d1 feat(core): implement domain dataclasses for issue #5
- Create core/__init__.py
- Create core/models.py with all domain dataclasses:
  - Bounty (base class)
  - GroupBounty (extends Bounty)
  - PersonalBounty (extends Bounty)
  - TrackedBounty
  - GroupData
  - TrackingData
  - UserData
- Create tests/test_models.py with 15 passing tests

Fixes #5
2026-04-02 20:15:41 +00:00