Add pagination for past events
This commit is contained in:
@@ -12,7 +12,7 @@ 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 pydantic import BaseModel, BeforeValidator, validator
|
from pydantic import BaseModel, BeforeValidator, validator
|
||||||
from sqlalchemy import create_engine, select
|
from sqlalchemy import create_engine, func, select
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
|
|
||||||
from meal_manager.grist import sync_with_grist
|
from meal_manager.grist import sync_with_grist
|
||||||
@@ -93,12 +93,13 @@ 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))]
|
||||||
|
|
||||||
|
PAGE_SIZE = 18
|
||||||
|
|
||||||
|
|
||||||
@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"""
|
||||||
now = datetime.now()
|
now = datetime.now()
|
||||||
# TODO: Once we refactored to use SQLAlchemy directly, we can probably do a nicer filtering on the date alone
|
|
||||||
statement = (
|
statement = (
|
||||||
select(Event)
|
select(Event)
|
||||||
.order_by(Event.event_time)
|
.order_by(Event.event_time)
|
||||||
@@ -108,7 +109,14 @@ async def index(request: Request, session: SessionDep, user: UserDep):
|
|||||||
return templates.TemplateResponse(
|
return templates.TemplateResponse(
|
||||||
request=request,
|
request=request,
|
||||||
name="index.html",
|
name="index.html",
|
||||||
context={"events": events, "current_page": "home", "now": now, "user": user},
|
context={
|
||||||
|
"now": now,
|
||||||
|
"total_pages": 1,
|
||||||
|
"page": {
|
||||||
|
"page_number": 1,
|
||||||
|
"events": events,
|
||||||
|
},
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -117,20 +125,39 @@ async def robots_txt():
|
|||||||
return FileResponse("src/meal_manager/static/robots.txt", media_type="text/plain")
|
return FileResponse("src/meal_manager/static/robots.txt", media_type="text/plain")
|
||||||
|
|
||||||
|
|
||||||
@app.get("/past_events")
|
@app.get("/past_events/{page_number}")
|
||||||
async def past_events(request: Request, session: SessionDep):
|
async def past_events(request: Request, session: SessionDep, page_number: int):
|
||||||
|
|
||||||
now = datetime.now()
|
now = datetime.now()
|
||||||
# TODO: Once we refactored to use SQLAlchemy directly, we can probably do a nicer filtering on the date alone
|
|
||||||
statement = (
|
statement = (
|
||||||
select(Event)
|
select(Event)
|
||||||
.order_by(Event.event_time)
|
|
||||||
.where(Event.event_time < now - timedelta(days=1))
|
.where(Event.event_time < now - timedelta(days=1))
|
||||||
|
.order_by(Event.event_time.desc())
|
||||||
|
.offset((page_number - 1) * PAGE_SIZE)
|
||||||
|
.limit(PAGE_SIZE)
|
||||||
)
|
)
|
||||||
events = session.scalars(statement)
|
events = session.scalars(statement)
|
||||||
|
|
||||||
|
num_past_events = (
|
||||||
|
session.query(func.count(Event.id))
|
||||||
|
.where(Event.event_time < func.datetime("now", "-1 day"))
|
||||||
|
.scalar()
|
||||||
|
)
|
||||||
|
assert num_past_events is not None, "num_past_events should not be None"
|
||||||
|
total_pages = num_past_events // PAGE_SIZE + 1
|
||||||
|
|
||||||
return templates.TemplateResponse(
|
return templates.TemplateResponse(
|
||||||
request=request,
|
request=request,
|
||||||
name="index.html",
|
name="index.html",
|
||||||
context={"events": events, "current_page": "past", "now": now},
|
context={
|
||||||
|
"now": now,
|
||||||
|
"total_pages": total_pages,
|
||||||
|
"page": {
|
||||||
|
"page_number": page_number,
|
||||||
|
"events": events,
|
||||||
|
},
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
<a class="nav-link {% if current_page == 'home' %}active{% endif %}" {% if current_page == 'home' %}aria-current="page"{% endif %} href="/">Kommende</a>
|
<a class="nav-link {% if current_page == 'home' %}active{% endif %}" {% if current_page == 'home' %}aria-current="page"{% endif %} href="/">Kommende</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link {% if current_page == 'past' %}active{% endif %}" {% if current_page == 'past' %}aria-current="page"{% endif %} href="/past_events">Vergangene</a>
|
<a class="nav-link {% if current_page == 'past' %}active{% endif %}" {% if current_page == 'past' %}aria-current="page"{% endif %} href="/past_events/1/">Vergangene</a>
|
||||||
</li>
|
</li>
|
||||||
<!-- <li class="nav-item">-->
|
<!-- <li class="nav-item">-->
|
||||||
<!-- <a class="nav-link {% if current_page == 'preise' %}active{% endif %}" {% if current_page == 'preise' %}aria-current="page"{% endif %} href="/preise">Preise</a>-->
|
<!-- <a class="nav-link {% if current_page == 'preise' %}active{% endif %}" {% if current_page == 'preise' %}aria-current="page"{% endif %} href="/preise">Preise</a>-->
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4">
|
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-4">
|
||||||
|
|
||||||
|
|
||||||
{% for event in events %}
|
{% for event in page.events %}
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="card h-100 shadow-sm">
|
<div class="card h-100 shadow-sm">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@@ -49,13 +49,37 @@
|
|||||||
</div>
|
</div>
|
||||||
<p class="text-muted mb-3"><i class="bi bi-calendar"></i> {{ event.event_time.strftime('%A, %d.%m.%Y') }}</p>
|
<p class="text-muted mb-3"><i class="bi bi-calendar"></i> {{ event.event_time.strftime('%A, %d.%m.%Y') }}</p>
|
||||||
<p class="card-text">{{ event.description }}</p>
|
<p class="card-text">{{ event.description }}</p>
|
||||||
<a href="event/{{ event.id }}" class="btn btn-sm {% if event.registration_deadline > now %}btn-primary{% else %}btn-secondary{% endif %}">{% if event.registration_deadline > now %}Zur Anmeldung{% else %}Details ansehen{% endif %}</a>
|
<a href="/event/{{ event.id }}" class="btn btn-sm {% if event.registration_deadline > now %}btn-primary{% else %}btn-secondary{% endif %}">{% if event.registration_deadline > now %}Zur Anmeldung{% else %}Details ansehen{% endif %}</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% if total_pages and total_pages > 1 %}
|
||||||
|
<nav aria-label="Event pagination">
|
||||||
|
<ul class="pagination justify-content-center my-4">
|
||||||
|
<li class="page-item {% if page.page_number <= 1 %}disabled{% endif %}">
|
||||||
|
<a class="page-link" href="{% if page.page_number == 'home' %}/?page={{ page.page_number - 1 }}{% else %}/past_events/{{ page.page_number - 1 }}/{% endif %}" aria-label="Previous">
|
||||||
|
<span aria-hidden="true">«</span>
|
||||||
|
<span class="visually-hidden">Zurück</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% for p in range(1, total_pages + 1) %}
|
||||||
|
<li class="page-item {% if page.page_number == p %}active{% endif %}">
|
||||||
|
<a class="page-link" href="{% if page.page_number == 'home' %}/?page={{ p }}{% else %}/past_events/{{ p }}/{% endif %}">{{ p }}</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
<li class="page-item {% if page.page_number >= total_pages %}disabled{% endif %}">
|
||||||
|
<a class="page-link" href="{% if page.page_number == 'home' %}/?page={{ page.page_number + 1 }}{% else %}/past_events/{{ page.page_number + 1 }}/{% endif %}" aria-label="Next">
|
||||||
|
<span aria-hidden="true">»</span>
|
||||||
|
<span class="visually-hidden">Weiter</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<!-- Modal -->
|
<!-- Modal -->
|
||||||
{{ macros.login_info_modal() }}
|
{{ macros.login_info_modal() }}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
Reference in New Issue
Block a user