feat: implement IPTV settings management with streaming and display preferences

This commit is contained in:
Michael committed 2025-12-08 21:40:46 +01:00
1 parent 62fc19598a
commit 63846c090a
8 files changed
+265 -10

No files matched your search

+62
View File
@@ -0,0 +1,62 @@
import 'dart:convert';
import 'package:shelf/shelf.dart';
import 'package:shelf_router/shelf_router.dart';
import '../database/database.dart';
import '../models/user.dart';
class SettingsHandler {
final AppDatabase db;
SettingsHandler(this.db);
Router get router {
final router = Router();
// GET /api/settings
router.get('/', (Request req) {
final user = req.context['user'] as User?;
if (user == null) {
return Response.forbidden(jsonEncode({'error': 'Authentication required'}));
}
final settingsJson = db.getUserSettings(user.id);
// If no settings exist, return empty object or default
return Response.ok(
settingsJson ?? '{}',
headers: {'content-type': 'application/json'},
);
});
// POST /api/settings
router.post('/', (Request req) async {
final user = req.context['user'] as User?;
if (user == null) {
return Response.forbidden(jsonEncode({'error': 'Authentication required'}));
}
try {
final body = await req.readAsString();
// Validate JSON
try {
jsonDecode(body);
} catch (e) {
return Response.badRequest(body: jsonEncode({'error': 'Invalid JSON'}));
}
db.updateUserSettings(user.id, body);
return Response.ok(
body,
headers: {'content-type': 'application/json'},
);
} catch (e) {
return Response.internalServerError(
body: jsonEncode({'error': 'Failed to save settings: $e'}),
);
}
});
return router;
}
}
+37
View File
@@ -68,6 +68,16 @@ class AppDatabase {
)
''');
// User Settings table
_db.execute('''
CREATE TABLE IF NOT EXISTS user_settings (
user_id TEXT PRIMARY KEY,
settings_json TEXT NOT NULL,
updated_at TEXT DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
)
''');
// Indexes
_db.execute('CREATE INDEX IF NOT EXISTS idx_sessions_token ON sessions(token)');
_db.execute('CREATE INDEX IF NOT EXISTS idx_sessions_expires ON sessions(expires_at)');
@@ -312,6 +322,33 @@ class AppDatabase {
_db.execute('DELETE FROM playlists WHERE id = ?', [playlistId]);
}
// ==================== User Settings ====================
/// Get user settings as JSON string
String? getUserSettings(String userId) {
final result = _db.select(
'SELECT settings_json FROM user_settings WHERE user_id = ?',
[userId],
);
if (result.isEmpty) return null;
return result.first['settings_json'] as String;
}
/// Update user settings
void updateUserSettings(String userId, String settingsJson) {
final now = DateTime.now().toIso8601String();
// UPSERT (Insert or Replace)
_db.execute('''
INSERT INTO user_settings (user_id, settings_json, updated_at)
VALUES (?, ?, ?)
ON CONFLICT(user_id) DO UPDATE SET
settings_json = excluded.settings_json,
updated_at = excluded.updated_at
''', [userId, settingsJson, now]);
}
/// Close database connection
void close() {
_db.dispose();
+10 -2
View File
@@ -11,7 +11,10 @@ import 'database/database.dart';
import 'models/user.dart';
import 'api/auth_handler.dart';
import 'api/users_handler.dart';
import 'api/auth_handler.dart';
import 'api/users_handler.dart';
import 'api/playlists_handler.dart';
import 'api/settings_handler.dart';
import 'middleware/auth_middleware.dart';
import 'middleware/security_middleware.dart';
import 'services/cleanup_service.dart';
@@ -35,6 +38,7 @@ void main(List<String> args) async {
final authHandler = AuthHandler(db);
final playlistsHandler = PlaylistsHandler(db);
final usersHandler = UsersHandler(db);
final settingsHandler = SettingsHandler(db);
// Setup router
final apiRouter = Router()
@@ -43,11 +47,15 @@ void main(List<String> args) async {
// Playlists endpoints (with auth middleware)
..mount('/api/playlists', Pipeline()
.addMiddleware(authMiddleware(db))
.addHandler(playlistsHandler.router.call),)
.addHandler(playlistsHandler.router.call))
// Users endpoints (with auth middleware)
..mount('/api/users', Pipeline()
.addMiddleware(authMiddleware(db))
.addHandler(usersHandler.router.call),);
.addHandler(usersHandler.router.call))
// Settings endpoints (with auth middleware)
..mount('/api/settings', Pipeline()
.addMiddleware(authMiddleware(db))
.addHandler(settingsHandler.router.call));
// Initialize Cleanup Service
final cleanupService = CleanupService();