From 805df373ee01e4332a496d9c1752822e1ba2c1a3 Mon Sep 17 00:00:00 2001 From: fulleni Date: Fri, 4 Jul 2025 12:04:33 +0100 Subject: [PATCH 1/4] feat: implement sortBy and sortOrder in data endpoint - Updates the GET /api/v1/data route to parse and validate `sortBy` and `sortOrder` query parameters. - Passes the sorting parameters to the underlying data repository's `readAllByQuery` method. - Throws a `BadRequestException` if `sortOrder` is provided with a value other than "asc" or "desc". --- routes/api/v1/data/index.dart | 40 ++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/routes/api/v1/data/index.dart b/routes/api/v1/data/index.dart index 2adf9c8..9384235 100644 --- a/routes/api/v1/data/index.dart +++ b/routes/api/v1/data/index.dart @@ -109,12 +109,34 @@ Future _handleGet( final queryParams = context.request.uri.queryParameters; final startAfterId = queryParams['startAfterId']; final limitParam = queryParams['limit']; + final sortBy = queryParams['sortBy']; + final sortOrderRaw = queryParams['sortOrder']?.toLowerCase(); final limit = limitParam != null ? int.tryParse(limitParam) : null; + SortOrder? sortOrder; + if (sortOrderRaw != null) { + if (sortOrderRaw == 'asc') { + sortOrder = SortOrder.asc; + } else if (sortOrderRaw == 'desc') { + sortOrder = SortOrder.desc; + } else { + throw const BadRequestException( + 'Invalid "sortOrder" parameter. Must be "asc" or "desc".', + ); + } + } + final specificQueryForClient = {}; final Set allowedKeys; final receivedKeys = queryParams.keys - .where((k) => k != 'model' && k != 'startAfterId' && k != 'limit') + .where( + (k) => + k != 'model' && + k != 'startAfterId' && + k != 'limit' && + k != 'sortBy' && + k != 'sortOrder', + ) .toSet(); switch (modelName) { @@ -207,6 +229,8 @@ Future _handleGet( userId: userIdForRepoCall, startAfterId: startAfterId, limit: limit, + sortBy: sortBy, + sortOrder: sortOrder, ); case 'category': final repo = context.read>(); @@ -215,6 +239,8 @@ Future _handleGet( userId: userIdForRepoCall, startAfterId: startAfterId, limit: limit, + sortBy: sortBy, + sortOrder: sortOrder, ); case 'source': final repo = context.read>(); @@ -223,6 +249,8 @@ Future _handleGet( userId: userIdForRepoCall, startAfterId: startAfterId, limit: limit, + sortBy: sortBy, + sortOrder: sortOrder, ); case 'country': final repo = context.read>(); @@ -231,6 +259,8 @@ Future _handleGet( userId: userIdForRepoCall, startAfterId: startAfterId, limit: limit, + sortBy: sortBy, + sortOrder: sortOrder, ); case 'user': final repo = context.read>(); @@ -239,6 +269,8 @@ Future _handleGet( userId: userIdForRepoCall, startAfterId: startAfterId, limit: limit, + sortBy: sortBy, + sortOrder: sortOrder, ); case 'user_app_settings': final repo = context.read>(); @@ -247,6 +279,8 @@ Future _handleGet( userId: userIdForRepoCall, startAfterId: startAfterId, limit: limit, + sortBy: sortBy, + sortOrder: sortOrder, ); case 'user_content_preferences': final repo = context.read>(); @@ -255,6 +289,8 @@ Future _handleGet( userId: userIdForRepoCall, startAfterId: startAfterId, limit: limit, + sortBy: sortBy, + sortOrder: sortOrder, ); case 'app_config': final repo = context.read>(); @@ -263,6 +299,8 @@ Future _handleGet( userId: userIdForRepoCall, startAfterId: startAfterId, limit: limit, + sortBy: sortBy, + sortOrder: sortOrder, ); default: throw OperationFailedException( From a2cdb381e5abbde9b84cdd0620083c7a9ba9389c Mon Sep 17 00:00:00 2001 From: fulleni Date: Fri, 4 Jul 2025 12:09:57 +0100 Subject: [PATCH 2/4] docs: update coverage badge and enhance key capabilities section --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f8ff478..dbfc1cf 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ht_api -![coverage: percentage](https://img.shields.io/badge/coverage-XX-green) +![coverage: percentage](https://img.shields.io/badge/coverage-90%2B-green) [![style: very good analysis](https://img.shields.io/badge/style-very_good_analysis-B22C89.svg)](https://pub.dev/packages/very_good_analysis) [![License: PolyForm Free Trial](https://img.shields.io/badge/License-PolyForm%20Free%20Trial-blue)](https://polyformproject.org/licenses/free-trial/1.0.0) @@ -32,6 +32,10 @@ management dashboard](https://github.com/headlines-toolkit/ht-dashboard). including headlines, categories, and sources, through a well-structured and protected API. +* 🔀 **Flexible Data Sorting:** Order lists of headlines, sources, and other + data by various fields in ascending or descending order, allowing for + dynamic and user-driven content presentation. + * 📊 **Dynamic Dashboard Summary:** Access real-time, aggregated metrics on key data points like total headlines, categories, and sources, providing an at-a-glance overview for administrative dashboards. From 47d3b9cf93d087a5d6b789ea988afde55693f958 Mon Sep 17 00:00:00 2001 From: fulleni Date: Fri, 4 Jul 2025 12:10:16 +0100 Subject: [PATCH 3/4] docs: update coverage badge to reflect current percentage --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dbfc1cf..f8b4b4f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ht_api -![coverage: percentage](https://img.shields.io/badge/coverage-90%2B-green) +![coverage: percentage](https://img.shields.io/badge/coverage-XX%2B-green) [![style: very good analysis](https://img.shields.io/badge/style-very_good_analysis-B22C89.svg)](https://pub.dev/packages/very_good_analysis) [![License: PolyForm Free Trial](https://img.shields.io/badge/License-PolyForm%20Free%20Trial-blue)](https://polyformproject.org/licenses/free-trial/1.0.0) From bf3592660c87011638db8ce3ceb286bc6e3036e1 Mon Sep 17 00:00:00 2001 From: fulleni Date: Fri, 4 Jul 2025 12:10:47 +0100 Subject: [PATCH 4/4] fix: correct coverage badge percentage formatting --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f8b4b4f..239e48d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ht_api -![coverage: percentage](https://img.shields.io/badge/coverage-XX%2B-green) +![coverage: percentage](https://img.shields.io/badge/coverage-xx-green) [![style: very good analysis](https://img.shields.io/badge/style-very_good_analysis-B22C89.svg)](https://pub.dev/packages/very_good_analysis) [![License: PolyForm Free Trial](https://img.shields.io/badge/License-PolyForm%20Free%20Trial-blue)](https://polyformproject.org/licenses/free-trial/1.0.0)