diff options
| author | 2020-12-01 20:56:49 +0000 | |
|---|---|---|
| committer | 2020-12-01 20:56:49 +0000 | |
| commit | 0e34c3bd42bba9a3274ea7f83cdce9b0b828db14 (patch) | |
| tree | 1d687734f79effb728f27a0b2dd24edc7d7ae910 /backend/models | |
| parent | Merge pull request #12 from python-discord/ks123/admin-authentication (diff) | |
| parent | Ignore too long line for if statement (diff) | |
Merge pull request #11 from python-discord/ks123/models
Diffstat (limited to 'backend/models')
| -rw-r--r-- | backend/models/__init__.py | 4 | ||||
| -rw-r--r-- | backend/models/form.py | 27 | ||||
| -rw-r--r-- | backend/models/question.py | 54 | 
3 files changed, 85 insertions, 0 deletions
| diff --git a/backend/models/__init__.py b/backend/models/__init__.py new file mode 100644 index 0000000..80abf6f --- /dev/null +++ b/backend/models/__init__.py @@ -0,0 +1,4 @@ +from .form import Form +from .question import Question + +__all__ = ["Form", "Question"] diff --git a/backend/models/form.py b/backend/models/form.py new file mode 100644 index 0000000..d0f0a3c --- /dev/null +++ b/backend/models/form.py @@ -0,0 +1,27 @@ +import typing as t + +from pydantic import BaseModel, Field, validator + +from backend.constants import FormFeatures +from backend.models import Question + + +class Form(BaseModel): +    """Schema model for form.""" + +    id: str = Field(alias="_id") +    features: t.List[str] +    questions: t.List[Question] + +    @validator("features") +    def validate_features(self, value: t.List[str]) -> t.Optional[t.List[str]]: +        """Validates is all features in allowed list.""" +        # Uppercase everything to avoid mixed case in DB +        value = [v.upper() for v in value] +        if not all(v in FormFeatures.__members__.values() for v in value): +            raise ValueError("Form features list contains one or more invalid values.") + +        if FormFeatures.COLLECT_EMAIL in value and FormFeatures.REQUIRES_LOGIN not in value:  # noqa +            raise ValueError("COLLECT_EMAIL feature require REQUIRES_LOGIN feature.") + +        return value diff --git a/backend/models/question.py b/backend/models/question.py new file mode 100644 index 0000000..2324a47 --- /dev/null +++ b/backend/models/question.py @@ -0,0 +1,54 @@ +import typing as t + +from pydantic import BaseModel, Field, validator + +from backend.constants import QUESTION_TYPES, REQUIRED_QUESTION_TYPE_DATA + + +class Question(BaseModel): +    """Schema model for form question.""" + +    id: str = Field(alias="_id") +    name: str +    type: str +    data: t.Dict[str, t.Any] + +    @validator("type", pre=True) +    def validate_question_type(self, value: str) -> t.Optional[str]: +        """Checks if question type in currently allowed types list.""" +        value = value.lower() +        if value not in QUESTION_TYPES: +            raise ValueError( +                f"{value} is not valid question type. " +                f"Allowed question types: {QUESTION_TYPES}." +            ) + +        return value + +    @validator("data") +    def validate_question_data( +            self, +            value: t.Dict[str, t.Any] +    ) -> t.Optional[t.Dict[str, t.Any]]: +        """Check does required data exists for question type and remove other data.""" +        # When question type don't need data, don't add anything to keep DB clean. +        if self.type not in REQUIRED_QUESTION_TYPE_DATA: +            return {} + +        # Required keys (and values) will be stored to here +        # to remove all unnecessary stuff +        result = {} + +        for key, data_type in REQUIRED_QUESTION_TYPE_DATA[self.type].items(): +            if key not in value: +                raise ValueError(f"Required question data key '{key}' not provided.") + +            if not isinstance(value[key], data_type): +                raise ValueError( +                    f"Question data key '{key}' expects {data_type.__name__}, " +                    f"got {type(value[key]).__name__} instead." +                ) + +            result[key] = value[key] + +        return result | 
