diff --git a/app/modules/services/services.py b/app/modules/services/services.py index 0a13c60..c3320fd 100644 --- a/app/modules/services/services.py +++ b/app/modules/services/services.py @@ -65,6 +65,13 @@ def get_category(db: Session, category_id: int) -> ServiceCategory | None: def list_catalogue_payload(db: Session, *, q: str = "", category_id: int | None = None, recurrence_type: str = "", engagement_type: str = "", page: int = 1, per_page: int = 20): + # Keep catalogue paging predictable and prevent invalid/very large requests. + page = max(1, int(page or 1)) + allowed_page_sizes = {20, 50, 100} + per_page = int(per_page or 20) + if per_page not in allowed_page_sizes: + per_page = 20 + query = select(ServiceCatalogue).where( ServiceCatalogue.is_active.is_(True) ).options( @@ -90,12 +97,18 @@ def list_catalogue_payload(db: Session, *, q: str = "", category_id: int | None query = query.where(ServiceCatalogue.engagement_type == normalize_engagement_type(engagement_type)) total = db.execute(select(func.count()).select_from(query.subquery())).scalar_one() + pages = max(1, (total + per_page - 1) // per_page) + page = min(page, pages) + rows = db.execute( query.order_by(ServiceCatalogue.sort_order.asc(), ServiceCatalogue.service_name.asc()) .offset((page - 1) * per_page) .limit(per_page) ).scalars().all() + start_item = ((page - 1) * per_page + 1) if total else 0 + end_item = min(page * per_page, total) + return { "rows": rows, "q": q, @@ -105,7 +118,9 @@ def list_catalogue_payload(db: Session, *, q: str = "", category_id: int | None "page": page, "per_page": per_page, "total": total, - "pages": max(1, (total + per_page - 1) // per_page), + "pages": pages, + "start_item": start_item, + "end_item": end_item, } diff --git a/app/modules/services/templates/services/catalogue_list.html b/app/modules/services/templates/services/catalogue_list.html index 829c924..7d9714a 100644 --- a/app/modules/services/templates/services/catalogue_list.html +++ b/app/modules/services/templates/services/catalogue_list.html @@ -41,7 +41,22 @@ {% for value, label in engagement_type_choices %}{% endfor %} -
+