diff --git a/core/models.py b/core/models.py index 12a240d..6f6328c 100644 --- a/core/models.py +++ b/core/models.py @@ -1,53 +1,63 @@ """Domain dataclasses for JIGAIDO bounty tracker.""" from dataclasses import dataclass -from typing import Optional @dataclass class Bounty: - """Bounty - used for both group and personal bounties. + """A bounty created by a user. - Use created_by_user_id to distinguish: if set, it's a group bounty - created by that user. If None, it's a personal/DM bounty. + The created_by_user_id field always refers to the user who created the bounty. + It does NOT indicate whether the bounty is a group or personal bounty. """ id: int - text: Optional[str] - link: Optional[str] - due_date_ts: Optional[int] + text: str | None + link: str | None + due_date_ts: int | None created_at: int - created_by_user_id: Optional[int] = None + created_by_user_id: int @dataclass class TrackedBounty: - """A bounty that a user is tracking.""" + """A bounty that a user is tracking. + + Use TrackedBounty when you need to record that a user is tracking a specific + bounty from a specific room. The room_id indicates which room the bounty + was tracked from (useful when users can track bounties across multiple rooms). + + For simple tracking lists, just use bounty_id and created_at. + """ bounty_id: int created_at: int + room_id: int @dataclass class RoomData: """All data for a room (group or DM). - For groups: is_group=True, room_id is negative (Telegram group ID) - For DMs: is_group=False, room_id is the user_id (positive) - next_id is used to generate unique bounty IDs within this room. + The room_id can be negative for Telegram groups or positive for DMs. + The next_id field is used to generate unique bounty IDs within this room. """ room_id: int - is_group: bool bounties: list[Bounty] next_id: int @dataclass class TrackingData: - """User tracking data within a group. + """User tracking state within a group. - group_id is the Telegram group ID (always negative). + TrackingData vs TrackedBounty: + - Use TrackingData to store ALL tracked bounties for a user in a specific group. + It contains the group_id, user_id, and a list of TrackedBounty entries. + - Use TrackedBounty to represent a single tracked bounty entry within that list. + + TrackingData is the container, TrackedBounty is the item. """ group_id: int diff --git a/tests/test_models.py b/tests/test_models.py index f36843b..7995725 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -20,14 +20,14 @@ class TestBounty: link="https://github.com/example/repo/issues/1", due_date_ts=1735689600, created_at=1735603200, - created_by_user_id=None, + created_by_user_id=123, ) assert b.id == 1 assert b.text == "Fix the bug" assert b.link == "https://github.com/example/repo/issues/1" assert b.due_date_ts == 1735689600 assert b.created_at == 1735603200 - assert b.created_by_user_id is None + assert b.created_by_user_id == 123 def test_bounty_optional_fields_can_be_none(self): b = Bounty( @@ -36,7 +36,7 @@ class TestBounty: link=None, due_date_ts=None, created_at=0, - created_by_user_id=None, + created_by_user_id=123, ) assert b.text is None assert b.link is None @@ -49,7 +49,7 @@ class TestBounty: link=None, due_date_ts=None, created_at=0, - created_by_user_id=None, + created_by_user_id=123, ) b2 = Bounty( id=1, @@ -57,7 +57,7 @@ class TestBounty: link=None, due_date_ts=None, created_at=0, - created_by_user_id=None, + created_by_user_id=123, ) assert b1 == b2 @@ -68,7 +68,7 @@ class TestBounty: link=None, due_date_ts=None, created_at=0, - created_by_user_id=None, + created_by_user_id=123, ) b2 = Bounty( id=2, @@ -76,31 +76,21 @@ class TestBounty: link=None, due_date_ts=None, created_at=0, - created_by_user_id=None, + created_by_user_id=456, ) assert b1 != b2 - def test_bounty_with_created_by_user_id(self): - b = Bounty( - id=1, - text="Group task", - link=None, - due_date_ts=None, - created_at=0, - created_by_user_id=123456, - ) - assert b.created_by_user_id == 123456 - class TestTrackedBounty: def test_create_tracked_bounty(self): - tb = TrackedBounty(bounty_id=5, created_at=1735600000) + tb = TrackedBounty(bounty_id=5, created_at=1735600000, room_id=-1001) assert tb.bounty_id == 5 assert tb.created_at == 1735600000 + assert tb.room_id == -1001 def test_tracked_bounty_comparison(self): - tb1 = TrackedBounty(bounty_id=1, created_at=0) - tb2 = TrackedBounty(bounty_id=1, created_at=0) + tb1 = TrackedBounty(bounty_id=1, created_at=0, room_id=-1001) + tb2 = TrackedBounty(bounty_id=1, created_at=0, room_id=-1001) assert tb1 == tb2 @@ -108,24 +98,20 @@ class TestRoomData: def test_create_group_room_data(self): rd = RoomData( room_id=-1001, - is_group=True, bounties=[], next_id=1, ) assert rd.room_id == -1001 - assert rd.is_group is True assert rd.bounties == [] assert rd.next_id == 1 def test_create_dm_room_data(self): rd = RoomData( room_id=123456, - is_group=False, bounties=[], next_id=1, ) assert rd.room_id == 123456 - assert rd.is_group is False assert rd.bounties == [] assert rd.next_id == 1 @@ -138,7 +124,7 @@ class TestRoomData: created_at=0, created_by_user_id=123, ) - rd = RoomData(room_id=-1001, is_group=True, bounties=[b], next_id=2) + rd = RoomData(room_id=-1001, bounties=[b], next_id=2) assert len(rd.bounties) == 1 assert rd.bounties[0].text == "Task" assert rd.bounties[0].created_by_user_id == 123 @@ -152,7 +138,7 @@ class TestTrackingData: assert td.tracked == [] def test_tracking_data_with_tracked(self): - tb = TrackedBounty(bounty_id=5, created_at=0) + tb = TrackedBounty(bounty_id=5, created_at=0, room_id=-1001) td = TrackingData(group_id=-1001, user_id=123, tracked=[tb]) assert len(td.tracked) == 1 assert td.tracked[0].bounty_id == 5