from enum import Enum from typing import List from typing import TYPE_CHECKING, Optional from pydantic import BaseModel from pydantic import validator from sqlalchemy.inspection import inspect from sqlmodel import JSON, Column from sqlmodel import SQLModel, Field, Relationship from database.auth.models import User from services.io import get_filename_from_path from services.schema import as_form from .FileField import FileField if TYPE_CHECKING: from database.auth.models import User class ExampleEnum(str, Enum): csv = 'csv' pdf = 'pdf' web = 'web' undisponible = 'undisponible' class GeneratorOutput(BaseModel): calcul: str correction: str | None = None class Example(BaseModel): type: ExampleEnum = ExampleEnum.undisponible data: List[GeneratorOutput] | None = None class ExercicesTagLink(SQLModel, table=True): exercice_id: Optional[int] = Field( default=None, foreign_key='exercice.id', primary_key=True) tag_id: Optional[int] = Field( default=None, foreign_key='tag.id', primary_key=True) class ExerciceBase(SQLModel): name: str = Field(max_length=50, index=True) consigne: Optional[str] = Field(max_length=200, default=None) private: Optional[bool] = Field(default=False) class Supports(SQLModel): csv: bool pdf: bool web: bool class Exercice(ExerciceBase, Supports, table=True): id: Optional[int] = Field(default=None, primary_key=True) id_code: str = Field(unique=True, index=True) exo_source: FileField['/uploads'] author_id: int = Field(foreign_key='user.id') author: "User" = Relationship(back_populates='exercices') origin_id: Optional[int] = Field( foreign_key='exercice.id', default=None, nullable=True) original: Optional['Exercice'] = Relationship(back_populates='duplicated', sa_relationship_kwargs=dict( remote_side='Exercice.id' )) duplicated: List['Exercice'] = Relationship(back_populates='original') tags: List['Tag'] = Relationship( back_populates='exercices', link_model=ExercicesTagLink) examples: Optional[Example] = Field( sa_column=Column(JSON), default={}) def dict_relationship(self, *, exclude: List[str], include: List[str]): relationships = inspect(self.__class__).relationships.items() relationsData = {rname: getattr(self, rname) for rname, rp in relationships if rname not in exclude and (rname in include if len(include) != 0 else True)} return {**self.dict(), **relationsData} class Config: validate_assignment = True extra = 'allow' # translate the folowing object to python enum class ColorEnum(Enum): bleu = "rgb(51,123,255)" vert = "rgb(0,204,0)" rouge = "rgb(255,0,0)" marron = "rgb(153,76,0)" violet = "rgb(204,0,204)" jaune = "rgb(255,255,0)" orange = "rgb(255,128,0)" noir = "rgb(10,10,10)" rose = "rgb(255,102,255)" blanc = "rgb(240,240,240)" blanche = "rgb(240,240,240)" class TagBase(SQLModel): label: str = Field(max_length=20) color: ColorEnum class Tag(TagBase, table=True): id: Optional[int] = Field(default=None, primary_key=True) id_code: str = Field(unique=True, index=True) author_id: int = Field(foreign_key='user.id') author: "User" = Relationship(back_populates='tags') exercices: List["Exercice"] = Relationship( back_populates='tags', link_model=ExercicesTagLink) class TagCreate(TagBase): id_code: str = None class TagRead(TagBase): id_code: str @as_form class ExerciceCreate(ExerciceBase): pass class ExerciceEdit(ExerciceCreate): pass class Author(SQLModel): username: str class ExerciceOrigin(SQLModel): # id: int id_code: str name: str author: str def get_source_path_from_name_and_id(name: str, id_code: str): return f'/uploads/{id_code}/{name}' class ExerciceReadBase(ExerciceBase): id_code: str author: Author original: ExerciceOrigin | None tags: List[TagRead] = None exo_source: str examples: Example = None is_author: bool = None @validator('exo_source') def get_exo_source_name(cls, value, values): if value is not None: return get_filename_from_path(value) return value class ExerciceRead(ExerciceBase, Supports): id_code: str id: int author_id: int exo_source: str author: User original: Optional[Exercice] tags: List[Tag] examples: Example class ExerciceReadFull(ExerciceReadBase): supports: Supports