feat(responses): support safe option editing

This commit is contained in:
2026-07-20 18:20:33 +02:00
parent 65e2d1fd65
commit e0de54b756
3 changed files with 250 additions and 13 deletions

View File

@@ -3,11 +3,13 @@ from __future__ import annotations
from collections.abc import Mapping, Sequence
from govoplan_core.core.poll import (
PollAnswerRef,
PollCapabilityError,
PollCreateCommand,
PollInvitationCommand,
PollInvitationRef,
PollOptionRef,
PollOptionUpdateCommand,
PollRef,
PollResponseRef,
PollSchedulingProvider,
@@ -33,6 +35,7 @@ from govoplan_poll.backend.service import (
open_poll,
poll_result_summary_by_id,
submit_poll_response,
update_poll_option,
)
@@ -49,6 +52,27 @@ def _response_invitation_id(response: object) -> str | None:
return value if isinstance(value, str) else None
def _response_ref(response: object) -> PollResponseRef:
answers: list[PollAnswerRef] = []
for answer in response.answers or []:
if not isinstance(answer, Mapping):
continue
answers.append(
PollAnswerRef(
option_id=answer.get("option_id"),
option_key=answer.get("option_key"),
value=answer.get("value"),
rank=answer.get("rank"),
)
)
return PollResponseRef(
invitation_id=_response_invitation_id(response),
submitted_at=response.submitted_at,
respondent_id=response.respondent_id,
answers=tuple(answers),
)
class SqlPollSchedulingProvider(PollSchedulingProvider):
def create_poll(
self,
@@ -151,11 +175,7 @@ class SqlPollSchedulingProvider(PollSchedulingProvider):
)
except PollError as exc:
raise PollCapabilityError(str(exc)) from exc
return PollResponseRef(
invitation_id=_response_invitation_id(response),
submitted_at=response.submitted_at,
respondent_id=response.respondent_id,
)
return _response_ref(response)
def update_poll(
self,
@@ -179,6 +199,30 @@ class SqlPollSchedulingProvider(PollSchedulingProvider):
session.flush()
return _poll_ref(poll)
def update_option(
self,
session: object,
*,
tenant_id: str,
poll_id: str,
option_id: str,
command: PollOptionUpdateCommand,
) -> PollOptionRef:
try:
option = update_poll_option(
session,
tenant_id=tenant_id,
poll_id=poll_id,
option_id=option_id,
label=command.label,
description=command.description,
value=dict(command.value) if command.value is not None else None,
metadata=dict(command.metadata),
)
except PollError as exc:
raise PollCapabilityError(str(exc)) from exc
return PollOptionRef(id=option.id, position=option.position)
def open_poll(self, session: object, *, tenant_id: str, poll_id: str) -> PollRef:
return self._transition(open_poll, session, tenant_id=tenant_id, poll_id=poll_id)
@@ -245,14 +289,7 @@ class SqlPollSchedulingProvider(PollSchedulingProvider):
responses = list_poll_responses(session, tenant_id=tenant_id, poll_id=poll_id)
except PollError as exc:
raise PollCapabilityError(str(exc)) from exc
return tuple(
PollResponseRef(
invitation_id=_response_invitation_id(response),
submitted_at=response.submitted_at,
respondent_id=response.respondent_id,
)
for response in responses
)
return tuple(_response_ref(response) for response in responses)
@staticmethod
def _transition(callback, session: object, *, tenant_id: str, poll_id: str) -> PollRef: