V4.1 Mostly UI adjustments by GC

This commit is contained in:
Jim Lancaster
2026-08-12 13:11:50 -05:00
parent 1e8d8572d4
commit 89cf69f8a2
29 changed files with 1261 additions and 404 deletions
+60
View File
@@ -10,9 +10,11 @@ from transcription.db.models import JobSource
from transcription.db.models import JobSourceStatus
from transcription.db.models import Person
from transcription.db.models import Source
from transcription.errors import ErrorCategory
from transcription.services.documents import DocumentDeleteBlockedError
from transcription.services.documents import DocumentService
from transcription.services.jobs import JobService
from transcription.services.people import PeopleError
from transcription.services.people import PeopleService
from transcription.services.sources import SourceDeleteBlockedError
from transcription.services.sources import SourceService
@@ -53,6 +55,28 @@ async def test_people_service_handles_person_and_document_person_crud(default_se
assert len(await people_service.list_document_people(document_id=document.id)) == 0
@pytest.mark.asyncio
async def test_people_service_normalizes_and_rejects_duplicate_family_search_ids(default_session_factory):
people_service = PeopleService(session_factory=default_session_factory)
created = await people_service.create_person(
Person(full_name="Hig Higgins", family_search_id=" g8t4-mdq ")
)
assert created.family_search_id == "G8T4-MDQ"
with pytest.raises(PeopleError) as duplicate:
await people_service.create_person(
Person(full_name="Duplicate Hig", family_search_id="G8T4-MDQ")
)
assert duplicate.value.category == ErrorCategory.CONFLICT
with pytest.raises(PeopleError) as malformed:
await people_service.create_person(
Person(full_name="Malformed", family_search_id="not-an-id")
)
assert malformed.value.category == ErrorCategory.VALIDATION
@pytest.mark.asyncio
async def test_transcription_service_manages_source_crud(default_session_factory):
documents = DocumentService(session_factory=default_session_factory)
@@ -88,6 +112,42 @@ async def test_transcription_service_manages_source_crud(default_session_factory
assert len(await transcriptions.list_sources(document_id=document.id)) == 0
@pytest.mark.asyncio
async def test_source_navigation_is_bounded_to_ordered_document(default_session_factory):
documents = DocumentService(session_factory=default_session_factory)
sources = SourceService(session_factory=default_session_factory)
document = await documents.create_document(Document(id=uuid4(), name="ordered"))
other = await documents.create_document(Document(id=uuid4(), name="other"))
first, second, third, _foreign = [
await sources.create_source(
Source(
document_id=document_id,
page_number=page_number,
upload_name=f"page-{page_number}.jpg",
filename=f"page-{page_number}.jpg",
file_path=f"uploads/page-{page_number}.jpg",
file_hash=str(page_number) * 64,
file_size_bytes=1,
)
)
for document_id, page_number in [
(document.id, 1),
(document.id, 2),
(document.id, 3),
(other.id, 2),
]
]
first_navigation = await sources.read_source_navigation(first.id)
middle_navigation = await sources.read_source_navigation(second.id)
last_navigation = await sources.read_source_navigation(third.id)
assert (first_navigation.previous_id, first_navigation.next_id) == (None, second.id)
assert (middle_navigation.previous_id, middle_navigation.next_id) == (first.id, third.id)
assert (last_navigation.previous_id, last_navigation.next_id) == (second.id, None)
@pytest.mark.asyncio
async def test_transcription_service_job_source_crud_uses_caller_session(default_session_factory):
transcriptions = SourceService(session_factory=default_session_factory)