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-10 17:16:53 +08:00
await gFFI . abModel . reset ( clearCache: clearAbCache ) ;
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 ;
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
}