add(templates): base models and dto for girasol backend
Some checks failed
Deploy Girasol / deploy (push) Has been cancelled
Some checks failed
Deploy Girasol / deploy (push) Has been cancelled
This commit is contained in:
176
backend/.gitignore
vendored
Normal file
176
backend/.gitignore
vendored
Normal file
@@ -0,0 +1,176 @@
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/python
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=python
|
||||
|
||||
### Python ###
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
# .python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
#poetry.lock
|
||||
|
||||
# pdm
|
||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
||||
#pdm.lock
|
||||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
||||
# in version control.
|
||||
# https://pdm.fming.dev/#use-with-ide
|
||||
.pdm.toml
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
||||
|
||||
### Python Patch ###
|
||||
# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
|
||||
poetry.toml
|
||||
|
||||
# ruff
|
||||
.ruff_cache/
|
||||
|
||||
# LSP config files
|
||||
pyrightconfig.json
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/python
|
||||
6
backend/README.md
Normal file
6
backend/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# FastAPI Backend
|
||||
|
||||
```sh
|
||||
hatch shell
|
||||
fastapi dev
|
||||
```
|
||||
72
backend/pyproject.toml
Normal file
72
backend/pyproject.toml
Normal file
@@ -0,0 +1,72 @@
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "backend"
|
||||
dynamic = ["version"]
|
||||
description = ''
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.11"
|
||||
license = "MIT"
|
||||
keywords = []
|
||||
authors = [
|
||||
{ name = "Julien Aldon", email = "julien.aldon@wanadoo.fr" },
|
||||
]
|
||||
classifiers = [
|
||||
"Development Status :: 4 - Beta",
|
||||
"Programming Language :: Python",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
"Programming Language :: Python :: Implementation :: CPython",
|
||||
"Programming Language :: Python :: Implementation :: PyPy",
|
||||
]
|
||||
dependencies = [
|
||||
"fastapi[standard]",
|
||||
"sqlmodel",
|
||||
"psycopg2-binary",
|
||||
"PyJWT",
|
||||
"cryptography",
|
||||
"pytest",
|
||||
"pytest-cov",
|
||||
"pytest-mock",
|
||||
"pylint",
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
Documentation = ""
|
||||
Issues = ""
|
||||
Source = ""
|
||||
|
||||
[tool.hatch.version]
|
||||
path = "src/__about__.py"
|
||||
|
||||
[tool.hatch.envs.types]
|
||||
extra-dependencies = [
|
||||
"mypy>=1.0.0",
|
||||
]
|
||||
[tool.hatch.envs.types.scripts]
|
||||
check = "mypy --install-types --non-interactive {args:src tests}"
|
||||
|
||||
[tool.coverage.run]
|
||||
source_pkgs = ["backend", "tests"]
|
||||
branch = true
|
||||
parallel = true
|
||||
omit = [
|
||||
"src/__about__.py",
|
||||
]
|
||||
|
||||
[tool.coverage.paths]
|
||||
backend = ["src", "*/backend/src/"]
|
||||
tests = ["tests", "*/backend/tests"]
|
||||
|
||||
[tool.coverage.report]
|
||||
exclude_lines = [
|
||||
"no cov",
|
||||
"if __name__ == .__main__.:",
|
||||
"if TYPE_CHECKING:",
|
||||
]
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["src"]
|
||||
include = ["src/**/*.py"]
|
||||
6
backend/src/__about__.py
Normal file
6
backend/src/__about__.py
Normal file
@@ -0,0 +1,6 @@
|
||||
"""About
|
||||
"""
|
||||
# SPDX-FileCopyrightText: 2026-present Julien Aldon <julien.aldon@wanadoo.fr>
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
__version__ = "0.0.1"
|
||||
3
backend/src/__init__.py
Normal file
3
backend/src/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
# SPDX-FileCopyrightText: 2026-present Julien Aldon <julien.aldon@wanadoo.fr>
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
95
backend/src/events/dto.py
Normal file
95
backend/src/events/dto.py
Normal file
@@ -0,0 +1,95 @@
|
||||
"""Event module DTO
|
||||
"""
|
||||
import datetime
|
||||
import uuid
|
||||
from typing import List, Optional
|
||||
|
||||
from sqlmodel import Field, SQLModel
|
||||
from src.events.models import BaseEdition, BaseSeries, BaseTag
|
||||
from src.files.dto import ReadFile
|
||||
|
||||
|
||||
class CreateSeries(BaseSeries):
|
||||
"""CreateSeries DTO
|
||||
"""
|
||||
logotype_id: uuid.UUID = Field()
|
||||
|
||||
|
||||
class UpdateSeries(SQLModel):
|
||||
"""UpdateSeries DTO
|
||||
"""
|
||||
title: Optional[str] = None
|
||||
color_light: Optional[str] = None
|
||||
color_dark: Optional[str] = None
|
||||
color_strong: Optional[str] = None
|
||||
|
||||
|
||||
class ReadSeriesLight(BaseSeries):
|
||||
"""Lighter version of ReadSeries for nested usage.
|
||||
"""
|
||||
id: uuid.UUID
|
||||
logotype: ReadFile
|
||||
|
||||
|
||||
class ReadSeries(BaseSeries):
|
||||
"""ReadSeries DTO
|
||||
"""
|
||||
id: uuid.UUID
|
||||
logotype: ReadFile
|
||||
editions: List['ReadEdition'] = Field(default_factory=list)
|
||||
|
||||
|
||||
class CreateEdition(BaseEdition):
|
||||
"""CreateEdition DTO
|
||||
"""
|
||||
flyer_id: uuid.UUID = Field()
|
||||
hero_id: uuid.UUID = Field()
|
||||
series_id: uuid.UUID = Field()
|
||||
|
||||
|
||||
class UpdateEdition(SQLModel):
|
||||
"""UpdateEdition DTO
|
||||
"""
|
||||
title: Optional[str] = None
|
||||
long_description: Optional[dict] = None
|
||||
short_description: Optional[str] = None
|
||||
start_date: Optional[datetime.datetime] = None
|
||||
end_date: Optional[datetime.datetime] = None
|
||||
contact_information: Optional[dict] = None
|
||||
|
||||
|
||||
class ReadEdition(BaseEdition):
|
||||
"""ReadEdition DTO
|
||||
"""
|
||||
id: uuid.UUID
|
||||
sponsors: List['ReadSponsor'] = Field(default_factory=list)
|
||||
flyer: ReadFile
|
||||
hero: ReadFile
|
||||
series: ReadSeriesLight
|
||||
tags: List['ReadTagLight'] = Field(default_factory=list)
|
||||
gallery: List[ReadFile] = Field(default_factory=list)
|
||||
|
||||
|
||||
class CreateTag(BaseTag):
|
||||
"""CreateTag DTO
|
||||
"""
|
||||
|
||||
|
||||
class UpdateTag(SQLModel):
|
||||
"""UpdateTag DTO
|
||||
"""
|
||||
title: Optional[str] = None
|
||||
color: Optional[str] = None
|
||||
|
||||
|
||||
class ReadTagLight(BaseTag):
|
||||
"""Lighter version of ReadTag for nested usage.
|
||||
"""
|
||||
id: uuid.UUID
|
||||
|
||||
|
||||
class ReadTag(BaseTag):
|
||||
"""ReadTag DTO
|
||||
"""
|
||||
id: uuid.UUID
|
||||
editions: List['ReadEdition'] = Field(default_factory=list)
|
||||
145
backend/src/events/models.py
Normal file
145
backend/src/events/models.py
Normal file
@@ -0,0 +1,145 @@
|
||||
"""Event module models
|
||||
"""
|
||||
import datetime
|
||||
import uuid
|
||||
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
from sqlmodel import Field, Relationship, SQLModel
|
||||
|
||||
|
||||
class BaseSeries(SQLModel):
|
||||
"""Base model for a series.
|
||||
|
||||
Attributes:
|
||||
title (str): Name of the series.
|
||||
color_light (str): Light theme color.
|
||||
color_dark (str): Dark theme color.
|
||||
color_strong (str): Accent / Primary color.
|
||||
"""
|
||||
title: str
|
||||
color_light: str
|
||||
color_dark: str
|
||||
color_strong: str
|
||||
|
||||
|
||||
class Series(BaseSeries, table=True):
|
||||
"""Database model representing a series of editions.
|
||||
|
||||
A series of events under the same branding
|
||||
|
||||
Attributes:
|
||||
id (uuid.UUID): unique identifier of the series.
|
||||
logotype_id (uuid.UUID): Reference to the logotype file.
|
||||
editions (list['Edition']): List of editions belonging to this series.
|
||||
"""
|
||||
id: uuid.UUID | None = Field(
|
||||
default=None, default_factory=uuid.uuid4, primary_key=True)
|
||||
logotype_id: uuid.UUID = Field(foreign_key="file.id")
|
||||
editions: list['Edition'] = Relationship(back_populates='series')
|
||||
|
||||
|
||||
class BaseEdition(SQLModel):
|
||||
"""Base model for an edition
|
||||
|
||||
Attributes:
|
||||
title (str): Name of the edition.
|
||||
long_description (dict): Description block of the edition.
|
||||
short_description (str): Description of the edition for SEO.
|
||||
start_date (datetime.datetime): Start date of the edition.
|
||||
end_date (datetime.datetime): End date of the edition.
|
||||
contact_information (dict): Contact information block for contact page.
|
||||
"""
|
||||
title: str
|
||||
long_description: dict = Field(sa_type=JSONB, nullable=False)
|
||||
short_description: str
|
||||
start_date: datetime.datetime
|
||||
end_date: datetime.datetime
|
||||
contact_information: dict = Field(sa_type=JSONB, nullable=False)
|
||||
|
||||
|
||||
class EditionTagLink(SQLModel, table=True):
|
||||
"""Association table linking editions and tags
|
||||
|
||||
Represents a many-to-many relationship between editions and tags.
|
||||
"""
|
||||
edition_id: uuid.UUID = Field(foreign_key="edition.id", primary_key=True)
|
||||
tag_id: uuid.UUID = Field(foreign_key="tag.id", primary_key=True)
|
||||
|
||||
|
||||
class EditionFileLink(SQLModel, table=True):
|
||||
"""Association table linking editions and files
|
||||
|
||||
Represents a many-to-many relationship between editions and files.
|
||||
"""
|
||||
edition_id: uuid.UUID = Field(foreign_key="edition.id", primary_key=True)
|
||||
file_id: uuid.UUID = Field(foreign_key="file.id", primary_key=True)
|
||||
|
||||
|
||||
class EditionSponsorLink(SQLModel, table=True):
|
||||
"""Association table linking editions and sponsors.
|
||||
|
||||
Represents a many-to-many relationship between editions and sponsors.
|
||||
"""
|
||||
edition_id: uuid.UUID = Field(foreign_key="edition.id", primary_key=True)
|
||||
sponsor_id: uuid.UUID = Field(foreign_key="sponsor.id", primary_key=True)
|
||||
|
||||
|
||||
class Edition(BaseEdition, table=True):
|
||||
"""Database model representing an A single iteration of an event.
|
||||
|
||||
An edition will have it's own page to display its informations.
|
||||
|
||||
Attributes:
|
||||
id (uuid.UUID): unique identifier of the edition.
|
||||
series_id (uuid.UUID): Reference to edition's series
|
||||
flyer_id (uuid.UUID): Reference to the flyer file.
|
||||
Image used as flyer under herobanner in edition Page.
|
||||
hero_id (uuid.UUID): Reference to the hero file.
|
||||
Image used as herobanner for edition Page.
|
||||
sponsors (List['Sponsor']): List of sponsors belonging to this edition.
|
||||
series (Series): Series Object reference.
|
||||
tags (List('Tag')): List of tags associated to this edition.
|
||||
tags (List('File')): List of Images associated to this edition.
|
||||
"""
|
||||
id: uuid.UUID | None = Field(
|
||||
default=None, default_factory=uuid.uuid4, primary_key=True)
|
||||
series_id: uuid.UUID = Field(foreign_key="series.id")
|
||||
flyer_id: uuid.UUID = Field(foreign_key="file.id")
|
||||
hero_id: uuid.UUID = Field(foreign_key="file.id")
|
||||
sponsors: list['Sponsor'] = Relationship(
|
||||
cascade_delete=True,
|
||||
link_model=EditionSponsorLink,
|
||||
)
|
||||
series: Series = Relationship(back_populates="editions")
|
||||
tags: list['Tag'] = Relationship(
|
||||
link_model=EditionTagLink
|
||||
)
|
||||
gallery: list['File'] = Relationship(
|
||||
link_model=EditionFileLink
|
||||
)
|
||||
|
||||
|
||||
class BaseTag(SQLModel):
|
||||
"""Base model for a Tag
|
||||
|
||||
Attributes:
|
||||
title (str): Name of the tag.
|
||||
color (str): Color of the tag.
|
||||
"""
|
||||
title: str
|
||||
color: str
|
||||
|
||||
|
||||
class Tag(BaseTag, table=True):
|
||||
"""Database model representing a Tag
|
||||
|
||||
A tag is a way to group events with a mutual interests.
|
||||
|
||||
Attributes:
|
||||
id (uudi.UUID): Unique identifier of a tag
|
||||
"""
|
||||
id: uuid.UUID | None = Field(
|
||||
default=None, default_factory=uuid.uuid4, primary_key=True)
|
||||
editions: list['Edition'] = Relationship(
|
||||
link_model=EditionTagLink
|
||||
)
|
||||
27
backend/src/files/dto.py
Normal file
27
backend/src/files/dto.py
Normal file
@@ -0,0 +1,27 @@
|
||||
"""Files module DTO
|
||||
"""
|
||||
import uuid
|
||||
from typing import Optional
|
||||
|
||||
from sqlmodel import SQLModel
|
||||
from src.files.models import BaseFile
|
||||
|
||||
|
||||
class CreateFile(BaseFile):
|
||||
"""CreateFile DTO
|
||||
"""
|
||||
|
||||
|
||||
class UpdateFile(SQLModel):
|
||||
"""UpdateFile DTO
|
||||
"""
|
||||
name: Optional[str] = None
|
||||
type: Optional[str] = None
|
||||
|
||||
|
||||
class ReadFile(BaseFile):
|
||||
"""ReadFile DTO
|
||||
"""
|
||||
id: uuid.UUID
|
||||
path_full: str
|
||||
path_preview: str | None = None
|
||||
31
backend/src/files/models.py
Normal file
31
backend/src/files/models.py
Normal file
@@ -0,0 +1,31 @@
|
||||
"""File module models
|
||||
"""
|
||||
import uuid
|
||||
|
||||
from sqlmodel import Field, SQLModel
|
||||
|
||||
|
||||
class BaseFile(SQLModel):
|
||||
"""Base model for Files
|
||||
|
||||
Attributes:
|
||||
name (str): Name of the file (used in alt).
|
||||
type (str): Type of the file.
|
||||
"""
|
||||
name: str
|
||||
type: str
|
||||
|
||||
|
||||
class File(BaseFile, table=True):
|
||||
"""Database model representing a File
|
||||
|
||||
A file is a stored file through the media center, mostly images.
|
||||
|
||||
Attributes:
|
||||
path_full (str): Path toward the stored file.
|
||||
path_preview (str | None): Path toward a preview.
|
||||
"""
|
||||
id: uuid.UUID | None = Field(
|
||||
default=None, default_factory=uuid.uuid4, primary_key=True)
|
||||
path_full: str
|
||||
path_preview: str | None = None
|
||||
30
backend/src/links/dto.py
Normal file
30
backend/src/links/dto.py
Normal file
@@ -0,0 +1,30 @@
|
||||
"""Links module DTO
|
||||
"""
|
||||
import uuid
|
||||
from typing import Optional
|
||||
|
||||
from sqlmodel import SQLModel
|
||||
from src.events.dto import ReadEdition
|
||||
from src.links.models import BaseLink
|
||||
|
||||
|
||||
class CreateLink(BaseLink):
|
||||
"""CreateLink DTO
|
||||
"""
|
||||
edition_id: uuid.UUID
|
||||
|
||||
|
||||
class UpdateLink(SQLModel):
|
||||
"""UpdateLink DTO
|
||||
"""
|
||||
title: Optional[str] = None
|
||||
icon: Optional[str] = None
|
||||
url: Optional[str] = None
|
||||
order: Optional[int] = None
|
||||
|
||||
|
||||
class ReadLink(BaseLink):
|
||||
"""ReadLink DTO
|
||||
"""
|
||||
id: uuid.UUID
|
||||
edition: Optional[ReadEdition] = None
|
||||
36
backend/src/links/models.py
Normal file
36
backend/src/links/models.py
Normal file
@@ -0,0 +1,36 @@
|
||||
"""Link module models
|
||||
"""
|
||||
import uuid
|
||||
|
||||
from sqlmodel import Field, SQLModel
|
||||
|
||||
|
||||
class BaseLink(SQLModel):
|
||||
"""Base model for a Link
|
||||
|
||||
Attributes:
|
||||
title (str): Name of the link.
|
||||
icon (str): Icon to display this link (using icon library).
|
||||
url (str): Url of the link.
|
||||
order (int): Order of occurence in page.
|
||||
"""
|
||||
title: str
|
||||
icon: str
|
||||
url: str
|
||||
order: int
|
||||
|
||||
|
||||
class Link(BaseLink, table=True):
|
||||
"""Database model representing a Link
|
||||
|
||||
A link featured on an edition's page or in the website's header.
|
||||
|
||||
Attributes:
|
||||
id (uudi.UUID): Unique identifier for a link.
|
||||
edition_id (uuid.UUID | None): Unique identifier of the
|
||||
edition associated to this link (*optional*)
|
||||
"""
|
||||
id: uuid.UUID | None = Field(
|
||||
default=None, default_factory=uuid.uuid4, primary_key=True)
|
||||
edition_id: uuid.UUID | None = Field(
|
||||
default=None, foreign_key="edition.id")
|
||||
3
backend/src/main.py
Normal file
3
backend/src/main.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
34
backend/src/news/dto.py
Normal file
34
backend/src/news/dto.py
Normal file
@@ -0,0 +1,34 @@
|
||||
"""News module DTO
|
||||
"""
|
||||
import datetime
|
||||
import uuid
|
||||
from typing import Optional
|
||||
|
||||
from sqlmodel import SQLModel
|
||||
from src.files.dto import ReadFile
|
||||
from src.news.models import BaseNews
|
||||
|
||||
|
||||
class CreateNews(BaseNews):
|
||||
"""CreateNews DTO
|
||||
"""
|
||||
hero_id: uuid.UUID
|
||||
|
||||
|
||||
class UpdateNews(SQLModel):
|
||||
"""UpdateNews DTO
|
||||
"""
|
||||
title: Optional[str] = None
|
||||
subtitle: Optional[str] = None
|
||||
long_description: Optional[dict] = None
|
||||
short_description: Optional[str] = None
|
||||
carousel: Optional[bool] = None
|
||||
banner: Optional[bool] = None
|
||||
expiry_date: Optional[datetime.datetime] = None
|
||||
|
||||
|
||||
class ReadNews(BaseNews):
|
||||
"""ReadNews DTO
|
||||
"""
|
||||
id: uuid.UUID
|
||||
hero: Optional[ReadFile] = None
|
||||
32
backend/src/news/models.py
Normal file
32
backend/src/news/models.py
Normal file
@@ -0,0 +1,32 @@
|
||||
"""News module models
|
||||
"""
|
||||
import datetime
|
||||
import uuid
|
||||
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
from sqlmodel import Field, SQLModel
|
||||
|
||||
|
||||
class BaseNews(SQLModel):
|
||||
"""Base model for a News
|
||||
|
||||
Attributes:
|
||||
"""
|
||||
title: str
|
||||
subtitle: str
|
||||
long_description: dict = Field(sa_type=JSONB, nullable=False)
|
||||
short_description: str
|
||||
carousel: bool
|
||||
banner: bool
|
||||
expiry_date: datetime.datetime
|
||||
|
||||
|
||||
class News(BaseNews, table=True):
|
||||
"""Database model representing a News
|
||||
|
||||
A plain blog post unrelated to a specific event,
|
||||
appears in the homepage carousel, as a site-wide banner or both
|
||||
"""
|
||||
id: uuid.UUID | None = Field(
|
||||
default=None, default_factory=uuid.uuid4, primary_key=True)
|
||||
hero_id: uuid.UUID = Field(foreign_key="file.id")
|
||||
50
backend/src/sitewide/dto.py
Normal file
50
backend/src/sitewide/dto.py
Normal file
@@ -0,0 +1,50 @@
|
||||
"""Sitewide module DTO
|
||||
"""
|
||||
import uuid
|
||||
from typing import Optional
|
||||
|
||||
from sqlmodel import SQLModel
|
||||
from src.files.dto import ReadFile
|
||||
from src.sitewide.models import (BaseEmbeddedBlock, BaseSite,
|
||||
EmbeddedBlockLayout, EmbeddedBlockLocation)
|
||||
|
||||
|
||||
class CreateSite(BaseSite):
|
||||
"""CreateSite DTO
|
||||
"""
|
||||
image_id: uuid.UUID
|
||||
|
||||
|
||||
class UpdateSite(SQLModel):
|
||||
"""UpdateSite DTO
|
||||
"""
|
||||
legal: Optional[dict] = None
|
||||
about: Optional[dict] = None
|
||||
short_description: Optional[str] = None
|
||||
|
||||
|
||||
class ReadSite(BaseSite):
|
||||
"""ReadSite DTO
|
||||
"""
|
||||
id: uuid.UUID
|
||||
|
||||
|
||||
class CreateEnbeddedBlock(BaseEmbeddedBlock):
|
||||
"""CreateEnbeddedBlock DTO
|
||||
"""
|
||||
|
||||
|
||||
class UpdateEnbeddedBlock(SQLModel):
|
||||
"""UpdateEnbeddedBlock DTO
|
||||
"""
|
||||
title: Optional[str] = None
|
||||
layout: Optional[EmbeddedBlockLayout] = None
|
||||
location: Optional[EmbeddedBlockLocation] = None
|
||||
description: Optional[dict] = None
|
||||
|
||||
|
||||
class ReadEnbeddedBlock(BaseEmbeddedBlock):
|
||||
"""ReadEnbeddedBlock DTO
|
||||
"""
|
||||
id: uuid.UUID
|
||||
image: ReadFile
|
||||
55
backend/src/sitewide/models.py
Normal file
55
backend/src/sitewide/models.py
Normal file
@@ -0,0 +1,55 @@
|
||||
"""Sitewide module models
|
||||
"""
|
||||
import uuid
|
||||
from enum import StrEnum
|
||||
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
from sqlmodel import Field, SQLModel
|
||||
|
||||
|
||||
class EmbeddedBlockLayout(StrEnum):
|
||||
"""Relative layout of an embedded block's image and description
|
||||
"""
|
||||
LEFT = 'left'
|
||||
RIGHT = 'right'
|
||||
CENTER = 'center'
|
||||
|
||||
|
||||
class EmbeddedBlockLocation(StrEnum):
|
||||
"""The location where an embedded block should appear
|
||||
"""
|
||||
HOME = 'home'
|
||||
CONTACT = 'contact'
|
||||
|
||||
|
||||
class BaseSite(SQLModel):
|
||||
"""BaseSite
|
||||
"""
|
||||
legal: dict = Field(sa_type=JSONB, nullable=False)
|
||||
about: dict = Field(sa_type=JSONB, nullable=False)
|
||||
short_description: str
|
||||
|
||||
|
||||
class Site(BaseSite, table=True):
|
||||
"""Database model representing the Site-wide configuration
|
||||
"""
|
||||
id: uuid.UUID | None = Field(
|
||||
default=None, default_factory=uuid.uuid4, primary_key=True)
|
||||
|
||||
|
||||
class BaseEmbeddedBlock(SQLModel):
|
||||
"""BaseEmbeddedBlock
|
||||
"""
|
||||
title: str
|
||||
layout: EmbeddedBlockLayout
|
||||
location: EmbeddedBlockLocation
|
||||
description: dict = Field(sa_type=JSONB, nullable=False)
|
||||
|
||||
|
||||
class EmbeddedBlock(BaseEmbeddedBlock, table=True):
|
||||
"""A paragraph displayed on the home page or contact page
|
||||
with information about Girasol
|
||||
"""
|
||||
id: uuid.UUID | None = Field(
|
||||
default=None, default_factory=uuid.uuid4, primary_key=True)
|
||||
image_id: uuid.UUID = Field(foreign_key="file.id")
|
||||
29
backend/src/sponsors/dto.py
Normal file
29
backend/src/sponsors/dto.py
Normal file
@@ -0,0 +1,29 @@
|
||||
"""Sponsor module DTO
|
||||
"""
|
||||
import uuid
|
||||
from typing import List, Optional
|
||||
|
||||
from sqlmodel import Field, SQLModel
|
||||
from src.events.dto import ReadEdition
|
||||
from src.sponsors.models import BaseSponsor
|
||||
|
||||
|
||||
class CreateSponsor(BaseSponsor):
|
||||
"""CreateSponsor DTO
|
||||
"""
|
||||
image_id: uuid.UUID
|
||||
|
||||
|
||||
class UpdateSponsor(SQLModel):
|
||||
"""UpdateSponsor DTO
|
||||
"""
|
||||
title: Optional[str] = None
|
||||
sitewide: Optional[bool] = None
|
||||
url: Optional[str] = None
|
||||
|
||||
|
||||
class ReadSponsor(BaseSponsor):
|
||||
"""ReadSponsor DTO
|
||||
"""
|
||||
id: uuid.UUID
|
||||
editions: List['ReadEdition'] = Field(default_factory=list)
|
||||
28
backend/src/sponsors/models.py
Normal file
28
backend/src/sponsors/models.py
Normal file
@@ -0,0 +1,28 @@
|
||||
"""Sponsor module model
|
||||
"""
|
||||
import uuid
|
||||
|
||||
from sqlmodel import Field, Relationship, SQLModel
|
||||
from src.sponsors.models import EditionSponsorLink
|
||||
|
||||
|
||||
class BaseSponsor(SQLModel):
|
||||
"""Base Sponsor
|
||||
"""
|
||||
title: str
|
||||
sitewide: bool
|
||||
url: str
|
||||
|
||||
|
||||
class Sponsor(BaseSponsor, table=True):
|
||||
"""Database model representing a Sponsor
|
||||
|
||||
A sponsor for Girasol's activities
|
||||
"""
|
||||
id: uuid.UUID | None = Field(
|
||||
default=None, default_factory=uuid.uuid4, primary_key=True)
|
||||
image_id: uuid.UUID = Field(foreign_key="file.id")
|
||||
editions: list['Edition'] = Relationship(
|
||||
cascade_delete=True,
|
||||
link_model=EditionSponsorLink,
|
||||
)
|
||||
Reference in New Issue
Block a user