diff --git a/README.md b/README.md index f8ff478..239e48d 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-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) @@ -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. 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(