import 'dart:convert'; import 'dart:io'; import 'package:shelf/shelf.dart'; import '../cors_headers.dart'; import '../firebase_auth.dart'; import '../question_source_preferences.dart'; import '../question_source_preferences_db.dart'; const String questionSourcesBasePath = '/v1/me/question-sources'; Handler questionSourceHandler({ required QuestionSourcePreferencesDb db, required FirebaseAuthVerifier auth, }) { return (Request request) async { if (request.method == 'OPTIONS') { return Response.ok( '', headers: apiCorsHeaders(methods: 'GET, PUT, OPTIONS'), ); } if (request.requestedUri.path != questionSourcesBasePath) { return _jsonResponse(404, {'error': 'Not found'}); } final String? firebaseUid = await auth.verifyBearerToken( request.headers['Authorization'] ?? request.headers['authorization'], ); if (firebaseUid == null) { return _jsonResponse(401, {'error': 'Unauthorized'}); } try { if (request.method == 'GET') { final List sources = await db.getResolved(firebaseUid); return _jsonResponse( 200, QuestionSourcePreferences.toApiPayload(sources: sources), ); } if (request.method == 'PUT') { final String body = await request.readAsString(); final Map json = jsonDecode(body) as Map; final List> stored = QuestionSourcePreferences.parsePutBody(json); final List saved = await db.save(firebaseUid, stored); return _jsonResponse( 200, QuestionSourcePreferences.toApiPayload( sources: saved, updatedAt: DateTime.now().toUtc(), ), ); } return _jsonResponse(405, {'error': 'Method not allowed'}); } on QuestionSourceValidationException catch (e) { return _jsonResponse(400, {'error': e.message}); } catch (e, st) { stderr.writeln('Question source handler error: $e\n$st'); return _jsonResponse(500, {'error': 'Internal error'}); } }; } Response _jsonResponse(int status, Map body) { return Response( status, body: jsonEncode(body), headers: { ...apiCorsHeaders(methods: 'GET, PUT, OPTIONS'), 'Content-Type': 'application/json', }, ); }