Skip to content

Commit 4ebc31a

Browse files
authored
Merge pull request #6 from headlines-toolkit/feature_dashboard_summary_api_handling
Feature dashboard summary api handling
2 parents 51670e9 + 7973922 commit 4ebc31a

File tree

4 files changed

+83
-0
lines changed

4 files changed

+83
-0
lines changed

lib/src/registry/model_registry.dart

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,27 @@ final modelRegistry = <String, ModelConfig<dynamic>>{
313313
type: RequiredPermissionType.adminOnly, // Only administrators can delete
314314
),
315315
),
316+
'dashboard_summary': ModelConfig<DashboardSummary>(
317+
fromJson: DashboardSummary.fromJson,
318+
getId: (summary) => summary.id,
319+
getOwnerId: null, // Not a user-owned resource
320+
// Permissions: Read-only for admins, all other actions unsupported.
321+
getCollectionPermission: const ModelActionPermission(
322+
type: RequiredPermissionType.unsupported,
323+
),
324+
getItemPermission: const ModelActionPermission(
325+
type: RequiredPermissionType.adminOnly,
326+
),
327+
postPermission: const ModelActionPermission(
328+
type: RequiredPermissionType.unsupported,
329+
),
330+
putPermission: const ModelActionPermission(
331+
type: RequiredPermissionType.unsupported,
332+
),
333+
deletePermission: const ModelActionPermission(
334+
type: RequiredPermissionType.unsupported,
335+
),
336+
),
316337
};
317338

318339
/// Type alias for the ModelRegistry map for easier provider usage.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import 'package:ht_data_repository/ht_data_repository.dart';
2+
import 'package:ht_shared/ht_shared.dart';
3+
4+
/// {@template dashboard_summary_service}
5+
/// A service responsible for calculating the dashboard summary data on demand.
6+
///
7+
/// This service aggregates data from various repositories to provide a
8+
/// real-time overview of key metrics in the system.
9+
/// {@endtemplate}
10+
class DashboardSummaryService {
11+
/// {@macro dashboard_summary_service}
12+
const DashboardSummaryService({
13+
required HtDataRepository<Headline> headlineRepository,
14+
required HtDataRepository<Category> categoryRepository,
15+
required HtDataRepository<Source> sourceRepository,
16+
}) : _headlineRepository = headlineRepository,
17+
_categoryRepository = categoryRepository,
18+
_sourceRepository = sourceRepository;
19+
20+
final HtDataRepository<Headline> _headlineRepository;
21+
final HtDataRepository<Category> _categoryRepository;
22+
final HtDataRepository<Source> _sourceRepository;
23+
24+
/// Calculates and returns the current dashboard summary.
25+
///
26+
/// This method fetches all items from the required repositories to count them
27+
/// and constructs a [DashboardSummary] object.
28+
Future<DashboardSummary> getSummary() async {
29+
// Use Future.wait to fetch all counts in parallel for efficiency.
30+
final results = await Future.wait([
31+
_headlineRepository.readAll(),
32+
_categoryRepository.readAll(),
33+
_sourceRepository.readAll(),
34+
]);
35+
36+
// The results are PaginatedResponse objects.
37+
final headlineResponse = results[0] as PaginatedResponse<Headline>;
38+
final categoryResponse = results[1] as PaginatedResponse<Category>;
39+
final sourceResponse = results[2] as PaginatedResponse<Source>;
40+
41+
return DashboardSummary(
42+
id: 'dashboard_summary', // Fixed ID for the singleton summary
43+
headlineCount: headlineResponse.items.length,
44+
categoryCount: categoryResponse.items.length,
45+
sourceCount: sourceResponse.items.length,
46+
);
47+
}
48+
}

routes/_middleware.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import 'package:ht_api/src/registry/model_registry.dart';
55
import 'package:ht_api/src/services/auth_service.dart';
66
import 'package:ht_api/src/services/auth_token_service.dart';
77
import 'package:ht_api/src/services/default_user_preference_limit_service.dart';
8+
import 'package:ht_api/src/services/dashboard_summary_service.dart';
89
import 'package:ht_api/src/services/jwt_auth_token_service.dart';
910
import 'package:ht_api/src/services/token_blacklist_service.dart';
1011
import 'package:ht_api/src/services/user_preference_limit_service.dart';
@@ -175,6 +176,14 @@ Handler middleware(Handler handler) {
175176
_createUserContentPreferencesRepository();
176177
final appConfigRepository = _createAppConfigRepository();
177178

179+
// Instantiate the new DashboardSummaryService with its dependencies
180+
final dashboardSummaryService = DashboardSummaryService(
181+
headlineRepository: headlineRepository,
182+
categoryRepository: categoryRepository,
183+
sourceRepository: sourceRepository,
184+
);
185+
print('[MiddlewareSetup] DashboardSummaryService instantiated.');
186+
178187
const uuid = Uuid();
179188

180189
// --- Auth Dependencies ---
@@ -308,6 +317,7 @@ Handler middleware(Handler handler) {
308317
.use(
309318
provider<AuthService>((_) => authService),
310319
) // Reads other services/repos
320+
.use(provider<DashboardSummaryService>((_) => dashboardSummaryService))
311321
// --- 5. RBAC Service Provider ---
312322
// PURPOSE: Provides the PermissionService for authorization checks.
313323
// ORDER: Must be provided before any middleware or handlers that use it

routes/api/v1/data/[id].dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import 'dart:io';
33
import 'package:dart_frog/dart_frog.dart';
44
import 'package:ht_api/src/rbac/permission_service.dart';
55
import 'package:ht_api/src/registry/model_registry.dart';
6+
import 'package:ht_api/src/services/dashboard_summary_service.dart';
67
import 'package:ht_api/src/services/user_preference_limit_service.dart'; // Import UserPreferenceLimitService
78
import 'package:ht_data_repository/ht_data_repository.dart';
89
import 'package:ht_shared/ht_shared.dart';
@@ -122,6 +123,9 @@ Future<Response> _handleGet(
122123
id: id,
123124
userId: userIdForRepoCall,
124125
); // userId should be null for AppConfig
126+
case 'dashboard_summary':
127+
final service = context.read<DashboardSummaryService>();
128+
item = await service.getSummary();
125129
default:
126130
// This case should ideally be caught by middleware, but added for safety
127131
// Throw an exception to be caught by the errorHandler

0 commit comments

Comments
 (0)