diff options
Diffstat (limited to '')
| -rw-r--r-- | backend/routes/forms/form.py | 70 | 
1 files changed, 66 insertions, 4 deletions
| diff --git a/backend/routes/forms/form.py b/backend/routes/forms/form.py index 86bbf49..9414e30 100644 --- a/backend/routes/forms/form.py +++ b/backend/routes/forms/form.py @@ -1,9 +1,10 @@  """Returns, updates or deletes a single form given an ID.""" +import enum  import json.decoder  import deepmerge -from pydantic import ValidationError +from pydantic import BaseModel, ValidationError  from spectree.response import Response  from starlette.authentication import requires  from starlette.requests import Request @@ -18,6 +19,33 @@ from backend.validation import ErrorMessage, OkayResponse, api  PUBLIC_FORM_FEATURES = (constants.FormFeatures.OPEN, constants.FormFeatures.DISCOVERABLE) +class SubmissionPrecheckSeverity(enum.StrEnum): +    SECONDARY = "secondary" +    WARNING = "warning" +    DANGER = "danger" + + +class SubmissionProblem(BaseModel): +    severity: SubmissionPrecheckSeverity +    message: str + + +class SubmissionPrecheck(BaseModel): +    problems: list[SubmissionProblem] = [] +    can_submit: bool = True + + +class FormWithAncillaryData(Form): +    """ +    Form model with ancillary data for the form. + +    This is used to return the form with additional information such as +    whether the user has edit access or not. +    """ + +    submission_precheck: SubmissionPrecheck = SubmissionPrecheck() + +  class SingleForm(Route):      """      Returns, updates or deletes a single form given an ID. @@ -28,14 +56,17 @@ class SingleForm(Route):      name = "form"      path = "/{form_id:str}" -    @api.validate(resp=Response(HTTP_200=Form, HTTP_404=ErrorMessage), tags=["forms"]) +    @api.validate(resp=Response(HTTP_200=FormWithAncillaryData, HTTP_404=ErrorMessage), tags=["forms"])      async def get(self, request: Request) -> JSONResponse:          """Returns single form information by ID."""          form_id = request.path_params["form_id"].lower()          if form_id == AUTH_FORM.id:              # Empty form for login purposes -            return JSONResponse(AUTH_FORM.dict(admin=False)) +            data = AUTH_FORM.dict(admin=False) +            # Add in empty ancillary data +            data["submission_precheck"] = SubmissionPrecheck().dict() +            return JSONResponse(data)          try:              await discord.verify_edit_access(form_id, request) @@ -53,10 +84,41 @@ class SingleForm(Route):              filters["features"] = {"$in": ["OPEN", "DISCOVERABLE"]}          form = await request.state.db.forms.find_one(filters) +        form = FormWithAncillaryData(**form)          if not form:              return JSONResponse({"error": "not_found"}, status_code=404) -        return JSONResponse(Form(**form).dict(admin=admin)) +        if constants.FormFeatures.OPEN.value not in form.features: +            form.submission_precheck.problems.append( +                SubmissionProblem( +                    severity=SubmissionPrecheckSeverity.DANGER, +                    message="This form is not open for submissions at the moment." +                ) +            ) +            form.submission_precheck.can_submit = False +        elif constants.FormFeatures.UNIQUE_RESPONDER.value in form.features: +            user_id = request.user.payload["id"] if request.user.is_authenticated else None +            if user_id: +                existing_response = await request.state.db.responses.find_one( +                    {"form_id": form_id, "user.id": user_id} +                ) +                if existing_response: +                    form.submission_precheck.problems.append( +                        SubmissionProblem( +                            severity=SubmissionPrecheckSeverity.DANGER, +                            message="You have already submitted a response to this form." +                        ) +                    ) +                    form.submission_precheck.can_submit = False +            else: +                form.submission_precheck.problems.append( +                    SubmissionProblem( +                        severity=SubmissionPrecheckSeverity.SECONDARY, +                        message="You must login at the bottom of the page before submitting this form." +                    ) +                ) + +        return JSONResponse(form.dict(admin=admin))      @requires(["authenticated"])      @api.validate( | 
