Auth: Require logged in user to delete registrations, team_registrations and subscriptions

This commit is contained in:
2025-10-16 10:54:20 +02:00
parent 1df2ecbebf
commit bfe40a4837
4 changed files with 40 additions and 15 deletions

View File

@@ -7,7 +7,7 @@ from typing import Annotated
import starlette.status as status import starlette.status as status
from fastapi import Depends, FastAPI, HTTPException, Request, Response from fastapi import Depends, FastAPI, HTTPException, Request, Response
from fastapi.responses import RedirectResponse, FileResponse from fastapi.responses import FileResponse, RedirectResponse
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
from sqlalchemy import create_engine, select from sqlalchemy import create_engine, select
@@ -132,7 +132,7 @@ async def past_events(request: Request, session: SessionDep):
@app.get("/subscribe") @app.get("/subscribe")
async def subscribe(request: Request, session: SessionDep): async def subscribe(request: Request, session: SessionDep, user: UserDep):
statement = select(Household) statement = select(Household)
households = session.scalars(statement) households = session.scalars(statement)
@@ -146,7 +146,11 @@ async def subscribe(request: Request, session: SessionDep):
return templates.TemplateResponse( return templates.TemplateResponse(
request=request, request=request,
name="subscribe.html", name="subscribe.html",
context={"households": households, "subscriptions": subscriptions}, context={
"households": households,
"subscriptions": subscriptions,
"user": user,
},
) )
@@ -187,7 +191,9 @@ async def add_subscribe(request: Request, session: SessionDep):
@app.get("/subscribe/{household_id}/delete") @app.get("/subscribe/{household_id}/delete")
async def delete_subscription(request: Request, session: SessionDep, household_id: int): async def delete_subscription(
request: Request, session: SessionDep, household_id: int, user: StrictUserDep
):
statement = select(Subscription).where(Subscription.household_id == household_id) statement = select(Subscription).where(Subscription.household_id == household_id)
sub = session.scalars(statement).one() sub = session.scalars(statement).one()
@@ -345,7 +351,11 @@ async def add_registration(request: Request, event_id: int, session: SessionDep)
@app.get("/event/{event_id}/registration/{household_id}/delete") @app.get("/event/{event_id}/registration/{household_id}/delete")
async def delete_registration( async def delete_registration(
request: Request, event_id: int, household_id: int, session: SessionDep request: Request,
event_id: int,
household_id: int,
session: SessionDep,
user: StrictUserDep,
): ):
""" """
Deletes a registration record for a specific household at a given event. This endpoint Deletes a registration record for a specific household at a given event. This endpoint
@@ -388,6 +398,7 @@ async def delete_team_registration(
event_id: int, event_id: int,
entry_id: int, entry_id: int,
session: SessionDep, session: SessionDep,
user: StrictUserDep,
): ):
statement = select(TeamRegistration).where(TeamRegistration.id == entry_id) statement = select(TeamRegistration).where(TeamRegistration.id == entry_id)
session.delete(session.scalars(statement).one()) session.delete(session.scalars(statement).one())

View File

@@ -33,8 +33,12 @@ class Event(Base):
team_prep_min: Mapped[int] = mapped_column(default=1, nullable=False) team_prep_min: Mapped[int] = mapped_column(default=1, nullable=False)
team_prep_max: Mapped[int] = mapped_column(default=1, nullable=False) team_prep_max: Mapped[int] = mapped_column(default=1, nullable=False)
registrations: Mapped[list["Registration"]] = relationship("Registration", cascade="all, delete") registrations: Mapped[list["Registration"]] = relationship(
team: Mapped[list["TeamRegistration"]] = relationship("TeamRegistration", cascade="all, delete") "Registration", cascade="all, delete"
)
team: Mapped[list["TeamRegistration"]] = relationship(
"TeamRegistration", cascade="all, delete"
)
def team_min_reached(self, work_type: WorkTypes): def team_min_reached(self, work_type: WorkTypes):
threshold = { threshold = {
@@ -62,6 +66,14 @@ class Event(Base):
self.team_max_reached(work_type) for work_type in typing.get_args(WorkTypes) self.team_max_reached(work_type) for work_type in typing.get_args(WorkTypes)
) )
@property
def registration_open(self):
return datetime.now() < self.registration_deadline
@property
def in_the_past(self):
return datetime.now() > self.event_time
class TeamRegistration(Base): class TeamRegistration(Base):
__tablename__ = "teamregistration" __tablename__ = "teamregistration"

View File

@@ -3,11 +3,13 @@
{% for entry in event.team | selectattr("work_type", "equalto", work_type)%} {% for entry in event.team | selectattr("work_type", "equalto", work_type)%}
<div class="d-inline-flex align-items-center bg-light border rounded-pill px-3 py-1 m-1"> <div class="d-inline-flex align-items-center bg-light border rounded-pill px-3 py-1 m-1">
<span class="me-2">{{ entry.person_name }}</span> <span class="me-2">{{ entry.person_name }}</span>
{% if user and event.registration_open -%}
<button type="button" class="btn btn-sm p-0 border-0 bg-transparent text-muted"> <button type="button" class="btn btn-sm p-0 border-0 bg-transparent text-muted">
<a href="/event/{{event.id}}/register_team/{{entry.id}}/delete"> <a href="/event/{{event.id}}/register_team/{{entry.id}}/delete">
<i class="bi bi-trash"></i> <i class="bi bi-trash"></i>
</a> </a>
</button> </button>
{% endif -%}
</div> </div>
{% endfor %} {% endfor %}
{%- endmacro %} {%- endmacro %}
@@ -24,10 +26,10 @@
<div class="col-md-4 d-flex justify-content-center align-items-center flex-column"> <div class="col-md-4 d-flex justify-content-center align-items-center flex-column">
<p class="text-muted w-100 mb-2">Anmeldung schließt {{ event.registration_deadline.strftime('%A, %d.%m.%Y, %H:%M Uhr') }}</p> <p class="text-muted w-100 mb-2">Anmeldung schließt {{ event.registration_deadline.strftime('%A, %d.%m.%Y, %H:%M Uhr') }}</p>
<!-- Button trigger modal --> <!-- Button trigger modal -->
<button type="button" class="btn btn-primary mb-2 w-100" {% if event.registration_deadline < now %}disabled{% endif%} data-bs-toggle="modal" data-bs-target="#registration"> <button type="button" class="btn btn-primary mb-2 w-100" {% if not (event.registration_open or (user and user.admin)) %}disabled{% endif%} data-bs-toggle="modal" data-bs-target="#registration">
Anmeldung hinzufügen Anmeldung hinzufügen
</button> </button>
<button type="button" class="btn btn-primary mb-2 w-100" {% if event.all_teams_max() or event.event_time < now %}disabled{% endif %} data-bs-toggle="modal" data-bs-target="#teamRegistration"> <button type="button" class="btn btn-primary mb-2 w-100" {% if event.all_teams_max() or event.in_the_past %}disabled{% endif %} data-bs-toggle="modal" data-bs-target="#teamRegistration">
Dienst übernehmen Dienst übernehmen
</button> </button>
{% if event.recipe_link %} {% if event.recipe_link %}
@@ -129,7 +131,7 @@
<th scope="col">Kinder</th> <th scope="col">Kinder</th>
<th scope="col">Kleinkinder</th> <th scope="col">Kleinkinder</th>
<th scope="col">Kommentar</th> <th scope="col">Kommentar</th>
<th scope="col">Löschen</th> {% if user %}<th scope="col">Löschen</th>{% endif %}
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -140,7 +142,7 @@
<td>{{ reg.num_children_meals }}</td> <td>{{ reg.num_children_meals }}</td>
<td>{{ reg.num_small_children_meals }}</td> <td>{{ reg.num_small_children_meals }}</td>
<td>{% if reg.comment %}{{ reg.comment }}{% endif %}</td> <td>{% if reg.comment %}{{ reg.comment }}{% endif %}</td>
<td><a href="/event/{{event.id}}/registration/{{reg.household_id}}/delete"><i class="bi bi-trash"></i></a></td> {% if user %}<td><a href="/event/{{event.id}}/registration/{{reg.household_id}}/delete"><i class="bi bi-trash"></i></a></td>{% endif %}
</tr> </tr>
{% endfor %} {% endfor %}
</tbody> </tbody>
@@ -154,9 +156,9 @@
<div class="card-body"> <div class="card-body">
<div class="d-flex justify-content-between align-items-start mb-2"> <div class="d-flex justify-content-between align-items-start mb-2">
<h5 class="card-title mb-0">{{ reg.household.name }}</h5> <h5 class="card-title mb-0">{{ reg.household.name }}</h5>
<a href="/event/{{event.id}}/registration/{{reg.household_id}}/delete" class="text-danger"> {% if user %}<a href="/event/{{event.id}}/registration/{{reg.household_id}}/delete" class="text-danger">
<i class="bi bi-trash"></i> <i class="bi bi-trash"></i>
</a> </a>{% endif -%}
</div> </div>
<div class="row mt-3"> <div class="row mt-3">
<div class="col-3 text-center"> <div class="col-3 text-center">

View File

@@ -106,9 +106,9 @@
<div class="card-body py-2 px-3"> <div class="card-body py-2 px-3">
<div class="d-flex justify-content-between align-items-center mb-1"> <div class="d-flex justify-content-between align-items-center mb-1">
<h6 class="mb-0">{{ sub.household.name }}</h6> <h6 class="mb-0">{{ sub.household.name }}</h6>
<a href="/subscribe/{{sub.household.id}}/delete" class="text-danger"> {% if user %}<a href="/subscribe/{{sub.household.id}}/delete" class="text-danger">
<i class="bi bi-trash"></i> <i class="bi bi-trash"></i>
</a> </a>{% endif %}
</div> </div>
<div class="row g-2"> <div class="row g-2">
<div class="col-3 text-center"> <div class="col-3 text-center">