aboutsummaryrefslogtreecommitdiffstats
path: root/backend/models
diff options
context:
space:
mode:
authorGravatar Hassan Abouelela <[email protected]>2020-12-18 23:12:33 +0300
committerGravatar Hassan Abouelela <[email protected]>2020-12-18 23:12:33 +0300
commitd1cb4200229a7811f21ce44dc427674e4f0b4ff3 (patch)
treeb9f9d9522c3da4d4e05bc8aadfe3973b6cea16d1 /backend/models
parentUses Builtin User Class (diff)
Runs Initial Validation Asynchronously
Moves the validation code of webhook urls to an async function that is called by the route, to avoid blocking code. Signed-off-by: Hassan Abouelela <[email protected]>
Diffstat (limited to 'backend/models')
-rw-r--r--backend/models/form.py87
1 files changed, 55 insertions, 32 deletions
diff --git a/backend/models/form.py b/backend/models/form.py
index 9a3a8a2..96362d4 100644
--- a/backend/models/form.py
+++ b/backend/models/form.py
@@ -2,8 +2,9 @@ import typing as t
import httpx
from pydantic import BaseModel, Field, validator
+from pydantic.error_wrappers import ErrorWrapper, ValidationError
-from backend.constants import FormFeatures
+from backend.constants import FormFeatures, Meta, WebHook
from .question import Question
PUBLIC_FIELDS = ["id", "features", "questions", "name", "description"]
@@ -16,40 +17,10 @@ class _WebHook(BaseModel):
@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.")
-
+ """Validates URL parameter."""
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
@@ -107,3 +78,55 @@ class Form(BaseModel):
class FormList(BaseModel):
__root__: t.List[Form]
+
+
+async def validate_hook_url(url: str) -> t.Optional[ValidationError]:
+ """Validator for discord webhook urls."""
+ async def validate():
+ 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.")
+
+ try:
+ async with httpx.AsyncClient() as client:
+ response = await client.get(url)
+ response.raise_for_status()
+
+ except httpx.RequestError as error:
+ # Catch exceptions in request format
+ raise ValueError(
+ f"Encountered error while trying to connect to url: `{error}`"
+ )
+
+ except httpx.HTTPStatusError as error:
+ # Catch exceptions in response
+ status = error.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: {error}"
+ )
+
+ return url
+
+ # Validate, and return errors, if any
+ try:
+ await validate()
+ except Exception as e:
+ loc = (
+ Meta.__name__.lower(),
+ WebHook.__name__.lower(),
+ WebHook.URL.value
+ )
+
+ return ValidationError([ErrorWrapper(e, loc=loc)], _WebHook)