mirror of
https://github.com/grey-cat-1908/formaptix-server.git
synced 2024-11-11 18:57:27 +03:00
fixes
This commit is contained in:
parent
4c06904661
commit
a1e46dd7bb
2 changed files with 27 additions and 18 deletions
|
@ -1,6 +1,6 @@
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
from typing import TypeAlias, Annotated
|
from typing import Annotated, Union, Literal
|
||||||
|
|
||||||
from pydantic import field_validator, field_serializer, Field
|
from pydantic import field_validator, field_serializer, Field
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ class BaseValue(BaseModel):
|
||||||
|
|
||||||
|
|
||||||
class TextValue(BaseValue):
|
class TextValue(BaseValue):
|
||||||
question_type: form.QuestionType = form.QuestionType.text
|
question_type: Literal[form.QuestionType.text] = form.QuestionType.text
|
||||||
value: str
|
value: str
|
||||||
|
|
||||||
def validate(self, question: form.TextQuestion) -> None:
|
def validate(self, question: form.TextQuestion) -> None:
|
||||||
|
@ -53,7 +53,7 @@ class TextValue(BaseValue):
|
||||||
|
|
||||||
|
|
||||||
class ScaleValue(BaseValue):
|
class ScaleValue(BaseValue):
|
||||||
question_type: form.QuestionType = form.QuestionType.scale
|
question_type: Literal[form.QuestionType.scale] = form.QuestionType.scale
|
||||||
value: int
|
value: int
|
||||||
|
|
||||||
def validate(self, question: form.ScaleQuestion) -> None:
|
def validate(self, question: form.ScaleQuestion) -> None:
|
||||||
|
@ -62,13 +62,17 @@ class ScaleValue(BaseValue):
|
||||||
|
|
||||||
|
|
||||||
class SelectorValue(BaseValue):
|
class SelectorValue(BaseValue):
|
||||||
question_type: form.QuestionType = form.QuestionType.selector
|
question_type: Literal[form.QuestionType.selector] = form.QuestionType.selector
|
||||||
values: set[int]
|
values: set[int]
|
||||||
|
|
||||||
|
@field_serializer("values")
|
||||||
|
def serialize_values(self, values: set[int]):
|
||||||
|
return list(values)
|
||||||
|
|
||||||
def validate(self, question: form.SelectorQuestion) -> None:
|
def validate(self, question: form.SelectorQuestion) -> None:
|
||||||
min_values = max(question.min_values, 1) if question.min_values else 1
|
min_values = max(question.min_values, 1) if question.min_values else 1
|
||||||
max_values = (
|
max_values = (
|
||||||
min(question.max_values, question.options)
|
min(question.max_values, len(question.options))
|
||||||
if question.max_values
|
if question.max_values
|
||||||
else len(question.options)
|
else len(question.options)
|
||||||
)
|
)
|
||||||
|
@ -79,7 +83,7 @@ class SelectorValue(BaseValue):
|
||||||
raise ValueError(AnswerError.TOO_MANY_SELECTED.value)
|
raise ValueError(AnswerError.TOO_MANY_SELECTED.value)
|
||||||
|
|
||||||
|
|
||||||
Value: TypeAlias = SelectorValue | TextValue | ScaleValue
|
Value = Annotated[Union[SelectorValue, TextValue, ScaleValue], Field(discriminator='question_type')]
|
||||||
|
|
||||||
|
|
||||||
class AnswerData(BaseModel):
|
class AnswerData(BaseModel):
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from enum import IntEnum, Enum
|
from enum import IntEnum, Enum
|
||||||
from typing import TypeAlias
|
from typing import Annotated, Union, Literal
|
||||||
from uuid import UUID, uuid4
|
from uuid import UUID, uuid4
|
||||||
|
|
||||||
from pydantic import Field, field_validator, field_serializer
|
from pydantic import Field, field_validator, field_serializer
|
||||||
|
@ -16,6 +16,7 @@ class FormError(Enum):
|
||||||
SIMMILAR_ID_ERR = "All questions must have different id's"
|
SIMMILAR_ID_ERR = "All questions must have different id's"
|
||||||
SCALE_MIN_VALUE_ERR = "min_value must be in range from 0 to 1"
|
SCALE_MIN_VALUE_ERR = "min_value must be in range from 0 to 1"
|
||||||
SCALE_MAX_VALUE_ERR = "max_value must be in range from 2 to 10"
|
SCALE_MAX_VALUE_ERR = "max_value must be in range from 2 to 10"
|
||||||
|
EMPTY_OPTIONS_ERR = "Options field cannot be empty"
|
||||||
|
|
||||||
|
|
||||||
class QuestionType(IntEnum):
|
class QuestionType(IntEnum):
|
||||||
|
@ -44,11 +45,11 @@ class BaseQuestion(BaseModel):
|
||||||
|
|
||||||
class Option(BaseModel):
|
class Option(BaseModel):
|
||||||
label: str
|
label: str
|
||||||
image_url: str | None
|
image_url: str | None = None
|
||||||
|
|
||||||
|
|
||||||
class TextQuestion(BaseQuestion):
|
class TextQuestion(BaseQuestion):
|
||||||
question_type: QuestionType = QuestionType.text
|
question_type: Literal[QuestionType.text] = QuestionType.text
|
||||||
validator: TextValidator | None = None
|
validator: TextValidator | None = None
|
||||||
min_length: int | None = None
|
min_length: int | None = None
|
||||||
max_length: int | None = None
|
max_length: int | None = None
|
||||||
|
@ -80,7 +81,7 @@ class TextQuestion(BaseQuestion):
|
||||||
|
|
||||||
|
|
||||||
class ScaleQuestion(BaseQuestion):
|
class ScaleQuestion(BaseQuestion):
|
||||||
question_type: QuestionType = QuestionType.scale
|
question_type: Literal[QuestionType.scale] = QuestionType.scale
|
||||||
min_value: int
|
min_value: int
|
||||||
min_label: str | None = None
|
min_label: str | None = None
|
||||||
max_value: int
|
max_value: int
|
||||||
|
@ -102,17 +103,22 @@ class ScaleQuestion(BaseQuestion):
|
||||||
|
|
||||||
|
|
||||||
class SelectorQuestion(BaseQuestion):
|
class SelectorQuestion(BaseQuestion):
|
||||||
question_type: QuestionType = QuestionType.selector
|
question_type: Literal[QuestionType.selector] = QuestionType.selector
|
||||||
min_values: int = 1
|
min_values: int = 1
|
||||||
max_values: int | None = None
|
max_values: int | None = None
|
||||||
options: list[Option] = []
|
options: list[Option]
|
||||||
|
|
||||||
|
@field_validator("options")
|
||||||
|
@classmethod
|
||||||
|
def validate_options(cls, v, info):
|
||||||
|
if len(v) < 1:
|
||||||
|
raise ValueError(FormError.EMPTY_OPTIONS_ERR.value)
|
||||||
|
return v
|
||||||
|
|
||||||
@field_validator("min_values")
|
@field_validator("min_values")
|
||||||
@classmethod
|
@classmethod
|
||||||
def validate_min_values(cls, v, info):
|
def validate_min_values(cls, v, info):
|
||||||
options = info.data.get("options")
|
if v is not None and v < 1:
|
||||||
options = [] if not options else options
|
|
||||||
if v is not None and (v < 1 or v > len(options)):
|
|
||||||
raise ValueError(FormError.MIN_VALUES_ERR.value)
|
raise ValueError(FormError.MIN_VALUES_ERR.value)
|
||||||
return v
|
return v
|
||||||
|
|
||||||
|
@ -120,13 +126,12 @@ class SelectorQuestion(BaseQuestion):
|
||||||
@classmethod
|
@classmethod
|
||||||
def validate_max_values(cls, v, info):
|
def validate_max_values(cls, v, info):
|
||||||
min_values = info.data.get("min_values")
|
min_values = info.data.get("min_values")
|
||||||
options = info.data.get("options")
|
if v is not None and min_values > v:
|
||||||
if v is not None and (v > len(options) or min_values > v):
|
|
||||||
raise ValueError(FormError.MAX_VALUES_ERR.value)
|
raise ValueError(FormError.MAX_VALUES_ERR.value)
|
||||||
return v
|
return v
|
||||||
|
|
||||||
|
|
||||||
Question: TypeAlias = SelectorQuestion | TextQuestion | ScaleQuestion
|
Question = Annotated[Union[SelectorQuestion, TextQuestion, ScaleQuestion], Field(discriminator='question_type')]
|
||||||
|
|
||||||
|
|
||||||
class Page(BaseModel):
|
class Page(BaseModel):
|
||||||
|
|
Loading…
Reference in a new issue