Add poll workflow and signed participation support

This commit is contained in:
2026-07-12 17:32:07 +02:00
parent d0e68f5aa6
commit fc9b7c287c
10 changed files with 519 additions and 16 deletions

View File

@@ -9,6 +9,9 @@ from govoplan_poll.backend.manifest import READ_SCOPE, RESPOND_SCOPE, WRITE_SCOP
from govoplan_poll.backend.schemas import (
PollCreateRequest,
PollDecisionRequest,
PollInvitationCreateRequest,
PollInvitationListResponse,
PollInvitationResponse,
PollListResponse,
PollResponse,
PollResponseItem,
@@ -21,16 +24,22 @@ from govoplan_poll.backend.schemas import (
from govoplan_poll.backend.service import (
PollError,
close_poll,
create_poll_invitation,
create_poll,
decide_poll,
get_poll_by_invitation_token,
get_poll,
list_poll_responses,
list_poll_invitations,
list_polls,
open_poll,
poll_invitation_response,
poll_response,
poll_response_item,
poll_result_summary_by_id,
revoke_poll_invitation,
submit_poll_response,
submit_poll_response_with_token,
update_poll,
)
@@ -46,6 +55,8 @@ def _require_scope(principal: ApiPrincipal, scope: str) -> None:
def _poll_http_error(exc: PollError) -> HTTPException:
if str(exc) == "Poll not found":
return HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc))
if str(exc) == "Poll invitation not found":
return HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(exc))
return HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc))
@@ -189,3 +200,78 @@ def api_poll_summary(
return PollResultSummaryResponse.model_validate(poll_result_summary_by_id(session, tenant_id=principal.tenant_id, poll_id=poll_id))
except PollError as exc:
raise _poll_http_error(exc) from exc
@router.post("/polls/{poll_id}/invitations", response_model=PollInvitationResponse, status_code=status.HTTP_201_CREATED)
def api_create_poll_invitation(
poll_id: str,
payload: PollInvitationCreateRequest,
session: Session = Depends(get_session),
principal: ApiPrincipal = Depends(get_api_principal),
) -> PollInvitationResponse:
_require_scope(principal, WRITE_SCOPE)
try:
invitation, token = create_poll_invitation(session, tenant_id=principal.tenant_id, poll_id=poll_id, payload=payload)
except PollError as exc:
raise _poll_http_error(exc) from exc
return PollInvitationResponse.model_validate(poll_invitation_response(invitation, token=token))
@router.get("/polls/{poll_id}/invitations", response_model=PollInvitationListResponse)
def api_list_poll_invitations(
poll_id: str,
session: Session = Depends(get_session),
principal: ApiPrincipal = Depends(get_api_principal),
) -> PollInvitationListResponse:
_require_scope(principal, READ_SCOPE)
try:
invitations = list_poll_invitations(session, tenant_id=principal.tenant_id, poll_id=poll_id)
except PollError as exc:
raise _poll_http_error(exc) from exc
return PollInvitationListResponse(
invitations=[PollInvitationResponse.model_validate(poll_invitation_response(invitation)) for invitation in invitations]
)
@router.delete("/polls/{poll_id}/invitations/{invitation_id}", response_model=PollInvitationResponse)
def api_revoke_poll_invitation(
poll_id: str,
invitation_id: str,
session: Session = Depends(get_session),
principal: ApiPrincipal = Depends(get_api_principal),
) -> PollInvitationResponse:
_require_scope(principal, WRITE_SCOPE)
try:
invitation = revoke_poll_invitation(
session,
tenant_id=principal.tenant_id,
poll_id=poll_id,
invitation_id=invitation_id,
)
except PollError as exc:
raise _poll_http_error(exc) from exc
return PollInvitationResponse.model_validate(poll_invitation_response(invitation))
@router.get("/public/{token}", response_model=PollResponse)
def api_get_public_poll(
token: str,
session: Session = Depends(get_session),
) -> PollResponse:
try:
return _poll_response(get_poll_by_invitation_token(session, token=token))
except PollError as exc:
raise _poll_http_error(exc) from exc
@router.post("/public/{token}/responses", response_model=PollResponseItem, status_code=status.HTTP_201_CREATED)
def api_submit_public_poll_response(
token: str,
payload: PollSubmitResponseRequest,
session: Session = Depends(get_session),
) -> PollResponseItem:
try:
response = submit_poll_response_with_token(session, token=token, payload=payload)
except PollError as exc:
raise _poll_http_error(exc) from exc
return PollResponseItem.model_validate(poll_response_item(response))