diff options
| author | 2020-12-21 19:39:56 +0000 | |
|---|---|---|
| committer | 2020-12-21 19:39:56 +0000 | |
| commit | 59a605290795c0563311993fb16d992972104025 (patch) | |
| tree | d1b392efe12ccaa053e3f6253f12a471d94da253 /backend/models | |
| parent | Remove validator import (diff) | |
| parent | Merge pull request #39 from python-discord/discord-webhook (diff) | |
Merge branch 'main' into big-int-fix
Diffstat (limited to '')
| -rw-r--r-- | backend/models/form.py | 76 | 
1 files changed, 75 insertions, 1 deletions
| diff --git a/backend/models/form.py b/backend/models/form.py index 9d8ffaa..d5e2ff5 100644 --- a/backend/models/form.py +++ b/backend/models/form.py @@ -1,13 +1,34 @@  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"] +class _WebHook(BaseModel): +    """Schema model of discord webhooks.""" +    url: str +    message: t.Optional[str] + +    @validator("url") +    def validate_url(cls, url: str) -> str: +        """Validates URL parameter.""" +        if "discord.com/api/webhooks/" not in url: +            raise ValueError("URL must be a discord webhook.") + +        return url + + +class _FormMeta(BaseModel): +    """Schema model for form meta data.""" +    webhook: _WebHook = None + +  class Form(BaseModel):      """Schema model for form.""" @@ -16,6 +37,7 @@ class Form(BaseModel):      questions: list[Question]      name: str      description: str +    meta: _FormMeta = _FormMeta()      class Config:          allow_population_by_field_name = True @@ -56,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() -> t.Optional[str]: +        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) | 
