| 
									
										
										
										
											2022-07-27 14:29:47 +08:00
										 |  |  | import 'dart:async'; | 
					
						
							|  |  |  | import 'dart:convert'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-10 17:16:53 +08:00
										 |  |  | import 'package:bot_toast/bot_toast.dart'; | 
					
						
							| 
									
										
										
										
											2023-06-22 10:04:16 +08:00
										 |  |  | import 'package:flutter/material.dart'; | 
					
						
							| 
									
										
										
										
											2023-01-06 19:26:19 +09:00
										 |  |  | import 'package:flutter_hbb/common/hbbs/hbbs.dart'; | 
					
						
							| 
									
										
										
										
											2022-07-27 14:29:47 +08:00
										 |  |  | import 'package:get/get.dart'; | 
					
						
							|  |  |  | import 'package:http/http.dart' as http; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-27 17:52:36 +08:00
										 |  |  | import '../common.dart'; | 
					
						
							| 
									
										
										
										
											2022-07-27 14:29:47 +08:00
										 |  |  | import 'model.dart'; | 
					
						
							| 
									
										
										
										
											2022-08-03 22:03:31 +08:00
										 |  |  | import 'platform_model.dart'; | 
					
						
							| 
									
										
										
										
											2022-07-27 14:29:47 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-01 10:19:59 +08:00
										 |  |  | bool refreshingUser = false; | 
					
						
							| 
									
										
										
										
											2023-06-22 23:19:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-09 19:41:50 +09:00
										 |  |  | class UserModel { | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |   final RxString userName = ''.obs; | 
					
						
							|  |  |  |   final RxBool isAdmin = false.obs; | 
					
						
							| 
									
										
										
										
											2023-08-03 16:48:14 +08:00
										 |  |  |   bool get isLogin => userName.isNotEmpty; | 
					
						
							| 
									
										
										
										
											2022-07-27 14:29:47 +08:00
										 |  |  |   WeakReference<FFI> parent; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |   UserModel(this.parent); | 
					
						
							| 
									
										
										
										
											2022-10-09 19:41:50 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  |   void refreshCurrentUser() async { | 
					
						
							| 
									
										
										
										
											2022-11-10 21:25:12 +08:00
										 |  |  |     final token = bind.mainGetLocalOption(key: 'access_token'); | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |     if (token == '') { | 
					
						
							| 
									
										
										
										
											2023-06-21 18:28:52 +08:00
										 |  |  |       await updateOtherModels(); | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-06-21 11:39:48 +08:00
										 |  |  |     _updateLocalUserInfo(); | 
					
						
							| 
									
										
										
										
											2022-10-09 19:41:50 +09:00
										 |  |  |     final url = await bind.mainGetApiServer(); | 
					
						
							|  |  |  |     final body = { | 
					
						
							|  |  |  |       'id': await bind.mainGetMyId(), | 
					
						
							|  |  |  |       'uuid': await bind.mainGetUuid() | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2023-07-01 10:19:59 +08:00
										 |  |  |     if (refreshingUser) return; | 
					
						
							| 
									
										
										
										
											2022-10-09 19:41:50 +09:00
										 |  |  |     try { | 
					
						
							| 
									
										
										
										
											2023-07-01 10:19:59 +08:00
										 |  |  |       refreshingUser = true; | 
					
						
							| 
									
										
										
										
											2022-10-09 19:41:50 +09:00
										 |  |  |       final response = await http.post(Uri.parse('$url/api/currentUser'), | 
					
						
							|  |  |  |           headers: { | 
					
						
							| 
									
										
										
										
											2022-10-22 22:19:14 +08:00
										 |  |  |             'Content-Type': 'application/json', | 
					
						
							|  |  |  |             'Authorization': 'Bearer $token' | 
					
						
							| 
									
										
										
										
											2022-10-09 19:41:50 +09:00
										 |  |  |           }, | 
					
						
							|  |  |  |           body: json.encode(body)); | 
					
						
							| 
									
										
										
										
											2023-07-01 10:19:59 +08:00
										 |  |  |       refreshingUser = false; | 
					
						
							| 
									
										
										
										
											2022-10-09 19:41:50 +09:00
										 |  |  |       final status = response.statusCode; | 
					
						
							|  |  |  |       if (status == 401 || status == 400) { | 
					
						
							| 
									
										
										
										
											2023-08-10 17:16:53 +08:00
										 |  |  |         reset(clearAbCache: status == 401); | 
					
						
							| 
									
										
										
										
											2022-10-09 19:41:50 +09:00
										 |  |  |         return; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2023-06-18 13:53:03 +08:00
										 |  |  |       final data = json.decode(utf8.decode(response.bodyBytes)); | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |       final error = data['error']; | 
					
						
							|  |  |  |       if (error != null) { | 
					
						
							|  |  |  |         throw error; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2023-01-06 19:26:19 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  |       final user = UserPayload.fromJson(data); | 
					
						
							| 
									
										
										
										
											2023-06-21 11:32:50 +08:00
										 |  |  |       _parseAndUpdateUser(user); | 
					
						
							| 
									
										
										
										
											2022-10-09 19:41:50 +09:00
										 |  |  |     } catch (e) { | 
					
						
							| 
									
										
										
										
											2023-06-22 08:25:29 +08:00
										 |  |  |       debugPrint('Failed to refreshCurrentUser: $e'); | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |     } finally { | 
					
						
							| 
									
										
										
										
											2023-07-01 10:19:59 +08:00
										 |  |  |       refreshingUser = false; | 
					
						
							| 
									
										
										
										
											2023-06-21 18:28:52 +08:00
										 |  |  |       await updateOtherModels(); | 
					
						
							| 
									
										
										
										
											2022-10-09 19:41:50 +09:00
										 |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-21 11:32:50 +08:00
										 |  |  |   static Map<String, dynamic>? getLocalUserInfo() { | 
					
						
							| 
									
										
										
										
											2023-06-22 08:25:29 +08:00
										 |  |  |     final userInfo = bind.mainGetLocalOption(key: 'user_info'); | 
					
						
							|  |  |  |     if (userInfo == '') { | 
					
						
							|  |  |  |       return null; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-06-21 11:32:50 +08:00
										 |  |  |     try { | 
					
						
							| 
									
										
										
										
											2023-06-22 08:25:29 +08:00
										 |  |  |       return json.decode(userInfo); | 
					
						
							| 
									
										
										
										
											2023-06-21 11:32:50 +08:00
										 |  |  |     } catch (e) { | 
					
						
							| 
									
										
										
										
											2023-06-22 22:33:54 +08:00
										 |  |  |       debugPrint('Failed to get local user info "$userInfo": $e'); | 
					
						
							| 
									
										
										
										
											2023-06-21 11:32:50 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |     return null; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   _updateLocalUserInfo() { | 
					
						
							|  |  |  |     final userInfo = getLocalUserInfo(); | 
					
						
							|  |  |  |     if (userInfo != null) { | 
					
						
							|  |  |  |       userName.value = userInfo['name']; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-10 17:16:53 +08:00
										 |  |  |   Future<void> reset({bool clearAbCache = false}) async { | 
					
						
							| 
									
										
										
										
											2022-10-22 22:19:14 +08:00
										 |  |  |     await bind.mainSetLocalOption(key: 'access_token', value: ''); | 
					
						
							| 
									
										
										
										
											2023-06-21 23:58:13 +08:00
										 |  |  |     await bind.mainSetLocalOption(key: 'user_info', value: ''); | 
					
						
							| 
									
										
										
										
											2023-08-13 14:46:04 +08:00
										 |  |  |     if (clearAbCache) await bind.mainClearAb(); | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |     await gFFI.groupModel.reset(); | 
					
						
							| 
									
										
										
										
											2022-10-22 22:19:14 +08:00
										 |  |  |     userName.value = ''; | 
					
						
							| 
									
										
										
										
											2022-10-09 19:41:50 +09:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-21 11:32:50 +08:00
										 |  |  |   _parseAndUpdateUser(UserPayload user) { | 
					
						
							| 
									
										
										
										
											2023-01-06 19:26:19 +09:00
										 |  |  |     userName.value = user.name; | 
					
						
							|  |  |  |     isAdmin.value = user.isAdmin; | 
					
						
							| 
									
										
										
										
											2023-08-20 17:14:52 +08:00
										 |  |  |     bind.mainSetLocalOption(key: 'user_info', value: jsonEncode(user)); | 
					
						
							| 
									
										
										
										
											2022-10-09 19:41:50 +09:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-07-27 14:29:47 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-21 18:28:52 +08:00
										 |  |  |   // update ab and group status
 | 
					
						
							|  |  |  |   static Future<void> updateOtherModels() async { | 
					
						
							| 
									
										
										
										
											2023-06-21 16:04:52 +08:00
										 |  |  |     await Future.wait([gFFI.abModel.pullAb(), gFFI.groupModel.pull()]); | 
					
						
							| 
									
										
										
										
											2022-07-27 14:29:47 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-08 21:37:34 +08:00
										 |  |  |   Future<void> logOut({String? apiServer}) async { | 
					
						
							| 
									
										
										
										
											2022-10-09 19:57:38 +09:00
										 |  |  |     final tag = gFFI.dialogManager.showLoading(translate('Waiting')); | 
					
						
							| 
									
										
										
										
											2022-12-16 23:18:30 +09:00
										 |  |  |     try { | 
					
						
							| 
									
										
										
										
											2023-08-08 21:37:34 +08:00
										 |  |  |       final url = apiServer ?? await bind.mainGetApiServer(); | 
					
						
							| 
									
										
										
										
											2023-01-28 22:02:42 +09:00
										 |  |  |       final authHeaders = getHttpHeaders(); | 
					
						
							|  |  |  |       authHeaders['Content-Type'] = "application/json"; | 
					
						
							| 
									
										
										
										
											2022-12-20 23:36:04 +09:00
										 |  |  |       await http | 
					
						
							|  |  |  |           .post(Uri.parse('$url/api/logout'), | 
					
						
							| 
									
										
										
										
											2023-01-28 22:02:42 +09:00
										 |  |  |               body: jsonEncode({ | 
					
						
							| 
									
										
										
										
											2022-12-20 23:36:04 +09:00
										 |  |  |                 'id': await bind.mainGetMyId(), | 
					
						
							|  |  |  |                 'uuid': await bind.mainGetUuid(), | 
					
						
							| 
									
										
										
										
											2023-01-28 22:02:42 +09:00
										 |  |  |               }), | 
					
						
							|  |  |  |               headers: authHeaders) | 
					
						
							| 
									
										
										
										
											2022-12-20 23:36:04 +09:00
										 |  |  |           .timeout(Duration(seconds: 2)); | 
					
						
							|  |  |  |     } catch (e) { | 
					
						
							| 
									
										
										
										
											2023-06-22 08:25:29 +08:00
										 |  |  |       debugPrint("request /api/logout failed: err=$e"); | 
					
						
							| 
									
										
										
										
											2022-12-16 23:18:30 +09:00
										 |  |  |     } finally { | 
					
						
							| 
									
										
										
										
											2023-08-10 17:16:53 +08:00
										 |  |  |       await reset(clearAbCache: true); | 
					
						
							| 
									
										
										
										
											2022-12-16 23:18:30 +09:00
										 |  |  |       gFFI.dialogManager.dismissByTag(tag); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-07-27 14:29:47 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-06 19:26:19 +09:00
										 |  |  |   /// throw [RequestException]
 | 
					
						
							|  |  |  |   Future<LoginResponse> login(LoginRequest loginRequest) async { | 
					
						
							| 
									
										
										
										
											2022-07-27 14:29:47 +08:00
										 |  |  |     final url = await bind.mainGetApiServer(); | 
					
						
							| 
									
										
										
										
											2023-01-06 19:26:19 +09:00
										 |  |  |     final resp = await http.post(Uri.parse('$url/api/login'), | 
					
						
							|  |  |  |         headers: {'Content-Type': 'application/json'}, | 
					
						
							|  |  |  |         body: jsonEncode(loginRequest.toJson())); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     final Map<String, dynamic> body; | 
					
						
							| 
									
										
										
										
											2022-07-27 14:29:47 +08:00
										 |  |  |     try { | 
					
						
							| 
									
										
										
										
											2023-06-18 13:53:03 +08:00
										 |  |  |       body = jsonDecode(utf8.decode(resp.bodyBytes)); | 
					
						
							| 
									
										
										
										
											2023-01-06 19:26:19 +09:00
										 |  |  |     } catch (e) { | 
					
						
							| 
									
										
										
										
											2023-06-22 08:25:29 +08:00
										 |  |  |       debugPrint("login: jsonDecode resp body failed: ${e.toString()}"); | 
					
						
							| 
									
										
										
										
											2023-08-10 17:16:53 +08:00
										 |  |  |       if (resp.statusCode != 200) { | 
					
						
							|  |  |  |         BotToast.showText( | 
					
						
							|  |  |  |             contentColor: Colors.red, text: 'HTTP ${resp.statusCode}'); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2023-01-06 19:26:19 +09:00
										 |  |  |       rethrow; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (resp.statusCode != 200) { | 
					
						
							|  |  |  |       throw RequestException(resp.statusCode, body['error'] ?? ''); | 
					
						
							| 
									
										
										
										
											2022-07-27 14:29:47 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-06-22 22:33:54 +08:00
										 |  |  |     if (body['error'] != null) { | 
					
						
							|  |  |  |       throw RequestException(0, body['error']); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-01-06 19:26:19 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-21 11:32:50 +08:00
										 |  |  |     return getLoginResponseFromAuthBody(body); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   LoginResponse getLoginResponseFromAuthBody(Map<String, dynamic> body) { | 
					
						
							| 
									
										
										
										
											2023-01-06 19:26:19 +09:00
										 |  |  |     final LoginResponse loginResponse; | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       loginResponse = LoginResponse.fromJson(body); | 
					
						
							|  |  |  |     } catch (e) { | 
					
						
							| 
									
										
										
										
											2023-06-22 08:25:29 +08:00
										 |  |  |       debugPrint("login: jsonDecode LoginResponse failed: ${e.toString()}"); | 
					
						
							| 
									
										
										
										
											2023-01-06 19:26:19 +09:00
										 |  |  |       rethrow; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (loginResponse.user != null) { | 
					
						
							| 
									
										
										
										
											2023-06-21 11:32:50 +08:00
										 |  |  |       _parseAndUpdateUser(loginResponse.user!); | 
					
						
							| 
									
										
										
										
											2023-01-06 19:26:19 +09:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return loginResponse; | 
					
						
							| 
									
										
										
										
											2022-07-27 14:29:47 +08:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-06-14 15:17:20 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-20 08:05:38 +08:00
										 |  |  |   static Future<List<dynamic>> queryOidcLoginOptions() async { | 
					
						
							| 
									
										
										
										
											2023-06-14 15:17:20 +08:00
										 |  |  |     try { | 
					
						
							| 
									
										
										
										
											2023-06-15 15:28:53 +08:00
										 |  |  |       final url = await bind.mainGetApiServer(); | 
					
						
							| 
									
										
										
										
											2023-06-29 06:25:17 +08:00
										 |  |  |       if (url.trim().isEmpty) return []; | 
					
						
							| 
									
										
										
										
											2023-08-07 19:08:29 +08:00
										 |  |  |       final resp = await http.get(Uri.parse('$url/api/login-options')); | 
					
						
							|  |  |  |       final List<String> ops = []; | 
					
						
							|  |  |  |       for (final item in jsonDecode(resp.body)) { | 
					
						
							|  |  |  |         ops.add(item as String); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       for (final item in ops) { | 
					
						
							|  |  |  |         if (item.startsWith('common-oidc/')) { | 
					
						
							|  |  |  |           return jsonDecode(item.substring('common-oidc/'.length)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       return ops | 
					
						
							|  |  |  |           .where((item) => item.startsWith('oidc/')) | 
					
						
							|  |  |  |           .map((item) => {'name': item.substring('oidc/'.length)}) | 
					
						
							|  |  |  |           .toList(); | 
					
						
							| 
									
										
										
										
											2023-06-14 15:17:20 +08:00
										 |  |  |     } catch (e) { | 
					
						
							| 
									
										
										
										
											2023-06-22 10:04:16 +08:00
										 |  |  |       debugPrint( | 
					
						
							| 
									
										
										
										
											2023-07-20 08:05:38 +08:00
										 |  |  |           "queryOidcLoginOptions: jsonDecode resp body failed: ${e.toString()}"); | 
					
						
							| 
									
										
										
										
											2023-06-14 15:17:20 +08:00
										 |  |  |       return []; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-07-27 14:29:47 +08:00
										 |  |  | } |