feat: 增强日历功能并集成 AgentScope 代理服务

This commit is contained in:
qzl
2026-03-11 15:28:29 +08:00
parent e55e445906
commit e20e7d2a02
85 changed files with 5175 additions and 885 deletions
@@ -4,6 +4,7 @@ from uuid import UUID, uuid4
import pytest
from fastapi import HTTPException
from sqlalchemy.exc import SQLAlchemyError
from core.auth.models import CurrentUser
from models.inbox_messages import (
@@ -11,8 +12,6 @@ from models.inbox_messages import (
InboxMessageStatus as InboxMessageModelStatus,
InboxMessageType as InboxMessageModelType,
)
from models.schedule_subscriptions import ScheduleSubscription, SubscriptionStatus
from v1.inbox_messages.schemas import InboxMessageAcceptRequest, InboxMessageListRequest
from v1.inbox_messages.service import InboxMessageService
@@ -31,6 +30,7 @@ def _build_message(
message.sender_id = uuid4()
message.message_type = message_type
message.schedule_item_id = schedule_item_id
message.friendship_id = None
message.content = content
message.is_read = False
message.status = status
@@ -56,7 +56,7 @@ async def test_list_messages_returns_messages() -> None:
current_user=CurrentUser(id=user_id),
)
result = await service.list_messages(InboxMessageListRequest())
result = await service.list_messages()
assert len(result) == 1
assert result[0].recipient_id == user_id
@@ -65,28 +65,21 @@ async def test_list_messages_returns_messages() -> None:
@pytest.mark.asyncio
async def test_accept_invitation_creates_subscription() -> None:
async def test_mark_as_read_updates_message() -> None:
user_id = uuid4()
message_id = uuid4()
item_id = uuid4()
pending_message = _build_message(
updated_message = _build_message(
message_id=message_id,
recipient_id=user_id,
schedule_item_id=item_id,
)
accepted_message = _build_message(
message_id=message_id,
recipient_id=user_id,
status=InboxMessageModelStatus.ACCEPTED,
schedule_item_id=item_id,
status=InboxMessageModelStatus.PENDING,
schedule_item_id=uuid4(),
)
updated_message.is_read = True
repo = AsyncMock()
repo.get_by_id.return_value = pending_message
repo.update_status.return_value = accepted_message
repo.mark_as_read.return_value = updated_message
session = AsyncMock()
session.add = MagicMock()
service = InboxMessageService(
repository=repo,
@@ -94,46 +87,20 @@ async def test_accept_invitation_creates_subscription() -> None:
current_user=CurrentUser(id=user_id),
)
result = await service.accept_invitation(
message_id,
InboxMessageAcceptRequest(
permission_view=True,
permission_edit=True,
permission_invite=False,
),
)
result = await service.mark_as_read(message_id)
session.add.assert_called_once()
subscription = session.add.call_args.args[0]
assert isinstance(subscription, ScheduleSubscription)
assert subscription.item_id == item_id
assert subscription.subscriber_id == user_id
assert subscription.permission == 5 # view(1) + edit(4) = 5
assert subscription.status == SubscriptionStatus.ACTIVE
repo.update_status.assert_awaited_once_with(message_id, user_id, "accepted")
repo.mark_as_read.assert_awaited_once_with(message_id, user_id)
session.commit.assert_awaited_once()
assert result.status.value == "accepted"
assert result.is_read is True
@pytest.mark.asyncio
async def test_dismiss_invitation_updates_status() -> None:
async def test_mark_as_read_raises_404_when_message_missing() -> None:
user_id = uuid4()
message_id = uuid4()
pending_message = _build_message(
message_id=message_id,
recipient_id=user_id,
schedule_item_id=uuid4(),
)
dismissed_message = _build_message(
message_id=message_id,
recipient_id=user_id,
status=InboxMessageModelStatus.DISMISSED,
schedule_item_id=uuid4(),
)
repo = AsyncMock()
repo.get_by_id.return_value = pending_message
repo.update_status.return_value = dismissed_message
repo.mark_as_read.return_value = None
session = AsyncMock()
service = InboxMessageService(
@@ -142,29 +109,23 @@ async def test_dismiss_invitation_updates_status() -> None:
current_user=CurrentUser(id=user_id),
)
result = await service.dismiss_invitation(message_id)
with pytest.raises(HTTPException) as exc_info:
await service.mark_as_read(message_id)
repo.update_status.assert_awaited_once_with(message_id, user_id, "dismissed")
session.commit.assert_awaited_once()
assert result.status.value == "dismissed"
assert exc_info.value.status_code == 404
assert exc_info.value.detail == "Inbox message not found"
session.commit.assert_not_awaited()
@pytest.mark.asyncio
async def test_accept_noncalendar_message_fails() -> None:
async def test_mark_as_read_store_error_returns_503() -> None:
user_id = uuid4()
message_id = uuid4()
non_calendar_message = _build_message(
message_id=message_id,
recipient_id=user_id,
message_type=InboxMessageModelType.FRIEND_REQUEST,
schedule_item_id=None,
)
repo = AsyncMock()
repo.get_by_id.return_value = non_calendar_message
repo.mark_as_read.side_effect = SQLAlchemyError("boom")
session = AsyncMock()
session.add = MagicMock()
service = InboxMessageService(
repository=repo,
@@ -173,9 +134,8 @@ async def test_accept_noncalendar_message_fails() -> None:
)
with pytest.raises(HTTPException) as exc_info:
await service.accept_invitation(message_id, InboxMessageAcceptRequest())
await service.mark_as_read(message_id)
assert exc_info.value.status_code == 400
assert exc_info.value.detail == "Message is not a calendar invitation"
session.add.assert_not_called()
session.commit.assert_not_awaited()
assert exc_info.value.status_code == 503
assert exc_info.value.detail == "Inbox message store unavailable"
session.rollback.assert_awaited_once()