826 lines
26 KiB
Python
826 lines
26 KiB
Python
from __future__ import annotations
|
|
|
|
from collections.abc import Mapping, Sequence
|
|
from datetime import datetime
|
|
|
|
from pydantic import ValidationError
|
|
|
|
from govoplan_core.core.poll import (
|
|
PollAnswerRef,
|
|
PollCapabilityError,
|
|
PollCreateCommand,
|
|
PollInvitationCommand,
|
|
PollInvitationRef,
|
|
PollOptionOrderCommand,
|
|
PollOptionRequest,
|
|
PollOptionRef,
|
|
PollOptionUpdateCommand,
|
|
PollRef,
|
|
PollResponseRef,
|
|
PollResponseRetirementCommand,
|
|
PollResponseRetirementRef,
|
|
PollSchedulingProvider,
|
|
PollSubmitResponseCommand,
|
|
PollUpdateCommand,
|
|
)
|
|
from govoplan_poll.backend.participation import (
|
|
ANONYMOUS_PASSWORD_REQUIREMENT,
|
|
PollGovernedInvitationCommand,
|
|
PollGovernedResponseCommand,
|
|
PollGovernedResponseRef,
|
|
PollInvitationExpiryRef,
|
|
PollInvitationRevocationRef,
|
|
PollOptionMutationRef,
|
|
PollParticipationContextRef,
|
|
PollResponseGatewayRef,
|
|
)
|
|
from govoplan_poll.backend.participation_service import (
|
|
governed_invitation,
|
|
governed_invitation_by_id,
|
|
participation_policy_payload,
|
|
participation_policy_ref,
|
|
response_for_invitation,
|
|
response_gateway_payload,
|
|
response_gateway_ref,
|
|
response_metadata,
|
|
submit_governed_poll_response,
|
|
submit_authenticated_poll_response,
|
|
update_governed_invitation_expiry,
|
|
)
|
|
from govoplan_poll.backend.db.models import PollInvitation
|
|
from govoplan_poll.backend.schemas import (
|
|
PollAnswerInput,
|
|
PollCreateRequest,
|
|
PollDecisionRequest,
|
|
PollInvitationCreateRequest,
|
|
PollOptionInput,
|
|
PollSubmitResponseRequest,
|
|
)
|
|
from govoplan_poll.backend.service import (
|
|
PollError,
|
|
PollMutationOwner,
|
|
close_poll,
|
|
add_poll_option,
|
|
create_poll,
|
|
create_poll_invitation,
|
|
decide_poll,
|
|
get_poll,
|
|
get_poll_response_for_respondents,
|
|
list_poll_responses,
|
|
open_poll,
|
|
poll_mutation_owner,
|
|
poll_owner_ref,
|
|
poll_result_summary_by_id,
|
|
response_datetime,
|
|
retire_poll_responses,
|
|
remove_poll_option,
|
|
reorder_poll_options,
|
|
revoke_poll_invitation_with_replay,
|
|
set_poll_workflow_context,
|
|
submit_poll_response,
|
|
update_poll_snapshot,
|
|
update_poll_option,
|
|
)
|
|
|
|
|
|
def _poll_ref(poll: object) -> PollRef:
|
|
return PollRef(
|
|
id=poll.id,
|
|
status=poll.status,
|
|
options=tuple(
|
|
PollOptionRef(id=option.id, position=option.position)
|
|
for option in sorted(
|
|
(option for option in poll.options if option.deleted_at is None),
|
|
key=lambda item: (item.position, item.id),
|
|
)
|
|
),
|
|
)
|
|
|
|
|
|
def _command_owner(command: PollCreateCommand) -> PollMutationOwner | None:
|
|
context = (
|
|
command.context_module,
|
|
command.context_resource_type,
|
|
command.context_resource_id,
|
|
)
|
|
if not any(value is not None for value in context):
|
|
return None
|
|
return poll_owner_ref(
|
|
module_id=command.context_module,
|
|
resource_type=command.context_resource_type,
|
|
resource_id=command.context_resource_id,
|
|
)
|
|
|
|
|
|
def _stored_owner(
|
|
session: object,
|
|
*,
|
|
tenant_id: str,
|
|
poll_id: str,
|
|
) -> PollMutationOwner | None:
|
|
return poll_mutation_owner(
|
|
get_poll(session, tenant_id=tenant_id, poll_id=poll_id)
|
|
)
|
|
|
|
|
|
def _response_invitation_id(response: object) -> str | None:
|
|
value = (response.metadata_ or {}).get("invitation_id")
|
|
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_datetime(response.submitted_at),
|
|
respondent_id=response.respondent_id,
|
|
answers=tuple(answers),
|
|
)
|
|
|
|
|
|
def _participation_context_ref(
|
|
session: object,
|
|
*,
|
|
invitation: PollInvitation,
|
|
respondent_id: str | None = None,
|
|
participant_email: str | None = None,
|
|
) -> PollParticipationContextRef:
|
|
policy = participation_policy_ref(invitation.participation_policy_)
|
|
response = response_for_invitation(
|
|
session,
|
|
invitation=invitation,
|
|
respondent_id=respondent_id,
|
|
participant_email=participant_email,
|
|
)
|
|
response_ref = None
|
|
if response is not None:
|
|
email, comment = response_metadata(response)
|
|
response_ref = PollGovernedResponseRef(
|
|
response=_response_ref(response),
|
|
participant_email=email,
|
|
comment=comment,
|
|
)
|
|
return PollParticipationContextRef(
|
|
invitation_id=invitation.id,
|
|
tenant_id=invitation.tenant_id,
|
|
poll_id=invitation.poll_id,
|
|
gateway=response_gateway_ref(invitation.response_gateway_),
|
|
policy=policy,
|
|
respondent_id=invitation.respondent_id or respondent_id,
|
|
respondent_label=invitation.respondent_label,
|
|
email=invitation.email,
|
|
response=response_ref,
|
|
)
|
|
|
|
|
|
class SqlPollSchedulingProvider(PollSchedulingProvider):
|
|
def create_poll(
|
|
self,
|
|
session: object,
|
|
*,
|
|
tenant_id: str,
|
|
user_id: str | None,
|
|
command: PollCreateCommand,
|
|
) -> PollRef:
|
|
payload = PollCreateRequest(
|
|
title=command.title,
|
|
description=command.description,
|
|
kind=command.kind,
|
|
status=command.status,
|
|
visibility=command.visibility,
|
|
result_visibility=command.result_visibility,
|
|
context_module=command.context_module,
|
|
context_resource_type=command.context_resource_type,
|
|
context_resource_id=command.context_resource_id,
|
|
workflow_state=command.workflow_state,
|
|
workflow_steps=[dict(step) for step in command.workflow_steps],
|
|
allow_anonymous=command.allow_anonymous,
|
|
allow_response_update=command.allow_response_update,
|
|
min_choices=command.min_choices,
|
|
max_choices=command.max_choices,
|
|
opens_at=command.opens_at,
|
|
closes_at=command.closes_at,
|
|
options=[
|
|
PollOptionInput(
|
|
key=option.key,
|
|
label=option.label,
|
|
description=option.description,
|
|
value=dict(option.value) if option.value is not None else None,
|
|
metadata=dict(option.metadata),
|
|
)
|
|
for option in command.options
|
|
],
|
|
metadata=dict(command.metadata),
|
|
)
|
|
try:
|
|
poll = create_poll(
|
|
session,
|
|
tenant_id=tenant_id,
|
|
user_id=user_id,
|
|
payload=payload,
|
|
mutation_owner=_command_owner(command),
|
|
)
|
|
except PollError as exc:
|
|
raise PollCapabilityError(str(exc)) from exc
|
|
return _poll_ref(poll)
|
|
|
|
def create_invitation(
|
|
self,
|
|
session: object,
|
|
*,
|
|
tenant_id: str,
|
|
poll_id: str,
|
|
command: PollInvitationCommand,
|
|
) -> PollInvitationRef:
|
|
payload = PollInvitationCreateRequest(
|
|
respondent_id=command.respondent_id,
|
|
respondent_label=command.respondent_label,
|
|
email=command.email,
|
|
expires_at=command.expires_at,
|
|
metadata=dict(command.metadata),
|
|
)
|
|
try:
|
|
invitation, token = create_poll_invitation(
|
|
session,
|
|
tenant_id=tenant_id,
|
|
poll_id=poll_id,
|
|
payload=payload,
|
|
)
|
|
except PollError as exc:
|
|
raise PollCapabilityError(str(exc)) from exc
|
|
return PollInvitationRef(id=invitation.id, token=token)
|
|
|
|
def create_governed_invitation(
|
|
self,
|
|
session: object,
|
|
*,
|
|
tenant_id: str,
|
|
poll_id: str,
|
|
command: PollGovernedInvitationCommand,
|
|
) -> PollInvitationRef:
|
|
try:
|
|
payload = PollInvitationCreateRequest(
|
|
respondent_id=command.respondent_id,
|
|
respondent_label=command.respondent_label,
|
|
email=command.email,
|
|
expires_at=command.expires_at,
|
|
response_gateway=response_gateway_payload(command.gateway),
|
|
participation_policy=participation_policy_payload(command.policy),
|
|
metadata=dict(command.metadata),
|
|
)
|
|
invitation, token = create_poll_invitation(
|
|
session,
|
|
tenant_id=tenant_id,
|
|
poll_id=poll_id,
|
|
payload=payload,
|
|
governed_capability=True,
|
|
)
|
|
except (PollError, ValidationError) as exc:
|
|
raise PollCapabilityError(str(exc)) from exc
|
|
return PollInvitationRef(id=invitation.id, token=token)
|
|
|
|
def resolve_participation(
|
|
self,
|
|
session: object,
|
|
*,
|
|
token: str,
|
|
gateway: PollResponseGatewayRef,
|
|
respondent_id: str | None = None,
|
|
participant_email: str | None = None,
|
|
participant_is_authenticated: bool = False,
|
|
verified_requirements: frozenset[str] = frozenset(),
|
|
) -> PollParticipationContextRef:
|
|
try:
|
|
invitation = governed_invitation(
|
|
session,
|
|
token=token,
|
|
gateway=gateway,
|
|
)
|
|
policy = participation_policy_ref(invitation.participation_policy_)
|
|
if (
|
|
not participant_is_authenticated
|
|
and policy.anonymous_password_required
|
|
and ANONYMOUS_PASSWORD_REQUIREMENT not in verified_requirements
|
|
):
|
|
raise PollError("Poll invitation not found")
|
|
return _participation_context_ref(
|
|
session,
|
|
invitation=invitation,
|
|
respondent_id=(respondent_id if participant_is_authenticated else None),
|
|
participant_email=participant_email,
|
|
)
|
|
except (PollError, ValidationError) as exc:
|
|
raise PollCapabilityError(str(exc)) from exc
|
|
|
|
def submit_governed_response(
|
|
self,
|
|
session: object,
|
|
*,
|
|
token: str,
|
|
gateway: PollResponseGatewayRef,
|
|
command: PollGovernedResponseCommand,
|
|
) -> PollGovernedResponseRef:
|
|
try:
|
|
_invitation, response, replayed = submit_governed_poll_response(
|
|
session,
|
|
token=token,
|
|
gateway=gateway,
|
|
command=command,
|
|
)
|
|
except (PollError, ValidationError) as exc:
|
|
raise PollCapabilityError(str(exc)) from exc
|
|
email, comment = response_metadata(response)
|
|
return PollGovernedResponseRef(
|
|
response=_response_ref(response),
|
|
participant_email=email,
|
|
comment=comment,
|
|
replayed=replayed,
|
|
)
|
|
|
|
def resolve_authenticated_participation(
|
|
self,
|
|
session: object,
|
|
*,
|
|
tenant_id: str,
|
|
poll_id: str,
|
|
invitation_id: str,
|
|
gateway: PollResponseGatewayRef,
|
|
respondent_id: str,
|
|
) -> PollParticipationContextRef:
|
|
try:
|
|
invitation = governed_invitation_by_id(
|
|
session,
|
|
tenant_id=tenant_id,
|
|
poll_id=poll_id,
|
|
invitation_id=invitation_id,
|
|
gateway=gateway,
|
|
respondent_id=respondent_id,
|
|
)
|
|
return _participation_context_ref(
|
|
session,
|
|
invitation=invitation,
|
|
respondent_id=respondent_id,
|
|
)
|
|
except (PollError, ValidationError) as exc:
|
|
raise PollCapabilityError(str(exc)) from exc
|
|
|
|
def submit_authenticated_response(
|
|
self,
|
|
session: object,
|
|
*,
|
|
tenant_id: str,
|
|
poll_id: str,
|
|
invitation_id: str,
|
|
gateway: PollResponseGatewayRef,
|
|
respondent_id: str,
|
|
command: PollGovernedResponseCommand,
|
|
) -> PollGovernedResponseRef:
|
|
try:
|
|
_invitation, response, replayed = submit_authenticated_poll_response(
|
|
session,
|
|
tenant_id=tenant_id,
|
|
poll_id=poll_id,
|
|
invitation_id=invitation_id,
|
|
gateway=gateway,
|
|
respondent_id=respondent_id,
|
|
command=command,
|
|
)
|
|
except (PollError, ValidationError) as exc:
|
|
raise PollCapabilityError(str(exc)) from exc
|
|
email, comment = response_metadata(response)
|
|
return PollGovernedResponseRef(
|
|
response=_response_ref(response),
|
|
participant_email=email,
|
|
comment=comment,
|
|
replayed=replayed,
|
|
)
|
|
|
|
def add_option(
|
|
self,
|
|
session: object,
|
|
*,
|
|
tenant_id: str,
|
|
poll_id: str,
|
|
command: PollOptionRequest,
|
|
) -> PollOptionMutationRef:
|
|
try:
|
|
mutation_owner = _stored_owner(
|
|
session,
|
|
tenant_id=tenant_id,
|
|
poll_id=poll_id,
|
|
)
|
|
option, replayed = add_poll_option(
|
|
session,
|
|
tenant_id=tenant_id,
|
|
poll_id=poll_id,
|
|
option=PollOptionInput(
|
|
key=command.key,
|
|
label=command.label,
|
|
description=command.description,
|
|
value=dict(command.value) if command.value is not None else None,
|
|
metadata=dict(command.metadata),
|
|
),
|
|
mutation_owner=mutation_owner,
|
|
)
|
|
except (PollError, ValidationError) as exc:
|
|
raise PollCapabilityError(str(exc)) from exc
|
|
return PollOptionMutationRef(
|
|
id=option.id,
|
|
position=option.position,
|
|
replayed=replayed,
|
|
)
|
|
|
|
def remove_option(
|
|
self,
|
|
session: object,
|
|
*,
|
|
tenant_id: str,
|
|
poll_id: str,
|
|
option_id: str,
|
|
) -> PollOptionMutationRef:
|
|
try:
|
|
mutation_owner = _stored_owner(
|
|
session,
|
|
tenant_id=tenant_id,
|
|
poll_id=poll_id,
|
|
)
|
|
option, replayed, invalidated = remove_poll_option(
|
|
session,
|
|
tenant_id=tenant_id,
|
|
poll_id=poll_id,
|
|
option_id=option_id,
|
|
mutation_owner=mutation_owner,
|
|
)
|
|
except (PollError, ValidationError) as exc:
|
|
raise PollCapabilityError(str(exc)) from exc
|
|
return PollOptionMutationRef(
|
|
id=option.id,
|
|
position=option.position,
|
|
replayed=replayed,
|
|
invalidated_response_count=invalidated,
|
|
)
|
|
|
|
def revoke_invitation(
|
|
self,
|
|
session: object,
|
|
*,
|
|
tenant_id: str,
|
|
poll_id: str,
|
|
invitation_id: str,
|
|
) -> PollInvitationRevocationRef:
|
|
try:
|
|
mutation_owner = _stored_owner(
|
|
session,
|
|
tenant_id=tenant_id,
|
|
poll_id=poll_id,
|
|
)
|
|
invitation, replayed = revoke_poll_invitation_with_replay(
|
|
session,
|
|
tenant_id=tenant_id,
|
|
poll_id=poll_id,
|
|
invitation_id=invitation_id,
|
|
mutation_owner=mutation_owner,
|
|
)
|
|
except (PollError, ValidationError) as exc:
|
|
raise PollCapabilityError(str(exc)) from exc
|
|
return PollInvitationRevocationRef(
|
|
id=invitation.id,
|
|
revoked_at=response_datetime(invitation.revoked_at),
|
|
replayed=replayed,
|
|
)
|
|
|
|
def update_invitation_expiry(
|
|
self,
|
|
session: object,
|
|
*,
|
|
tenant_id: str,
|
|
poll_id: str,
|
|
invitation_id: str,
|
|
gateway: PollResponseGatewayRef,
|
|
expires_at: datetime | None,
|
|
) -> PollInvitationExpiryRef:
|
|
try:
|
|
invitation, replayed = update_governed_invitation_expiry(
|
|
session,
|
|
tenant_id=tenant_id,
|
|
poll_id=poll_id,
|
|
invitation_id=invitation_id,
|
|
gateway=gateway,
|
|
expires_at=expires_at,
|
|
)
|
|
except (PollError, ValidationError) as exc:
|
|
raise PollCapabilityError(str(exc)) from exc
|
|
return PollInvitationExpiryRef(
|
|
id=invitation.id,
|
|
expires_at=response_datetime(invitation.expires_at),
|
|
replayed=replayed,
|
|
)
|
|
|
|
def submit_response(
|
|
self,
|
|
session: object,
|
|
*,
|
|
tenant_id: str,
|
|
poll_id: str,
|
|
command: PollSubmitResponseCommand,
|
|
) -> PollResponseRef:
|
|
payload = PollSubmitResponseRequest(
|
|
respondent_id=command.respondent_id,
|
|
respondent_label=command.respondent_label,
|
|
answers=[
|
|
PollAnswerInput(
|
|
option_id=answer.option_id,
|
|
option_key=answer.option_key,
|
|
value=answer.value,
|
|
rank=answer.rank,
|
|
)
|
|
for answer in command.answers
|
|
],
|
|
metadata=dict(command.metadata),
|
|
)
|
|
try:
|
|
response = submit_poll_response(
|
|
session,
|
|
tenant_id=tenant_id,
|
|
poll_id=poll_id,
|
|
payload=payload,
|
|
)
|
|
except PollError as exc:
|
|
raise PollCapabilityError(str(exc)) from exc
|
|
return _response_ref(response)
|
|
|
|
def update_poll(
|
|
self,
|
|
session: object,
|
|
*,
|
|
tenant_id: str,
|
|
poll_id: str,
|
|
command: PollUpdateCommand,
|
|
) -> PollRef:
|
|
try:
|
|
mutation_owner = _stored_owner(
|
|
session,
|
|
tenant_id=tenant_id,
|
|
poll_id=poll_id,
|
|
)
|
|
poll = update_poll_snapshot(
|
|
session,
|
|
tenant_id=tenant_id,
|
|
poll_id=poll_id,
|
|
title=command.title,
|
|
description=command.description,
|
|
visibility=command.visibility,
|
|
result_visibility=command.result_visibility,
|
|
allow_anonymous=command.allow_anonymous,
|
|
allow_response_update=command.allow_response_update,
|
|
closes_at=command.closes_at,
|
|
mutation_owner=mutation_owner,
|
|
)
|
|
except PollError as exc:
|
|
raise PollCapabilityError(str(exc)) from exc
|
|
return _poll_ref(poll)
|
|
|
|
def update_option(
|
|
self,
|
|
session: object,
|
|
*,
|
|
tenant_id: str,
|
|
poll_id: str,
|
|
option_id: str,
|
|
command: PollOptionUpdateCommand,
|
|
) -> PollOptionRef:
|
|
try:
|
|
mutation_owner = _stored_owner(
|
|
session,
|
|
tenant_id=tenant_id,
|
|
poll_id=poll_id,
|
|
)
|
|
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),
|
|
mutation_owner=mutation_owner,
|
|
)
|
|
except PollError as exc:
|
|
raise PollCapabilityError(str(exc)) from exc
|
|
return PollOptionRef(id=option.id, position=option.position)
|
|
|
|
def reorder_options(
|
|
self,
|
|
session: object,
|
|
*,
|
|
tenant_id: str,
|
|
poll_id: str,
|
|
command: PollOptionOrderCommand,
|
|
) -> PollRef:
|
|
try:
|
|
mutation_owner = _stored_owner(
|
|
session,
|
|
tenant_id=tenant_id,
|
|
poll_id=poll_id,
|
|
)
|
|
poll = reorder_poll_options(
|
|
session,
|
|
tenant_id=tenant_id,
|
|
poll_id=poll_id,
|
|
option_ids=command.option_ids,
|
|
mutation_owner=mutation_owner,
|
|
)
|
|
except PollError as exc:
|
|
raise PollCapabilityError(str(exc)) from exc
|
|
return _poll_ref(poll)
|
|
|
|
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)
|
|
|
|
def close_poll(self, session: object, *, tenant_id: str, poll_id: str) -> PollRef:
|
|
return self._transition(close_poll, session, tenant_id=tenant_id, poll_id=poll_id)
|
|
|
|
def decide_poll(
|
|
self,
|
|
session: object,
|
|
*,
|
|
tenant_id: str,
|
|
poll_id: str,
|
|
option_id: str | None,
|
|
) -> PollRef:
|
|
try:
|
|
mutation_owner = _stored_owner(
|
|
session,
|
|
tenant_id=tenant_id,
|
|
poll_id=poll_id,
|
|
)
|
|
poll = decide_poll(
|
|
session,
|
|
tenant_id=tenant_id,
|
|
poll_id=poll_id,
|
|
payload=PollDecisionRequest(option_id=option_id),
|
|
mutation_owner=mutation_owner,
|
|
)
|
|
except PollError as exc:
|
|
raise PollCapabilityError(str(exc)) from exc
|
|
return _poll_ref(poll)
|
|
|
|
def get_poll(self, session: object, *, tenant_id: str, poll_id: str) -> PollRef:
|
|
try:
|
|
return _poll_ref(get_poll(session, tenant_id=tenant_id, poll_id=poll_id))
|
|
except PollError as exc:
|
|
raise PollCapabilityError(str(exc)) from exc
|
|
|
|
def set_workflow_context(
|
|
self,
|
|
session: object,
|
|
*,
|
|
tenant_id: str,
|
|
poll_id: str,
|
|
workflow_state: str,
|
|
workflow_steps: Sequence[Mapping[str, object]],
|
|
context_module: str,
|
|
context_resource_type: str,
|
|
context_resource_id: str,
|
|
) -> PollRef:
|
|
try:
|
|
mutation_owner = _stored_owner(
|
|
session,
|
|
tenant_id=tenant_id,
|
|
poll_id=poll_id,
|
|
)
|
|
requested_owner = poll_owner_ref(
|
|
module_id=context_module,
|
|
resource_type=context_resource_type,
|
|
resource_id=context_resource_id,
|
|
)
|
|
poll = set_poll_workflow_context(
|
|
session,
|
|
tenant_id=tenant_id,
|
|
poll_id=poll_id,
|
|
workflow_state=workflow_state,
|
|
workflow_steps=[dict(step) for step in workflow_steps],
|
|
context_module=context_module,
|
|
context_resource_type=context_resource_type,
|
|
context_resource_id=context_resource_id,
|
|
mutation_owner=mutation_owner,
|
|
requested_owner=requested_owner,
|
|
)
|
|
except PollError as exc:
|
|
raise PollCapabilityError(str(exc)) from exc
|
|
return _poll_ref(poll)
|
|
|
|
def result_summary(self, session: object, *, tenant_id: str, poll_id: str) -> Mapping[str, object]:
|
|
try:
|
|
return poll_result_summary_by_id(session, tenant_id=tenant_id, poll_id=poll_id)
|
|
except PollError as exc:
|
|
raise PollCapabilityError(str(exc)) from exc
|
|
|
|
def list_responses(self, session: object, *, tenant_id: str, poll_id: str) -> tuple[PollResponseRef, ...]:
|
|
try:
|
|
projection_owner = _stored_owner(
|
|
session,
|
|
tenant_id=tenant_id,
|
|
poll_id=poll_id,
|
|
)
|
|
responses = list_poll_responses(
|
|
session,
|
|
tenant_id=tenant_id,
|
|
poll_id=poll_id,
|
|
projection_owner=projection_owner,
|
|
)
|
|
except PollError as exc:
|
|
raise PollCapabilityError(str(exc)) from exc
|
|
return tuple(_response_ref(response) for response in responses)
|
|
|
|
def get_response(
|
|
self,
|
|
session: object,
|
|
*,
|
|
tenant_id: str,
|
|
poll_id: str,
|
|
respondent_ids: Sequence[str],
|
|
invitation_id: str | None = None,
|
|
) -> PollResponseRef | None:
|
|
try:
|
|
projection_owner = _stored_owner(
|
|
session,
|
|
tenant_id=tenant_id,
|
|
poll_id=poll_id,
|
|
)
|
|
response = get_poll_response_for_respondents(
|
|
session,
|
|
tenant_id=tenant_id,
|
|
poll_id=poll_id,
|
|
respondent_ids=tuple(respondent_ids),
|
|
invitation_id=invitation_id,
|
|
projection_owner=projection_owner,
|
|
)
|
|
except PollError as exc:
|
|
raise PollCapabilityError(str(exc)) from exc
|
|
return _response_ref(response) if response is not None else None
|
|
|
|
def retire_responses(
|
|
self,
|
|
session: object,
|
|
*,
|
|
tenant_id: str,
|
|
poll_id: str,
|
|
command: PollResponseRetirementCommand,
|
|
) -> PollResponseRetirementRef:
|
|
try:
|
|
mutation_owner = _stored_owner(
|
|
session,
|
|
tenant_id=tenant_id,
|
|
poll_id=poll_id,
|
|
)
|
|
responses, retired_at, retired_count, replayed = retire_poll_responses(
|
|
session,
|
|
tenant_id=tenant_id,
|
|
poll_id=poll_id,
|
|
respondent_ids=command.respondent_ids,
|
|
invitation_id=command.invitation_id,
|
|
reason=command.reason,
|
|
idempotency_key=command.idempotency_key,
|
|
metadata=dict(command.metadata),
|
|
mutation_owner=mutation_owner,
|
|
)
|
|
except PollError as exc:
|
|
raise PollCapabilityError(str(exc)) from exc
|
|
return PollResponseRetirementRef(
|
|
response_ids=tuple(response.id for response in responses),
|
|
retired_at=response_datetime(retired_at),
|
|
newly_retired_count=retired_count,
|
|
replayed=replayed,
|
|
)
|
|
|
|
@staticmethod
|
|
def _transition(callback, session: object, *, tenant_id: str, poll_id: str) -> PollRef:
|
|
try:
|
|
mutation_owner = _stored_owner(
|
|
session,
|
|
tenant_id=tenant_id,
|
|
poll_id=poll_id,
|
|
)
|
|
poll = callback(
|
|
session,
|
|
tenant_id=tenant_id,
|
|
poll_id=poll_id,
|
|
mutation_owner=mutation_owner,
|
|
)
|
|
except PollError as exc:
|
|
raise PollCapabilityError(str(exc)) from exc
|
|
return _poll_ref(poll)
|