From df2d8f33a545cd33cad9b9cef1a32f5bea3d5228 Mon Sep 17 00:00:00 2001 From: matsewe Date: Mon, 26 May 2025 10:48:10 +0200 Subject: [PATCH] include time restriction --- app/api/deps.py | 2 + app/api/routes/registration.py | 31 ++++++------- app/core/config.py | 16 ++++++- app/core/db.py | 3 +- app/crud.py | 6 ++- app/index.html | 79 ---------------------------------- app/main.py | 37 ++++++++++++++-- app/models.py | 9 ++-- pyproject.toml | 1 + uv.lock | 11 +++++ 10 files changed, 90 insertions(+), 105 deletions(-) delete mode 100644 app/index.html diff --git a/app/api/deps.py b/app/api/deps.py index 90f832e..f8998c8 100644 --- a/app/api/deps.py +++ b/app/api/deps.py @@ -6,8 +6,10 @@ from sqlmodel import Session from app.core.db import engine + def get_db() -> Generator[Session, None, None]: with Session(engine) as session: yield session + SessionDep = Annotated[Session, Depends(get_db)] diff --git a/app/api/routes/registration.py b/app/api/routes/registration.py index b8320eb..e8bb860 100644 --- a/app/api/routes/registration.py +++ b/app/api/routes/registration.py @@ -5,27 +5,28 @@ from app.models import RegistrationCreate from app import crud from app.api.deps import SessionDep +from app.core.utils import is_registration_open + +from fastapi.responses import RedirectResponse + router = APIRouter(prefix="/registration") @router.post( - "/register", + "/register_form", ) -def register(*, session: SessionDep, registration_create: Annotated[RegistrationCreate, Form()]): - print(registration_create) +def register( + *, session: SessionDep, registration_create: Annotated[RegistrationCreate, Form()] +): """ Register """ - registration = crud.create_registration(session=session, registration_create=registration_create) - #if settings.emails_enabled and user_in.email: - # email_data = generate_new_account_email( - # email_to=user_in.email, username=user_in.email, password=user_in.password - # ) - # send_email( - # email_to=user_in.email, - # subject=email_data.subject, - # html_content=email_data.html_content, - # ) - - return registration + if is_registration_open(): + crud.create_registration( + session=session, registration_create=registration_create + ) + + return RedirectResponse("/success.html", status_code=303) + else: + return RedirectResponse("/", status_code=303) diff --git a/app/core/config.py b/app/core/config.py index a120448..3825b38 100644 --- a/app/core/config.py +++ b/app/core/config.py @@ -1,10 +1,24 @@ from pydantic_settings import BaseSettings import os +from datetime import datetime +from zoneinfo import ZoneInfo + +date_format = "%Y-%m-%dT%H:%M:%S%z" + class Settings(BaseSettings): API_V1_STR: str = "" PROJECT_NAME: str = "Choriosity Anmeldung" - SQLALCHEMY_DATABASE_URI: str = "sqlite:///" + os.environ.get("DATABASE_URL", "/data/db.sqlite") + SQLALCHEMY_DATABASE_URI: str = "sqlite:///" + os.environ.get( + "DATABASE_URL", "/data/db.sqlite" + ) + NOT_BEFORE: datetime = datetime.strptime( + os.environ.get("NOT_BEFORE", "2000-01-01T00:00:01+02:00"), date_format + ) + NOT_AFTER: datetime = datetime.strptime( + os.environ.get("NOT_AFTER", "2100-01-01T00:00:01+02:00"), date_format + ) + TZ: ZoneInfo = ZoneInfo(os.environ.get("TZ", "Europe/Berlin")) settings = Settings() diff --git a/app/core/db.py b/app/core/db.py index de82afe..86af4e6 100644 --- a/app/core/db.py +++ b/app/core/db.py @@ -9,6 +9,7 @@ engine = create_engine(str(settings.SQLALCHEMY_DATABASE_URI)) # otherwise, SQLModel might fail to initialize relationships properly # for more details: https://github.com/fastapi/full-stack-fastapi-template/issues/28 + def init_db(session: Session) -> None: # Tables should be created with Alembic migrations # But if you don't want to use migrations, create @@ -16,4 +17,4 @@ def init_db(session: Session) -> None: from sqlmodel import SQLModel # This works because the models are already imported and registered from app.models - SQLModel.metadata.create_all(engine) \ No newline at end of file + SQLModel.metadata.create_all(engine) diff --git a/app/crud.py b/app/crud.py index 846f2c6..e09e2f5 100644 --- a/app/crud.py +++ b/app/crud.py @@ -3,9 +3,11 @@ from sqlmodel import Session from app.models import Registration, RegistrationCreate -def create_registration(*, session: Session, registration_create: RegistrationCreate) -> Registration: +def create_registration( + *, session: Session, registration_create: RegistrationCreate +) -> Registration: db_obj = Registration.model_validate(registration_create) session.add(db_obj) session.commit() session.refresh(db_obj) - return db_obj \ No newline at end of file + return db_obj diff --git a/app/index.html b/app/index.html deleted file mode 100644 index cfd4d84..0000000 --- a/app/index.html +++ /dev/null @@ -1,79 +0,0 @@ - - - - Choriosity Anmeldung - - - -
- - - - - - - -
- Welche Stimme singst du? - -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
- -
- - -
-
- -
- Wie lange bleibst du in Ulm? - -
- - -
- -
- - -
- -
- - -
- -
- - -
-
- - - -
- - - \ No newline at end of file diff --git a/app/main.py b/app/main.py index df65cc7..3f00c7d 100644 --- a/app/main.py +++ b/app/main.py @@ -1,7 +1,10 @@ -from fastapi import FastAPI +from fastapi import FastAPI, Request +from fastapi.staticfiles import StaticFiles from fastapi.responses import FileResponse +from fastapi.templating import Jinja2Templates + from app.api.main import api_router from app.core.config import settings @@ -9,6 +12,8 @@ from app.core.db import init_db, engine from sqlmodel import Session +from app.core.utils import is_registration_open + with Session(engine) as session: init_db(session) @@ -16,10 +21,34 @@ app = FastAPI( title=settings.PROJECT_NAME, openapi_url=f"{settings.API_V1_STR}/openapi.json" ) -@api_router.get("/") -def index(): - return FileResponse("app/index.html") +templates = Jinja2Templates(directory="app/templates") +@api_router.get("/") +def index(request: Request): + reg_open, not_before, not_after = is_registration_open() + if reg_open: + return templates.TemplateResponse( + request=request, name="registration-open.html", context={} + ) + else: + return templates.TemplateResponse( + request=request, name="registration-closed.html", context={ + "not_before": settings.NOT_BEFORE, + "not_after": settings.NOT_AFTER, + } + ) + +@api_router.get("/success.html") +def success(request: Request): + return templates.TemplateResponse( + request=request, name="registration-success.html", context={ + "not_before": settings.NOT_BEFORE, + "not_after": settings.NOT_AFTER, + } + ) + app.include_router(api_router, prefix=settings.API_V1_STR) +app.mount("/static", StaticFiles(directory="app/static"), name="static") + diff --git a/app/models.py b/app/models.py index 75acb0b..5bad98d 100644 --- a/app/models.py +++ b/app/models.py @@ -25,18 +25,21 @@ class PeriodEnum(str, Enum): twoyears = "1 - 2 Jahre" longterm = "mehr als zwei Jahre" + class RegistrationBase(SQLModel): - email: EmailStr = Field(unique=True, index=True, max_length=255) + email: EmailStr = Field(max_length=255) first_name: str last_name: str birthday: date voice: VoiceEnum duration: PeriodEnum - + number_of_attempts: int + + class RegistrationCreate(RegistrationBase): pass + class Registration(RegistrationBase, table=True): id: uuid.UUID = Field(default_factory=uuid.uuid4, primary_key=True) timestamp: datetime = Field(default_factory=func.now) - diff --git a/pyproject.toml b/pyproject.toml index 08c2916..d30ce99 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,6 +9,7 @@ dependencies = [ "pydantic>=2.11.5", "pydantic-settings>=2.9.1", "sqlmodel>=0.0.24", + "tzdata>=2025.2", ] [tool.uv] diff --git a/uv.lock b/uv.lock index 4659ba9..6b271e1 100644 --- a/uv.lock +++ b/uv.lock @@ -43,6 +43,7 @@ dependencies = [ { name = "pydantic" }, { name = "pydantic-settings" }, { name = "sqlmodel" }, + { name = "tzdata" }, ] [package.dev-dependencies] @@ -58,6 +59,7 @@ requires-dist = [ { name = "pydantic", specifier = ">=2.11.5" }, { name = "pydantic-settings", specifier = ">=2.9.1" }, { name = "sqlmodel", specifier = ">=0.0.24" }, + { name = "tzdata", specifier = ">=2025.2" }, ] [package.metadata.requires-dev] @@ -718,6 +720,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552 }, ] +[[package]] +name = "tzdata" +version = "2025.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839 }, +] + [[package]] name = "uvicorn" version = "0.34.2"