feat: 重构 Reminder Notification 系统并更新应用包名
This commit is contained in:
@@ -59,6 +59,9 @@ class FakeRepo:
|
||||
return self._item
|
||||
return None
|
||||
|
||||
async def get_item(self, item_id: UUID) -> ScheduleItem | None:
|
||||
return await self.get_by_id(item_id)
|
||||
|
||||
async def create(self, data: dict) -> ScheduleItem:
|
||||
return _create_mock_schedule_item(
|
||||
owner_id=data["owner_id"],
|
||||
@@ -74,6 +77,23 @@ class FakeRepo:
|
||||
self._item.title = data["title"]
|
||||
return self._item
|
||||
|
||||
async def update_item(self, item_id: UUID, data: dict) -> ScheduleItem | None:
|
||||
if self._item is None:
|
||||
return None
|
||||
if "title" in data:
|
||||
self._item.title = data["title"]
|
||||
if "description" in data:
|
||||
self._item.description = data["description"]
|
||||
if "start_at" in data:
|
||||
self._item.start_at = data["start_at"]
|
||||
if "end_at" in data:
|
||||
self._item.end_at = data["end_at"]
|
||||
if "timezone" in data:
|
||||
self._item.timezone = data["timezone"]
|
||||
if "extra_metadata" in data:
|
||||
self._item.extra_metadata = data["extra_metadata"]
|
||||
return self._item
|
||||
|
||||
async def delete_by_item_id(
|
||||
self, item_id: UUID, owner_id: UUID
|
||||
) -> ScheduleItem | None:
|
||||
@@ -81,6 +101,9 @@ class FakeRepo:
|
||||
return None
|
||||
return self._item
|
||||
|
||||
async def delete_item(self, item_id: UUID) -> None:
|
||||
del item_id
|
||||
|
||||
async def list_by_date_range(
|
||||
self, owner_id: UUID, start_at: datetime, end_at: datetime
|
||||
) -> list[ScheduleItem]:
|
||||
@@ -327,12 +350,11 @@ async def test_update_maps_metadata_to_extra_metadata(
|
||||
captured: dict | None = None
|
||||
|
||||
class CaptureRepo(FakeRepo):
|
||||
async def update_by_item_id(
|
||||
self, item_id: UUID, owner_id: UUID, data: dict
|
||||
) -> ScheduleItem | None:
|
||||
async def update_item(self, item_id: UUID, data: dict) -> ScheduleItem | None:
|
||||
nonlocal captured
|
||||
del item_id
|
||||
captured = data
|
||||
return await super().update_by_item_id(item_id, owner_id, data)
|
||||
return await super().update_item(item.id, data)
|
||||
|
||||
service = ScheduleItemService(
|
||||
repository=CaptureRepo(item),
|
||||
@@ -370,12 +392,11 @@ async def test_update_maps_null_metadata_to_extra_metadata_null(
|
||||
captured: dict | None = None
|
||||
|
||||
class CaptureRepo(FakeRepo):
|
||||
async def update_by_item_id(
|
||||
self, item_id: UUID, owner_id: UUID, data: dict
|
||||
) -> ScheduleItem | None:
|
||||
async def update_item(self, item_id: UUID, data: dict) -> ScheduleItem | None:
|
||||
nonlocal captured
|
||||
del item_id
|
||||
captured = data
|
||||
return await super().update_by_item_id(item_id, owner_id, data)
|
||||
return await super().update_item(item.id, data)
|
||||
|
||||
service = ScheduleItemService(
|
||||
repository=CaptureRepo(item),
|
||||
|
||||
@@ -157,6 +157,14 @@ class FriendshipRepoStub:
|
||||
return friendship
|
||||
|
||||
|
||||
class UserRepoStub:
|
||||
async def get_by_user_id(self, user_id: UUID):
|
||||
profile = MagicMock()
|
||||
profile.id = user_id
|
||||
profile.username = "owner"
|
||||
return profile
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_share_forbidden_when_not_owner() -> None:
|
||||
owner_id = UUID("00000000-0000-0000-0000-000000000001")
|
||||
@@ -172,6 +180,7 @@ async def test_share_forbidden_when_not_owner() -> None:
|
||||
auth_gateway=cast(Any, AuthGatewayStub()),
|
||||
inbox_repository=InboxRepoStub(),
|
||||
friendship_repository=cast(Any, FriendshipRepoStub()),
|
||||
user_repository=cast(Any, UserRepoStub()),
|
||||
)
|
||||
|
||||
with pytest.raises(ApiProblemError) as exc_info:
|
||||
@@ -204,6 +213,7 @@ async def test_share_success_creates_calendar_invitation_message() -> None:
|
||||
auth_gateway=cast(Any, AuthGatewayStub()),
|
||||
inbox_repository=InboxRepoStub(),
|
||||
friendship_repository=cast(Any, FriendshipRepoStub()),
|
||||
user_repository=cast(Any, UserRepoStub()),
|
||||
)
|
||||
|
||||
result = await service.share(
|
||||
@@ -223,7 +233,17 @@ async def test_share_success_creates_calendar_invitation_message() -> None:
|
||||
assert message.sender_id == owner_id
|
||||
assert message.schedule_item_id == item_id
|
||||
assert message.message_type == InboxMessageType.CALENDAR
|
||||
assert message.content == {"type": "invite", "permission": 5, "action": "pending"}
|
||||
assert message.content is not None
|
||||
assert message.content["type"] == "invite"
|
||||
assert message.content["schema_version"] == 2
|
||||
assert message.content["permission"] == 5
|
||||
assert message.content["item"]["id"] == str(item_id)
|
||||
assert message.content["item"]["title"] == "test"
|
||||
assert message.content["item"]["start_at"] == "2026-02-28T16:00:00+00:00"
|
||||
assert message.content["item"]["end_at"] is None
|
||||
assert message.content["item"]["timezone"] == "UTC"
|
||||
assert message.content["actor"]["username"] == "owner"
|
||||
assert message.content["actor"]["phone"] == "+8613810000000"
|
||||
session.commit.assert_awaited_once()
|
||||
|
||||
|
||||
@@ -237,6 +257,7 @@ async def test_share_returns_not_found_when_item_missing() -> None:
|
||||
auth_gateway=cast(Any, AuthGatewayStub()),
|
||||
inbox_repository=InboxRepoStub(),
|
||||
friendship_repository=cast(Any, FriendshipRepoStub()),
|
||||
user_repository=cast(Any, UserRepoStub()),
|
||||
)
|
||||
|
||||
with pytest.raises(ApiProblemError) as exc_info:
|
||||
@@ -268,6 +289,7 @@ async def test_share_invalid_auth_user_id_returns_503() -> None:
|
||||
auth_gateway=cast(Any, AuthGatewayInvalidIdStub()),
|
||||
inbox_repository=InboxRepoStub(),
|
||||
friendship_repository=cast(Any, FriendshipRepoStub()),
|
||||
user_repository=cast(Any, UserRepoStub()),
|
||||
)
|
||||
|
||||
with pytest.raises(ApiProblemError) as exc_info:
|
||||
@@ -302,6 +324,7 @@ async def test_share_sqlalchemy_error_rolls_back() -> None:
|
||||
auth_gateway=cast(Any, AuthGatewayStub()),
|
||||
inbox_repository=InboxRepoStub(),
|
||||
friendship_repository=cast(Any, FriendshipRepoStub()),
|
||||
user_repository=cast(Any, UserRepoStub()),
|
||||
)
|
||||
|
||||
with pytest.raises(ApiProblemError) as exc_info:
|
||||
@@ -334,6 +357,7 @@ async def test_share_returns_forbidden_when_target_is_not_friend() -> None:
|
||||
auth_gateway=cast(Any, AuthGatewayStub()),
|
||||
inbox_repository=InboxRepoStub(),
|
||||
friendship_repository=cast(Any, FriendshipRepoStub(accepted=False)),
|
||||
user_repository=cast(Any, UserRepoStub()),
|
||||
)
|
||||
|
||||
with pytest.raises(ApiProblemError) as exc_info:
|
||||
|
||||
Reference in New Issue
Block a user