diff options
author | 2020-12-17 04:31:37 +0300 | |
---|---|---|
committer | 2020-12-17 06:35:22 +0300 | |
commit | b80b3293a5cc50d4482ead0903d516652f83b27e (patch) | |
tree | 604d70d7dd6522b30bfb528b653eddbf5cba0424 | |
parent | Create config.yml (diff) |
Adds Webhook Option
Adds webhook option on form creation, and adds validation. Updates
`SCHEMA.md`.
Signed-off-by: Hassan Abouelela <[email protected]>
-rw-r--r-- | SCHEMA.md | 22 | ||||
-rw-r--r-- | backend/constants.py | 1 | ||||
-rw-r--r-- | backend/models/form.py | 51 |
3 files changed, 67 insertions, 7 deletions
@@ -12,13 +12,14 @@ In this document: ## Form -| Field | Type | Description | Example | -| ----------- | ---------------------------------------- | ----------------------------------------------------------------------------------------- | --------------------------- | -| `id` | Unique identifier | A user selected, unique, descriptive identifier (used in URL routes, so no spaces) | `"ban-appeals"` | -| `features` | List of [form features](#form-features) | A list of features to change the behaviour of the form, described in the features section | `["OPEN", "COLLECT_EMAIL"]` | -| `questions` | List of [form questions](#form-question) | The list of questions to render on a specific form | Too long! See below | -| `name` | String | Name of the form | `"Summer Code Jam 2100"` | -| `description` | String | Form description | `"This is my amazing form description."` | +| Field | Type | Description | Example | +| ------------- | ----------------------------------------- | ----------------------------------------------------------------------------------------- | ---------------------------------------- | +| `id` | Unique identifier | A user selected, unique, descriptive identifier (used in URL routes, so no spaces) | `"ban-appeals"` | +| `features` | List of [form features](#form-features) | A list of features to change the behaviour of the form, described in the features section | `["OPEN", "COLLECT_EMAIL"]` | +| `meta` | Mapping of [meta options](#meta-options) | Meta properties for the form. | See meta-options section | +| `questions` | List of [form questions](#form-question) | The list of questions to render on a specific form | Too long! See below | +| `name` | String | Name of the form | `"Summer Code Jam 2100"` | +| `description` | String | Form description | `"This is my amazing form description."` | ### Form features @@ -29,6 +30,13 @@ In this document: | `OPEN` | The form is currently accepting responses. | | `COLLECT_EMAIL` | The form should collect the email from submissions. Requires `REQUIRES_LOGIN` | | `DISABLE_ANTISPAM` | Disable the anti-spam checks from running on a form submission. | +| `WEBHOOK_ENABLED` | The form should notify the webhook. Has no effect if no webhook is set. | + +### Meta options +| Field | Description | Example | +| --------- | ----------------------------------- | ------------------------------------------------------------------------------------------ | +| `webhook` | Mapping of webhook url and message. | `"webhook": {"url": "https://discord.com/api/webhooks/id/key", "message": "Hello World!"}` | + ### Form question diff --git a/backend/constants.py b/backend/constants.py index fdf7092..e733e53 100644 --- a/backend/constants.py +++ b/backend/constants.py @@ -58,3 +58,4 @@ class FormFeatures(Enum): OPEN = "OPEN" COLLECT_EMAIL = "COLLECT_EMAIL" DISABLE_ANTISPAM = "DISABLE_ANTISPAM" + WEBHOOK_ENABLED = "WEBHOOK_ENABLED" diff --git a/backend/models/form.py b/backend/models/form.py index cb58065..e6c56a4 100644 --- a/backend/models/form.py +++ b/backend/models/form.py @@ -1,5 +1,6 @@ import typing as t +import httpx from pydantic import BaseModel, Field, validator from backend.constants import FormFeatures @@ -8,6 +9,55 @@ from .question import Question PUBLIC_FIELDS = ["id", "features", "questions", "name", "description"] +class _WebHook(BaseModel): + """Schema model of discord webhooks.""" + url: str + message: str + + @validator("url") + def validate_url(cls, url: str) -> str: + """Checks if discord webhook urls are valid.""" + if not isinstance(url, str): + raise ValueError("Webhook URL must be a string.") + + if "discord.com/api/webhooks/" not in url: + raise ValueError("URL must be a discord webhook.") + + # Attempt to connect to URL + try: + httpx.get(url).raise_for_status() + + except httpx.RequestError as e: + # Catch exceptions in request format + raise ValueError( + f"Encountered error while trying to connect to url: `{e}`" + ) + + except httpx.HTTPStatusError as e: + # Catch exceptions in response + status = e.response.status_code + + if status == 401: + raise ValueError( + "Could not authenticate with target. Please check the webhook url." + ) + elif status == 404: + raise ValueError( + "Target could not find webhook url. Please check the webhook url." + ) + else: + raise ValueError( + f"Unknown error ({status}) while connecting to target: {e}" + ) + + return url + + +class _FormMeta(BaseModel): + """Schema model for form meta data.""" + webhook: _WebHook + + class Form(BaseModel): """Schema model for form.""" @@ -16,6 +66,7 @@ class Form(BaseModel): questions: list[Question] name: str description: str + meta: _FormMeta class Config: allow_population_by_field_name = True |