Feat: Add ability to edit events for logged in users
This commit is contained in:
@@ -36,6 +36,7 @@ def get_session():
|
|||||||
with Session(engine) as session:
|
with Session(engine) as session:
|
||||||
yield session
|
yield session
|
||||||
|
|
||||||
|
|
||||||
def get_user(request: Request, allow_none: bool = True) -> dict | None:
|
def get_user(request: Request, allow_none: bool = True) -> dict | None:
|
||||||
"""
|
"""
|
||||||
Retrieve user information from the incoming request.
|
Retrieve user information from the incoming request.
|
||||||
@@ -68,6 +69,7 @@ def get_user(request: Request, allow_none: bool=True) -> dict | None:
|
|||||||
else:
|
else:
|
||||||
raise HTTPException(status_code=401, detail="Not logged in")
|
raise HTTPException(status_code=401, detail="Not logged in")
|
||||||
|
|
||||||
|
|
||||||
def create_db_and_tables():
|
def create_db_and_tables():
|
||||||
Base.metadata.create_all(engine)
|
Base.metadata.create_all(engine)
|
||||||
|
|
||||||
@@ -87,6 +89,8 @@ SessionDep = Annotated[Session, Depends(get_session)]
|
|||||||
|
|
||||||
UserDep = Annotated[dict, Depends(get_user)]
|
UserDep = Annotated[dict, Depends(get_user)]
|
||||||
StrictUserDep = Annotated[dict, Depends(partial(get_user, allow_none=False))]
|
StrictUserDep = Annotated[dict, Depends(partial(get_user, allow_none=False))]
|
||||||
|
|
||||||
|
|
||||||
@app.get("/")
|
@app.get("/")
|
||||||
async def index(request: Request, session: SessionDep, user: UserDep):
|
async def index(request: Request, session: SessionDep, user: UserDep):
|
||||||
"""Displays coming events and a button to register new ones"""
|
"""Displays coming events and a button to register new ones"""
|
||||||
@@ -194,22 +198,46 @@ async def add_event_form(request: Request, user: StrictUserDep):
|
|||||||
return templates.TemplateResponse(request=request, name="add_event.html")
|
return templates.TemplateResponse(request=request, name="add_event.html")
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/event/{event_id}/edit")
|
||||||
|
async def edit_event_form(
|
||||||
|
request: Request, event_id: int, session: SessionDep, user: StrictUserDep
|
||||||
|
):
|
||||||
|
statement = select(Event).where(Event.id == event_id)
|
||||||
|
event = session.scalars(statement).one()
|
||||||
|
|
||||||
|
return templates.TemplateResponse(
|
||||||
|
request=request,
|
||||||
|
context={"event": event, "edit_mode": True},
|
||||||
|
name="add_event.html",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@app.post("/event/{event_id}/edit")
|
||||||
|
async def edit_event(
|
||||||
|
request: Request, event_id: int, session: SessionDep, user: StrictUserDep
|
||||||
|
):
|
||||||
|
statement = select(Event).where(Event.id == event_id)
|
||||||
|
event = session.scalars(statement).one()
|
||||||
|
|
||||||
|
form_data = await request.form()
|
||||||
|
event_time, registration_deadline = await parse_event_times(form_data)
|
||||||
|
|
||||||
|
event.title = form_data["eventName"]
|
||||||
|
event.event_time = event_time
|
||||||
|
event.registration_deadline = registration_deadline
|
||||||
|
event.description = form_data.get("eventDescription")
|
||||||
|
event.recipe_link = form_data.get("recipeLink")
|
||||||
|
|
||||||
|
session.commit()
|
||||||
|
|
||||||
|
return RedirectResponse(url=f"/event/{event.id}", status_code=status.HTTP_302_FOUND)
|
||||||
|
|
||||||
|
|
||||||
@app.post("/event/add")
|
@app.post("/event/add")
|
||||||
async def add_event(request: Request, session: SessionDep, user: StrictUserDep):
|
async def add_event(request: Request, session: SessionDep, user: StrictUserDep):
|
||||||
form_data = await request.form()
|
form_data = await request.form()
|
||||||
|
|
||||||
event_time = datetime.fromisoformat(form_data["eventTime"])
|
event_time, registration_deadline = await parse_event_times(form_data)
|
||||||
registration_deadline = form_data.get("registrationDeadline")
|
|
||||||
if not registration_deadline:
|
|
||||||
# Find the last Sunday before event_time
|
|
||||||
deadline = event_time
|
|
||||||
while deadline.weekday() != 6: # 6 represents Sunday
|
|
||||||
deadline = deadline.replace(day=deadline.day - 1)
|
|
||||||
registration_deadline = deadline.replace(
|
|
||||||
hour=19, minute=30, second=0, microsecond=0
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
registration_deadline = datetime.fromisoformat(registration_deadline)
|
|
||||||
|
|
||||||
event = Event(
|
event = Event(
|
||||||
title=form_data["eventName"],
|
title=form_data["eventName"],
|
||||||
@@ -222,8 +250,27 @@ async def add_event(request: Request, session: SessionDep, user: StrictUserDep):
|
|||||||
session.commit()
|
session.commit()
|
||||||
return RedirectResponse(url="/", status_code=status.HTTP_302_FOUND)
|
return RedirectResponse(url="/", status_code=status.HTTP_302_FOUND)
|
||||||
|
|
||||||
|
|
||||||
|
async def parse_event_times(form_data):
|
||||||
|
event_time = datetime.fromisoformat(form_data["eventTime"])
|
||||||
|
registration_deadline = form_data.get("registrationDeadline")
|
||||||
|
if not registration_deadline:
|
||||||
|
# Find the last Sunday before event_time
|
||||||
|
deadline = event_time
|
||||||
|
while deadline.weekday() != 6: # 6 represents Sunday
|
||||||
|
deadline = deadline.replace(day=deadline.day - 1)
|
||||||
|
registration_deadline = deadline.replace(
|
||||||
|
hour=19, minute=30, second=0, microsecond=0
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
registration_deadline = datetime.fromisoformat(registration_deadline)
|
||||||
|
return event_time, registration_deadline
|
||||||
|
|
||||||
|
|
||||||
@app.get("/event/{event_id}/delete")
|
@app.get("/event/{event_id}/delete")
|
||||||
async def delete_event(request: Request, session: SessionDep, event_id: int, user: StrictUserDep):
|
async def delete_event(
|
||||||
|
request: Request, session: SessionDep, event_id: int, user: StrictUserDep
|
||||||
|
):
|
||||||
if not user["admin"]:
|
if not user["admin"]:
|
||||||
raise HTTPException(status_code=403, detail="Not authorized")
|
raise HTTPException(status_code=403, detail="Not authorized")
|
||||||
|
|
||||||
@@ -234,8 +281,11 @@ async def delete_event(request: Request, session: SessionDep, event_id: int, use
|
|||||||
session.commit()
|
session.commit()
|
||||||
return RedirectResponse(url="/", status_code=status.HTTP_302_FOUND)
|
return RedirectResponse(url="/", status_code=status.HTTP_302_FOUND)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/event/{event_id}")
|
@app.get("/event/{event_id}")
|
||||||
async def read_event(request: Request, event_id: int, session: SessionDep, user: UserDep):
|
async def read_event(
|
||||||
|
request: Request, event_id: int, session: SessionDep, user: UserDep
|
||||||
|
):
|
||||||
statement = select(Event).where(Event.id == event_id)
|
statement = select(Event).where(Event.id == event_id)
|
||||||
event = session.scalars(statement).one()
|
event = session.scalars(statement).one()
|
||||||
|
|
||||||
@@ -252,7 +302,12 @@ async def read_event(request: Request, event_id: int, session: SessionDep, user:
|
|||||||
return templates.TemplateResponse(
|
return templates.TemplateResponse(
|
||||||
request=request,
|
request=request,
|
||||||
name="event.html",
|
name="event.html",
|
||||||
context={"event": event, "households": households, "now": datetime.now(), "user": user},
|
context={
|
||||||
|
"event": event,
|
||||||
|
"households": households,
|
||||||
|
"now": datetime.now(),
|
||||||
|
"user": user,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -334,6 +389,7 @@ async def delete_team_registration(
|
|||||||
session.commit()
|
session.commit()
|
||||||
return RedirectResponse(url=f"/event/{event_id}", status_code=status.HTTP_302_FOUND)
|
return RedirectResponse(url=f"/event/{event_id}", status_code=status.HTTP_302_FOUND)
|
||||||
|
|
||||||
|
|
||||||
@app.get("/event/{event_id}/pdf")
|
@app.get("/event/{event_id}/pdf")
|
||||||
def get_event_attendance_pdf(event_id: int, session: SessionDep):
|
def get_event_attendance_pdf(event_id: int, session: SessionDep):
|
||||||
|
|
||||||
@@ -347,7 +403,5 @@ def get_event_attendance_pdf(event_id: int, session: SessionDep):
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Response(
|
return Response(
|
||||||
content=pdf_buffer.getvalue(),
|
content=pdf_buffer.getvalue(), media_type="application/pdf", headers=headers
|
||||||
media_type="application/pdf",
|
|
||||||
headers=headers
|
|
||||||
)
|
)
|
||||||
@@ -3,35 +3,35 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row justify-content-center mt-4">
|
<div class="row justify-content-center mt-4">
|
||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<h2>Neues Event erstellen</h2>
|
{% if edit_mode %}<h2>Event bearbeiten</h2>{% else %}<h2>Neues Event erstellen</h2>{% endif %}
|
||||||
<form method="post" action="/event/add">
|
{% if edit_mode %}<form method="post" action="/event/{{ event.id }}/edit">{% else %}<form method="post" action="/event/add">{% endif %}
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="eventName" class="form-label">Event Name</label>
|
<label for="eventName" class="form-label">Event Name</label>
|
||||||
<input type="text" class="form-control" id="eventName" name="eventName" required>
|
<input type="text" class="form-control" id="eventName" name="eventName" required {% if edit_mode %}value="{{ event.title }}"{% endif %}>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="eventTime" class="form-label">Datum und Uhrzeit</label>
|
<label for="eventTime" class="form-label">Datum und Uhrzeit</label>
|
||||||
<input type="datetime-local" class="form-control" id="eventTime" name="eventTime" required>
|
<input type="datetime-local" class="form-control" id="eventTime" name="eventTime" required {% if edit_mode %}value="{{ event.event_time }}"{% endif %}>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="registrationDeadline" class="form-label">Anmeldungs-Deadline</label>
|
<label for="registrationDeadline" class="form-label">Anmeldungs-Deadline</label>
|
||||||
<input type="datetime-local" class="form-control" id="registrationDeadline" name="registrationDeadline">
|
<input type="datetime-local" class="form-control" id="registrationDeadline" name="registrationDeadline" {% if edit_mode %}value="{{ event.registration_deadline }}"{% endif %}>
|
||||||
<small class="form-text text-muted">Leer lassen für Sonntag Abend vor dem Event</small>
|
<small class="form-text text-muted">Leer lassen für Sonntag Abend vor dem Event</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="recipeLink" class="form-label">Rezept-Link</label>
|
<label for="recipeLink" class="form-label">Rezept-Link</label>
|
||||||
<input type="text" class="form-control" id="recipeLink" name="recipeLink">
|
<input type="text" class="form-control" id="recipeLink" name="recipeLink" {% if edit_mode %}value="{{ event.recipe_link }}"{% endif %}>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
<label for="eventDescription" class="form-label">Beschreibung</label>
|
<label for="eventDescription" class="form-label">Beschreibung</label>
|
||||||
<textarea class="form-control" id="eventDescription" name="eventDescription" rows="3"></textarea>
|
<textarea class="form-control" id="eventDescription" name="eventDescription" rows="3" {% if edit_mode %}value="{{ event.description }}"{% endif %}></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="submit" class="btn btn-primary">Event erstellen</button>
|
<button type="submit" class="btn btn-primary">Event {% if edit_mode %}bearbeiten{% else %}erstellen{% endif %}</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
{% import "macros.j2" as macros %}
|
||||||
{% macro teamEntries(event, work_type) -%}
|
{% macro teamEntries(event, work_type) -%}
|
||||||
{% 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">
|
||||||
@@ -34,9 +35,24 @@
|
|||||||
<i class="bi bi-book"></i> Original Rezept ansehen
|
<i class="bi bi-book"></i> Original Rezept ansehen
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="/event/{{event.id}}/pdf" class="btn btn-secondary mb-2 w-100" target="_blank">
|
<div class="row w-100">
|
||||||
|
<div class="col-6 p-1">
|
||||||
|
<a href="/event/{{event.id}}/pdf" class="btn btn-secondary w-100" target="_blank">
|
||||||
<i class="bi bi-printer m-2"></i> Druckansicht
|
<i class="bi bi-printer m-2"></i> Druckansicht
|
||||||
</a>
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="col-6 p-1">
|
||||||
|
{% if user -%}
|
||||||
|
<a href="/event/{{event.id}}/edit" class="btn btn-secondary w-100" target="_blank">
|
||||||
|
<i class="bi bi-pen m-2"></i> Event bearbeiten
|
||||||
|
</a>
|
||||||
|
{% else -%}
|
||||||
|
<button type="button" class="btn btn-secondary w-100" data-bs-toggle="modal" data-bs-target="#loginInfo">
|
||||||
|
<i class="bi bi-pen m-2"></i> Event bearbeiten
|
||||||
|
</button>
|
||||||
|
{% endif -%}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{% if user and user.admin %}
|
{% if user and user.admin %}
|
||||||
<button type="button" class="btn btn-danger mb-2 w-100" data-bs-toggle="modal" data-bs-target="#deleteEvent">
|
<button type="button" class="btn btn-danger mb-2 w-100" data-bs-toggle="modal" data-bs-target="#deleteEvent">
|
||||||
Event Löschen
|
Event Löschen
|
||||||
@@ -286,4 +302,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{{ macros.login_info_modal() }}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
{% import "macros.j2" as macros %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row mt-4 mb-3">
|
<div class="row mt-4 mb-3">
|
||||||
<div class="col d-flex justify-content-between align-items-center">
|
<div class="col d-flex justify-content-between align-items-center">
|
||||||
@@ -8,7 +9,7 @@
|
|||||||
<i class="bi bi-plus-circle"></i> Neues Event erstellen
|
<i class="bi bi-plus-circle"></i> Neues Event erstellen
|
||||||
</a>
|
</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#exampleModal">
|
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#loginInfo">
|
||||||
<i class="bi bi-plus-circle"></i> Neues Event erstellen
|
<i class="bi bi-plus-circle"></i> Neues Event erstellen
|
||||||
</button>
|
</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -48,22 +49,5 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Modal -->
|
<!-- Modal -->
|
||||||
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
|
{{ macros.login_info_modal() }}
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h1 class="modal-title fs-5" id="exampleModalLabel">Bitte einloggen</h1>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
Einige Funktionen, wie das erstellen neuer Koch-Events, stehen nur zur Verfügung, wenn du in die Allmende-Cloud
|
|
||||||
eingeloggt bist. Gehe dazu auf <a href="https://cloud.allmende-gufi.de">cloud.allmende-gufi.de</a> und logge dich ein.
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Verstanden</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|||||||
19
src/meal_manager/templates/macros.j2
Normal file
19
src/meal_manager/templates/macros.j2
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{% macro login_info_modal() -%}
|
||||||
|
<div class="modal fade" id="loginInfo" tabindex="-1" aria-labelledby="loginInfoLabel" aria-hidden="true">
|
||||||
|
<div class="modal-dialog">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="modal-header">
|
||||||
|
<h1 class="modal-title fs-5" id="loginInfoLabel">Bitte einloggen</h1>
|
||||||
|
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
Einige Funktionen, wie das Erstellen und Bearbeiten von Koch-Events, stehen nur zur Verfügung, wenn du in die Allmende-Cloud
|
||||||
|
eingeloggt bist. Gehe dazu auf <a href="https://cloud.allmende-gufi.de">cloud.allmende-gufi.de</a> und logge dich ein.
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Verstanden</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{%- endmacro %}
|
||||||
Reference in New Issue
Block a user