Fix stale VPS URL and token expiration when switching servers

This commit is contained in:
ssbg04 committed 2026-07-26 14:10:54 +08:00
1 parent 9c97d2db8a
commit 7681aa4c1f
15 files changed
+39 -20

No files matched your search

+24 -1
View File
@@ -1,3 +1,6 @@
import 'package:dio/dio.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
class ApiConstants {
static const int port = 18484;
static const String vpsUrl = 'http://198.252.107.197:$port/api';
@@ -12,6 +15,26 @@ class ApiConstants {
static void setBaseUrl(String url) {
// Strip trailing slash then append /api
final clean = url.replaceAll(RegExp(r'/+$'), '');
_baseUrl = clean.endsWith('/api') ? clean : '$clean/api';
final newUrl = clean.endsWith('/api') ? clean : '$clean/api';
if (_baseUrl != newUrl) {
_baseUrl = newUrl;
// Clear stored JWT token whenever server URL changes to prevent "token expired" on different server
const FlutterSecureStorage().delete(key: 'jwt_token');
const FlutterSecureStorage().delete(key: 'remember_me');
}
}
/// Creates a Dio client that dynamically uses the active [baseUrl] on every request.
static Dio createDio([BaseOptions? options]) {
final dio = Dio(options ?? BaseOptions(baseUrl: _baseUrl));
dio.interceptors.add(
InterceptorsWrapper(
onRequest: (options, handler) {
options.baseUrl = _baseUrl;
return handler.next(options);
},
),
);
return dio;
}
}
@@ -5,7 +5,7 @@ import '../entities/dashboard_models.dart';
/// Repository for paginated user history (admin-only).
class ActivityRepository {
final Dio _dio = Dio(BaseOptions(baseUrl: ApiConstants.baseUrl));
final Dio _dio = ApiConstants.createDio();
final FlutterSecureStorage _storage = const FlutterSecureStorage();
Future<Options> _getAuthOptions() async {
@@ -35,7 +35,7 @@ class ArchivePage {
}
class ArchiveRepository {
final Dio _dio = Dio(BaseOptions(baseUrl: ApiConstants.baseUrl));
final Dio _dio = ApiConstants.createDio();
final FlutterSecureStorage _storage = const FlutterSecureStorage();
Future<Options> _getAuthOptions() async {
@@ -4,7 +4,7 @@ import '../../domain/entities/user_model.dart';
import '../../core/network/api_constants.dart';
class AuthRepository {
final Dio _dio = Dio(BaseOptions(baseUrl: ApiConstants.baseUrl));
final Dio _dio = ApiConstants.createDio();
final FlutterSecureStorage _storage = const FlutterSecureStorage();
static const _tokenKey = 'jwt_token';
@@ -4,9 +4,8 @@ import '../../core/network/api_constants.dart';
import 'dart:io';
class BackupRepository {
final Dio _dio = Dio(
final Dio _dio = ApiConstants.createDio(
BaseOptions(
baseUrl: ApiConstants.baseUrl,
connectTimeout: const Duration(seconds: 120),
receiveTimeout: const Duration(seconds: 120), // Zipping might take time
),
@@ -4,7 +4,7 @@ import '../../core/network/api_constants.dart';
import '../entities/dashboard_models.dart';
class DashboardRepository {
final Dio _dio = Dio(BaseOptions(baseUrl: ApiConstants.baseUrl));
final Dio _dio = ApiConstants.createDio();
final FlutterSecureStorage _storage = const FlutterSecureStorage();
Future<Options> _getAuthOptions() async {
@@ -195,7 +195,7 @@ class MissingRequirements {
}
class DocumentRepository {
final Dio _dio = Dio(BaseOptions(baseUrl: ApiConstants.baseUrl));
final Dio _dio = ApiConstants.createDio();
final FlutterSecureStorage _storage = const FlutterSecureStorage();
Future<Options> _getAuthOptions() async {
@@ -4,7 +4,7 @@ import '../../core/network/api_constants.dart';
import '../entities/notification_model.dart';
class NotificationRepository {
final Dio _dio = Dio(BaseOptions(baseUrl: ApiConstants.baseUrl));
final Dio _dio = ApiConstants.createDio();
final FlutterSecureStorage _storage = const FlutterSecureStorage();
Future<Options> _getAuthOptions() async {
@@ -5,9 +5,8 @@ import '../../core/network/api_constants.dart';
import '../entities/ocr_result_model.dart';
class OcrRepository {
final Dio _dio = Dio(
final Dio _dio = ApiConstants.createDio(
BaseOptions(
baseUrl: ApiConstants.baseUrl,
connectTimeout: const Duration(seconds: 60), // OCR takes time
receiveTimeout: const Duration(seconds: 60),
),
@@ -4,7 +4,7 @@ import '../../core/network/api_constants.dart';
import '../entities/report_models.dart';
class ReportRepository {
final Dio _dio = Dio(BaseOptions(baseUrl: ApiConstants.baseUrl));
final Dio _dio = ApiConstants.createDio();
final FlutterSecureStorage _storage = const FlutterSecureStorage();
Future<Options> _authOptions() async {
@@ -4,7 +4,7 @@ import '../../core/network/api_constants.dart';
import '../entities/setup_models.dart';
class SetupRepository {
final Dio _dio = Dio(BaseOptions(baseUrl: ApiConstants.baseUrl));
final Dio _dio = ApiConstants.createDio();
final FlutterSecureStorage _storage = const FlutterSecureStorage();
Future<Options> _getAuthOptions() async {
@@ -36,7 +36,7 @@ class StudentPage {
}
class StudentRepository {
final Dio _dio = Dio(BaseOptions(baseUrl: ApiConstants.baseUrl));
final Dio _dio = ApiConstants.createDio();
final FlutterSecureStorage _storage = const FlutterSecureStorage();
IO.Socket? _socket;
@@ -4,7 +4,7 @@ import '../../core/network/api_constants.dart';
import '../entities/system_user.dart';
class UserRepository {
final Dio _dio = Dio(BaseOptions(baseUrl: ApiConstants.baseUrl));
final Dio _dio = ApiConstants.createDio();
final FlutterSecureStorage _storage = const FlutterSecureStorage();
Future<Options> _getAuthOptions() async {
@@ -44,7 +44,7 @@ final academicYearsProvider = FutureProvider.autoDispose<List<AcademicYear>>((
) async {
final storage = const FlutterSecureStorage();
final token = await storage.read(key: 'jwt_token');
final dio = Dio(BaseOptions(baseUrl: ApiConstants.baseUrl));
final dio = ApiConstants.createDio();
try {
final response = await dio.get(
@@ -185,8 +185,7 @@ class _UploadOcrModalState extends ConsumerState<UploadOcrModal> {
try {
final storage = const FlutterSecureStorage();
final token = await storage.read(key: 'jwt_token');
final dio = Dio(BaseOptions(
baseUrl: ApiConstants.baseUrl,
final dio = ApiConstants.createDio(BaseOptions(
headers: {'Authorization': 'Bearer $token'},
));
@@ -396,8 +395,7 @@ class _UploadOcrModalState extends ConsumerState<UploadOcrModal> {
try {
final storage = const FlutterSecureStorage();
final token = await storage.read(key: 'jwt_token');
final dio = Dio(BaseOptions(
baseUrl: ApiConstants.baseUrl,
final dio = ApiConstants.createDio(BaseOptions(
headers: {'Authorization': 'Bearer $token'},
));