Files
fcs/lib/data/provider/auth_fb.dart

278 lines
8.4 KiB
Dart
Raw Normal View History

2020-08-27 22:32:40 +06:30
import 'dart:async';
2020-09-04 01:42:58 +06:30
import 'package:cloud_firestore/cloud_firestore.dart';
2020-10-07 02:33:06 +06:30
import 'package:fcs/domain/constants.dart';
import 'package:fcs/domain/entities/auth_result.dart' as fcs;
import 'package:fcs/domain/entities/auth_status.dart';
import 'package:fcs/domain/entities/setting.dart';
import 'package:fcs/domain/entities/user.dart';
import 'package:fcs/domain/exceiptions/signin_exception.dart';
import 'package:fcs/helpers/api_helper.dart';
2020-10-17 01:40:24 +06:30
import 'package:fcs/helpers/firebase_helper.dart';
2021-09-10 14:27:38 +06:30
import 'package:firebase_auth/firebase_auth.dart' as fb;
2020-09-13 21:49:39 +06:30
import 'package:logging/logging.dart';
2020-08-27 22:32:40 +06:30
class AuthFb {
2020-09-13 21:49:39 +06:30
final log = Logger('AuthFb');
2020-08-27 22:32:40 +06:30
static final AuthFb instance = AuthFb._();
AuthFb._();
2021-09-10 14:27:38 +06:30
late StreamController<User?> controller;
static final fb.FirebaseAuth _fb = fb.FirebaseAuth.instance;
static String _verificationId = '';
2020-08-27 22:32:40 +06:30
2020-09-04 01:42:58 +06:30
Future<fcs.AuthResult> sendSmsCodeToPhoneNumber(String phoneNumber) {
Completer<fcs.AuthResult> completer = Completer();
2020-09-13 21:49:39 +06:30
bool codeSentCompleted = false;
2020-08-27 22:32:40 +06:30
2021-09-10 14:27:38 +06:30
final fb.PhoneVerificationCompleted verificationCompleted =
(fb.AuthCredential credential) async {
fb.UserCredential _authResult;
2020-09-13 21:49:39 +06:30
try {
_authResult = await _fb.signInWithCredential(credential);
print("PhoneVerificationCompleted :$_authResult");
} catch (e) {
print("Exception:$e");
// throw e;
completer.completeError(SigninException(e.toString()));
return;
2020-09-04 01:42:58 +06:30
}
fcs.AuthResult auth =
fcs.AuthResult(authStatus: AuthStatus.AUTH_VERIFIED);
2020-08-30 21:26:37 +06:30
completer.complete(auth);
2020-08-27 22:32:40 +06:30
print(
2020-09-04 01:42:58 +06:30
'Inside _sendCodeToPhoneNumber: signInWithPhoneNumber auto succeeded: ${_authResult.user}');
2020-08-27 22:32:40 +06:30
};
2021-09-10 14:27:38 +06:30
final fb.PhoneVerificationFailed verificationFailed =
(fb.FirebaseAuthException authException) async {
2020-08-27 22:32:40 +06:30
print(
'Phone number verification failed. Code: ${authException.code}. Message: ${authException.message}');
2020-09-13 21:49:39 +06:30
completer.completeError(SigninException(
"Phone number verification failed:${authException.message}"));
2020-08-27 22:32:40 +06:30
};
2021-09-10 14:27:38 +06:30
final fb.PhoneCodeSent codeSent =
(String verificationId, [int? forceResendingToken]) async {
2020-08-27 22:32:40 +06:30
_verificationId = verificationId;
2020-09-13 21:49:39 +06:30
print("codeSent " + phoneNumber);
codeSentCompleted = true;
2021-09-11 16:56:20 +06:30
if (!completer.isCompleted)
completer.complete(fcs.AuthResult(authStatus: AuthStatus.SMS_SENT));
2020-08-27 22:32:40 +06:30
};
2021-09-10 14:27:38 +06:30
final fb.PhoneCodeAutoRetrievalTimeout codeAutoRetrievalTimeout =
2020-08-27 22:32:40 +06:30
(String verificationId) {
2020-09-13 21:49:39 +06:30
print("codeAutoRetrievalTimeout $verificationId ");
2020-08-27 22:32:40 +06:30
_verificationId = verificationId;
2020-09-13 21:49:39 +06:30
if (codeSentCompleted) {
2021-09-11 16:56:20 +06:30
if (!completer.isCompleted)
completer.complete(fcs.AuthResult(authStatus: AuthStatus.SMS_SENT));
2020-09-13 21:49:39 +06:30
} else {
completer.completeError(SigninException("SMS code failed"));
}
2020-08-27 22:32:40 +06:30
};
_fb.verifyPhoneNumber(
phoneNumber: phoneNumber,
2020-09-13 21:49:39 +06:30
timeout: const Duration(seconds: 0),
2020-08-27 22:32:40 +06:30
verificationCompleted: verificationCompleted,
verificationFailed: verificationFailed,
codeSent: codeSent,
codeAutoRetrievalTimeout: codeAutoRetrievalTimeout);
return completer.future;
}
2020-09-04 01:42:58 +06:30
Future<fcs.AuthResult> signInWithPhoneNumber(String smsCode) async {
2020-08-27 22:32:40 +06:30
try {
2021-09-10 14:27:38 +06:30
final fb.AuthCredential credential = fb.PhoneAuthProvider.credential(
verificationId: _verificationId, smsCode: smsCode);
2021-09-11 16:56:20 +06:30
await _fb.signInWithCredential(credential);
2020-09-22 03:52:48 +06:30
await _addUserToStream(refreshIdToken: true);
2020-08-27 22:32:40 +06:30
} on Exception catch (e) {
2020-09-04 01:42:58 +06:30
return Future.error(SigninException(e.toString()));
2020-08-27 22:32:40 +06:30
}
2020-09-04 01:42:58 +06:30
return Future.value(fcs.AuthResult(authStatus: AuthStatus.AUTH_VERIFIED));
2020-08-27 22:32:40 +06:30
}
2020-09-22 03:52:48 +06:30
Future<void> signout() async {
2021-09-10 14:27:38 +06:30
if (userListener != null) await userListener!.cancel();
2020-08-27 22:32:40 +06:30
return _fb.signOut();
}
2020-08-30 21:26:37 +06:30
2020-09-22 03:52:48 +06:30
Future<void> _addUserToStream({bool refreshIdToken = false}) async {
2021-09-10 14:27:38 +06:30
fb.User? firebaseUser = _fb.currentUser;
2020-09-04 01:42:58 +06:30
if (firebaseUser == null) return null;
2021-09-10 14:27:38 +06:30
Map<dynamic, dynamic>? claims =
await getClaims(refreshIdToken: refreshIdToken);
2020-09-13 21:49:39 +06:30
2020-10-17 01:40:24 +06:30
log.info("Claims:$claims");
2021-09-10 14:27:38 +06:30
if (claims == null) return;
2020-09-13 21:49:39 +06:30
2021-09-11 16:56:20 +06:30
String? cid = claims["cid"];
2021-09-10 14:27:38 +06:30
User? user;
2020-09-20 05:34:49 +06:30
if (cid != null && cid != "") {
2020-09-22 03:52:48 +06:30
user = await _getUserFromFirestore(cid);
2020-09-20 05:34:49 +06:30
}
if (user == null) {
2020-09-22 03:52:48 +06:30
controller.add(null);
return;
2020-09-20 05:34:49 +06:30
}
2020-09-11 16:14:36 +06:30
// add privileges
2021-09-11 16:56:20 +06:30
String? privileges = claims["pr"];
2020-09-11 16:14:36 +06:30
if (privileges != null && privileges != "") {
user.privileges = privileges.split(":").toList();
2020-10-15 03:06:13 +06:30
} else {
user.privileges = [];
2020-09-11 16:14:36 +06:30
}
2020-09-22 03:52:48 +06:30
controller.add(user);
2020-08-30 21:26:37 +06:30
}
2021-09-10 14:27:38 +06:30
Future<User?> _getUserFromFirestore(String userID) async {
DocumentSnapshot snap = await FirebaseFirestore.instance
2020-09-13 21:49:39 +06:30
.collection(user_collection)
2021-09-10 14:27:38 +06:30
.doc(userID)
2020-09-13 21:49:39 +06:30
.get();
if (snap.exists) {
2021-09-10 14:27:38 +06:30
User user = User.fromMap(snap.data() as Map<String, dynamic>, snap.id);
2020-09-13 21:49:39 +06:30
return user;
}
return null;
}
2020-09-04 01:42:58 +06:30
Future<bool> isLogin() async {
2021-09-10 14:27:38 +06:30
final fb.User? firebaseUser = _fb.currentUser;
2020-09-04 01:42:58 +06:30
return Future.value(firebaseUser != null);
2020-08-30 21:26:37 +06:30
}
2020-09-22 03:52:48 +06:30
Future<void> signup(String userName) async {
2020-08-30 21:26:37 +06:30
await requestAPI("/signup", "POST",
payload: {
2020-09-04 01:42:58 +06:30
'user_name': userName,
2020-08-30 21:26:37 +06:30
},
token: await getToken());
2020-09-22 03:52:48 +06:30
await _addUserToStream(refreshIdToken: true);
_startUserListener();
return;
2020-08-30 21:26:37 +06:30
}
2020-09-22 03:52:48 +06:30
Future<void> joinInvite(String userName) async {
2020-09-17 06:02:48 +06:30
await requestAPI("/join_invite", "POST",
payload: {
'user_name': userName,
},
token: await getToken());
// refresh token once signup
2020-09-22 03:52:48 +06:30
await _addUserToStream(refreshIdToken: true);
_startUserListener();
return;
2020-09-17 06:02:48 +06:30
}
2020-09-13 21:49:39 +06:30
Future<bool> hasInvite() async {
var invited =
await requestAPI("/check_invitation", "GET", token: await getToken());
return invited["invited"];
}
2020-10-11 02:17:23 +06:30
Future<void> updateProfileName(String newUserName) async {
2020-09-13 21:49:39 +06:30
return await requestAPI("/profile", "PUT",
payload: {"user_name": newUserName}, token: await getToken());
}
2020-10-11 02:17:23 +06:30
Future<void> updatePreferredCurrency(String currency) async {
return await requestAPI("/currency", "PUT",
payload: {"preferred_currency": currency}, token: await getToken());
}
2020-09-07 16:05:28 +06:30
Stream<Setting> settings() async* {
2021-09-10 14:27:38 +06:30
Stream<DocumentSnapshot> snapshot = FirebaseFirestore.instance
2020-09-07 16:05:28 +06:30
.collection(config_collection)
2021-09-10 14:27:38 +06:30
.doc(setting_doc_id)
2020-09-07 16:05:28 +06:30
.snapshots();
await for (var snap in snapshot) {
2021-09-10 14:27:38 +06:30
Setting setting = Setting.fromMap(snap.data() as Map<String, dynamic>);
2020-09-07 16:05:28 +06:30
yield setting;
}
}
2020-09-17 06:02:48 +06:30
2021-09-10 14:27:38 +06:30
Future<String?> _getCurrentUserID() async {
fb.User? firebaseUser = _fb.currentUser;
2020-09-22 03:52:48 +06:30
if (firebaseUser == null) return null;
2021-09-10 14:27:38 +06:30
Map? claims = await getClaims();
if (claims == null) return null;
2020-10-17 01:40:24 +06:30
String cid = claims["cid"];
2020-09-22 03:52:48 +06:30
return cid;
}
Future<void> _startUserListener() async {
2021-09-10 14:27:38 +06:30
if (userListener != null) userListener!.cancel();
String? _userID = await _getCurrentUserID();
2020-09-22 03:52:48 +06:30
if (_userID == null) {
return;
}
2021-09-10 14:27:38 +06:30
Stream<DocumentSnapshot> snapshot = FirebaseFirestore.instance
2020-09-17 06:02:48 +06:30
.collection(user_collection)
2021-09-10 14:27:38 +06:30
.doc(_userID)
2020-09-17 06:02:48 +06:30
.snapshots();
2020-09-22 03:52:48 +06:30
userListener = snapshot.listen((snap) async {
2021-09-10 14:27:38 +06:30
User user = User.fromMap(snap.data() as Map<String, dynamic>, snap.id);
2020-09-22 03:52:48 +06:30
2021-09-10 14:27:38 +06:30
fb.User? firebaseUser = _fb.currentUser;
2020-09-22 03:52:48 +06:30
if (firebaseUser == null) {
2021-09-10 14:27:38 +06:30
userListener?.cancel();
2020-09-22 03:52:48 +06:30
return;
}
2020-10-17 01:40:24 +06:30
try {
// get privilege from claim
2021-09-10 14:27:38 +06:30
fb.IdTokenResult idToken = await firebaseUser.getIdTokenResult(true);
2021-09-11 16:56:20 +06:30
String? privileges = idToken.claims?["pr"] ?? '';
2020-10-17 01:40:24 +06:30
if (privileges != null && privileges != "") {
user.privileges = privileges.split(":").toList();
}
controller.add(user);
} catch (e) {
controller.add(null);
2020-09-22 03:52:48 +06:30
}
});
}
2021-09-10 14:27:38 +06:30
StreamSubscription<DocumentSnapshot>? userListener;
Stream<User?> user() {
2020-09-22 03:52:48 +06:30
// ignore: close_sinks
2021-09-10 14:27:38 +06:30
StreamSubscription<fb.User?>? authListener;
2020-09-22 03:52:48 +06:30
Future<void> _start() async {
2021-09-10 14:27:38 +06:30
authListener = _fb.authStateChanges().listen((firebaseUser) {
2020-09-22 03:52:48 +06:30
if (firebaseUser == null) {
controller.add(null);
} else {
_addUserToStream(refreshIdToken: true);
_startUserListener();
}
});
}
void _stop() {
if (userListener != null) {
2021-09-10 14:27:38 +06:30
userListener!.cancel();
2020-09-22 03:52:48 +06:30
}
if (authListener != null) {
2021-09-10 14:27:38 +06:30
authListener!.cancel();
2020-09-22 03:52:48 +06:30
}
2020-09-17 06:02:48 +06:30
}
2020-09-22 03:52:48 +06:30
2021-09-11 16:56:20 +06:30
controller = StreamController<User?>(
2020-09-22 03:52:48 +06:30
onListen: _start, onPause: _stop, onResume: _start, onCancel: _stop);
return controller.stream;
2020-09-17 06:02:48 +06:30
}
2020-08-27 22:32:40 +06:30
}