Merge branch 'feature-calendar-sharing' into dev
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime, timezone
|
||||
from typing import Callable
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
from fastapi import HTTPException
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from app import app
|
||||
from v1.inbox_messages.dependencies import get_inbox_message_service
|
||||
from v1.inbox_messages.schemas import (
|
||||
InboxMessageAcceptRequest,
|
||||
InboxMessageListRequest,
|
||||
InboxMessageResponse,
|
||||
InboxMessageStatus,
|
||||
InboxMessageType,
|
||||
)
|
||||
from v1.inbox_messages.service import InboxMessageService
|
||||
|
||||
|
||||
class FakeInboxMessageService:
|
||||
def __init__(
|
||||
self,
|
||||
messages: list[InboxMessageResponse],
|
||||
accepted: InboxMessageResponse,
|
||||
dismissed: InboxMessageResponse,
|
||||
) -> None:
|
||||
self._messages = messages
|
||||
self._accepted = accepted
|
||||
self._dismissed = dismissed
|
||||
|
||||
async def list_messages(
|
||||
self, request: InboxMessageListRequest
|
||||
) -> list[InboxMessageResponse]:
|
||||
if request.status is None:
|
||||
return self._messages
|
||||
return [
|
||||
message for message in self._messages if message.status == request.status
|
||||
]
|
||||
|
||||
async def accept_invitation(
|
||||
self,
|
||||
message_id: UUID,
|
||||
request: InboxMessageAcceptRequest,
|
||||
) -> InboxMessageResponse:
|
||||
if message_id != self._accepted.id:
|
||||
raise HTTPException(status_code=404, detail="Inbox message not found")
|
||||
if not request.permission_view:
|
||||
raise HTTPException(status_code=400, detail="permission_view is required")
|
||||
return self._accepted
|
||||
|
||||
async def dismiss_invitation(self, message_id: UUID) -> InboxMessageResponse:
|
||||
if message_id != self._dismissed.id:
|
||||
raise HTTPException(status_code=404, detail="Inbox message not found")
|
||||
return self._dismissed
|
||||
|
||||
|
||||
def _override_inbox_message_service(
|
||||
service: FakeInboxMessageService,
|
||||
) -> Callable[[], InboxMessageService]:
|
||||
def _get_service() -> InboxMessageService:
|
||||
return service # type: ignore[return-value]
|
||||
|
||||
return _get_service
|
||||
|
||||
|
||||
def _build_message(
|
||||
message_id: UUID,
|
||||
status: InboxMessageStatus,
|
||||
) -> InboxMessageResponse:
|
||||
return InboxMessageResponse(
|
||||
id=message_id,
|
||||
recipient_id=uuid4(),
|
||||
sender_id=uuid4(),
|
||||
message_type=InboxMessageType.CALENDAR,
|
||||
schedule_item_id=uuid4(),
|
||||
content='{"permission": 1}',
|
||||
is_read=False,
|
||||
status=status,
|
||||
created_at=datetime(2026, 2, 28, 9, 0, 0, tzinfo=timezone.utc),
|
||||
)
|
||||
|
||||
|
||||
def test_list_inbox_messages_returns_200() -> None:
|
||||
pending_message = _build_message(uuid4(), InboxMessageStatus.PENDING)
|
||||
accepted_message = _build_message(uuid4(), InboxMessageStatus.ACCEPTED)
|
||||
service = FakeInboxMessageService(
|
||||
messages=[pending_message, accepted_message],
|
||||
accepted=accepted_message,
|
||||
dismissed=_build_message(uuid4(), InboxMessageStatus.DISMISSED),
|
||||
)
|
||||
app.dependency_overrides[get_inbox_message_service] = (
|
||||
_override_inbox_message_service(service)
|
||||
)
|
||||
|
||||
client = TestClient(app)
|
||||
try:
|
||||
response = client.get("/api/v1/inbox/messages", params={"status": "pending"})
|
||||
assert response.status_code == 200
|
||||
body = response.json()
|
||||
assert len(body) == 1
|
||||
assert body[0]["status"] == "pending"
|
||||
finally:
|
||||
app.dependency_overrides = {}
|
||||
|
||||
|
||||
def test_accept_inbox_message_returns_200() -> None:
|
||||
accepted_message = _build_message(uuid4(), InboxMessageStatus.ACCEPTED)
|
||||
service = FakeInboxMessageService(
|
||||
messages=[accepted_message],
|
||||
accepted=accepted_message,
|
||||
dismissed=_build_message(uuid4(), InboxMessageStatus.DISMISSED),
|
||||
)
|
||||
app.dependency_overrides[get_inbox_message_service] = (
|
||||
_override_inbox_message_service(service)
|
||||
)
|
||||
|
||||
client = TestClient(app)
|
||||
try:
|
||||
response = client.post(
|
||||
f"/api/v1/inbox/messages/{accepted_message.id}/accept",
|
||||
json={
|
||||
"permission_view": True,
|
||||
"permission_edit": True,
|
||||
"permission_invite": False,
|
||||
},
|
||||
)
|
||||
assert response.status_code == 200
|
||||
body = response.json()
|
||||
assert body["id"] == str(accepted_message.id)
|
||||
assert body["status"] == "accepted"
|
||||
finally:
|
||||
app.dependency_overrides = {}
|
||||
|
||||
|
||||
def test_dismiss_inbox_message_returns_200() -> None:
|
||||
dismissed_message = _build_message(uuid4(), InboxMessageStatus.DISMISSED)
|
||||
service = FakeInboxMessageService(
|
||||
messages=[dismissed_message],
|
||||
accepted=_build_message(uuid4(), InboxMessageStatus.ACCEPTED),
|
||||
dismissed=dismissed_message,
|
||||
)
|
||||
app.dependency_overrides[get_inbox_message_service] = (
|
||||
_override_inbox_message_service(service)
|
||||
)
|
||||
|
||||
client = TestClient(app)
|
||||
try:
|
||||
response = client.post(f"/api/v1/inbox/messages/{dismissed_message.id}/dismiss")
|
||||
assert response.status_code == 200
|
||||
body = response.json()
|
||||
assert body["id"] == str(dismissed_message.id)
|
||||
assert body["status"] == "dismissed"
|
||||
finally:
|
||||
app.dependency_overrides = {}
|
||||
@@ -0,0 +1,68 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Callable
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
from fastapi import HTTPException
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from app import app
|
||||
from v1.schedule_items.dependencies import get_schedule_item_service
|
||||
from v1.schedule_items.schemas import (
|
||||
ScheduleItemShareRequest,
|
||||
ScheduleItemShareResponse,
|
||||
)
|
||||
from v1.schedule_items.service import ScheduleItemService
|
||||
|
||||
|
||||
class FakeScheduleItemShareService:
|
||||
def __init__(self, item_id: UUID) -> None:
|
||||
self._item_id = item_id
|
||||
self.last_share_request: ScheduleItemShareRequest | None = None
|
||||
|
||||
async def share(
|
||||
self,
|
||||
item_id: UUID,
|
||||
request: ScheduleItemShareRequest,
|
||||
) -> ScheduleItemShareResponse:
|
||||
if item_id != self._item_id:
|
||||
raise HTTPException(status_code=404, detail="Schedule item not found")
|
||||
self.last_share_request = request
|
||||
return ScheduleItemShareResponse(message="Calendar invitation sent")
|
||||
|
||||
|
||||
def _override_schedule_item_service(
|
||||
service: FakeScheduleItemShareService,
|
||||
) -> Callable[[], ScheduleItemService]:
|
||||
def _get_service() -> ScheduleItemService:
|
||||
return service # type: ignore[return-value]
|
||||
|
||||
return _get_service
|
||||
|
||||
|
||||
def test_share_schedule_item_returns_200() -> None:
|
||||
item_id = uuid4()
|
||||
service = FakeScheduleItemShareService(item_id=item_id)
|
||||
app.dependency_overrides[get_schedule_item_service] = (
|
||||
_override_schedule_item_service(service)
|
||||
)
|
||||
|
||||
client = TestClient(app)
|
||||
try:
|
||||
response = client.post(
|
||||
f"/api/v1/schedule-items/{item_id}/share",
|
||||
json={
|
||||
"email": "friend@example.com",
|
||||
"permission_view": True,
|
||||
"permission_edit": False,
|
||||
"permission_invite": True,
|
||||
},
|
||||
)
|
||||
assert response.status_code == 200
|
||||
body = response.json()
|
||||
assert body["message"] == "Calendar invitation sent"
|
||||
assert service.last_share_request is not None
|
||||
assert service.last_share_request.email == "friend@example.com"
|
||||
assert service.last_share_request.permission_invite is True
|
||||
finally:
|
||||
app.dependency_overrides = {}
|
||||
Reference in New Issue
Block a user