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
@@ -86,3 +86,30 @@ def test_metadata_attachment_reminder() -> None:
)
assert attachment.type == AttachmentType.REMINDER
assert attachment.content == "Don't forget!"
def test_metadata_rejects_invalid_color() -> None:
with pytest.raises(ValidationError):
ScheduleItemMetadata(color="blue")
def test_metadata_rejects_invalid_version() -> None:
with pytest.raises(ValidationError):
ScheduleItemMetadata(version=2)
def test_metadata_rejects_unknown_field() -> None:
with pytest.raises(ValidationError):
ScheduleItemMetadata.model_validate({"color": "#FF6B6B", "unknown": True})
def test_metadata_attachment_rejects_unknown_field() -> None:
with pytest.raises(ValidationError):
ScheduleItemMetadataAttachment.model_validate(
{
"name": "memo",
"type": "document",
"url": "https://example.com",
"unexpected": "x",
}
)
@@ -13,6 +13,7 @@ from models.schedule_items import (
)
from v1.schedule_items.schemas import (
ScheduleItemCreateRequest,
ScheduleItemMetadata,
ScheduleItemUpdateRequest,
)
from v1.schedule_items.service import ScheduleItemService
@@ -50,6 +51,11 @@ class FakeRepo:
return self._item
return None
async def get_by_id(self, entity_id: UUID) -> ScheduleItem | None:
if self._item and entity_id == self._item.id:
return self._item
return None
async def create(self, data: dict) -> ScheduleItem:
return _create_mock_schedule_item(
owner_id=data["owner_id"],
@@ -77,6 +83,20 @@ class FakeRepo:
) -> list[ScheduleItem]:
return [self._item] if self._item else []
async def list_paginated(
self,
owner_id: UUID,
*,
page: int,
page_size: int,
) -> tuple[list[ScheduleItem], int]:
del owner_id, page, page_size
return ([self._item] if self._item else [], 1 if self._item else 0)
async def create_subscription(self, data: dict):
del data
return MagicMock()
@pytest.fixture
def mock_session() -> AsyncMock:
@@ -183,3 +203,70 @@ async def test_delete_success(mock_session: AsyncMock) -> None:
await service.delete(item.id)
mock_session.commit.assert_awaited_once()
@pytest.mark.asyncio
async def test_create_maps_metadata_to_extra_metadata(mock_session: AsyncMock) -> None:
user_id = UUID("00000000-0000-0000-0000-000000000001")
captured: dict | None = None
class CaptureRepo(FakeRepo):
async def create(self, data: dict) -> ScheduleItem:
nonlocal captured
captured = data
return _create_mock_schedule_item(
owner_id=data["owner_id"], title=data["title"]
)
request = ScheduleItemCreateRequest(
title="Roadmap",
start_at=datetime(2026, 2, 28, 16, 0, 0, tzinfo=timezone.utc),
metadata=ScheduleItemMetadata(location="会议室A", color="#4F46E5", version=1),
)
service = ScheduleItemService(
repository=CaptureRepo(None),
session=mock_session,
current_user=CurrentUser(id=user_id),
)
await service.create(request)
assert captured is not None
assert "extra_metadata" in captured
assert captured["extra_metadata"]["location"] == "会议室A"
assert "metadata" not in captured
@pytest.mark.asyncio
async def test_update_maps_metadata_to_extra_metadata(mock_session: AsyncMock) -> None:
user_id = UUID("00000000-0000-0000-0000-000000000001")
item = _create_mock_schedule_item()
captured: dict | None = None
class CaptureRepo(FakeRepo):
async def update_by_item_id(
self, item_id: UUID, owner_id: UUID, data: dict
) -> ScheduleItem | None:
nonlocal captured
captured = data
return await super().update_by_item_id(item_id, owner_id, data)
service = ScheduleItemService(
repository=CaptureRepo(item),
session=mock_session,
current_user=CurrentUser(id=user_id),
)
await service.update(
item.id,
ScheduleItemUpdateRequest(
metadata=ScheduleItemMetadata(
location="线上会议", color="#3B82F6", version=1
)
),
)
assert captured is not None
assert "extra_metadata" in captured
assert captured["extra_metadata"]["location"] == "线上会议"
assert "metadata" not in captured