Skip to content

Commit 369b89c

Browse files
committed
feat: auth sim
1 parent 3bfcf3d commit 369b89c

File tree

10 files changed

+294
-45
lines changed

10 files changed

+294
-45
lines changed

auth/lib/auth_mixin.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export 'package:tekartik_firebase_auth/src/auth_mixin.dart'
55
FirebaseUserMixin,
66
FirebaseUserRecordDefaultMixin,
77
FirebaseUserCredentialMixin,
8-
FirebaseAuthCredentialMixin;
8+
FirebaseAuthCredentialMixin,
9+
FirebaseAuthLocalAdminDefaultMixin;
910

1011
export 'auth.dart';

auth/lib/src/auth_admin.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,13 @@ abstract class FirebaseAuthLocalAdmin implements FirebaseAuth {
1515

1616
/// User record stream
1717
Stream<UserRecord?> onUserRecord(String uid);
18+
19+
/// Do not sign in but get the credentials
20+
Future<UserCredential> getSignInWithEmailAndPasswordUserCredential({
21+
required String email,
22+
required String password,
23+
});
24+
25+
/// Do not sign in but get the credentials
26+
Future<UserCredential> getSignInAnonymouslyUserCredential();
1827
}

auth/lib/src/auth_mixin.dart

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'dart:async';
22

33
import 'package:tekartik_common_utils/stream/subject.dart';
44
import 'package:tekartik_firebase_auth/auth.dart';
5+
import 'package:tekartik_firebase_auth/auth_admin.dart';
56

67
/// Compat.
78
typedef AuthServiceMixin = FirebaseAuthServiceMixin;
@@ -181,3 +182,23 @@ mixin FirebaseUserRecordDefaultMixin implements UserRecord {
181182
String? get tokensValidAfterTime =>
182183
throw UnimplementedError('FirebaseUserRecord.tokensValidAfterTime');
183184
}
185+
186+
/// Mixin
187+
mixin FirebaseAuthLocalAdminDefaultMixin implements FirebaseAuthLocalAdmin {
188+
@override
189+
Future<UserCredential> getSignInAnonymouslyUserCredential() {
190+
throw UnimplementedError(
191+
'FirebaseAuthLocalAdmin.getSignInAnonymouslyUserCredential',
192+
);
193+
}
194+
195+
@override
196+
Future<UserCredential> getSignInWithEmailAndPasswordUserCredential({
197+
required String email,
198+
required String password,
199+
}) {
200+
throw UnimplementedError(
201+
'FirebaseAuthLocalAdmin.getSignInWithEmailAndPasswordUserCredential',
202+
);
203+
}
204+
}
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
export 'src/auth_sembast_impl.dart'
2-
show firebaseAuthCurrentUserRecord, DbCurrentUser;
2+
show
3+
firebaseAuthCurrentUserRecord,
4+
DbCurrentUser,
5+
firebaseAuthSembastInitDbBuilders;

auth_sembast/lib/src/auth_sembast_impl.dart

Lines changed: 104 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'package:path/path.dart' as p;
2+
import 'package:sembast/timestamp.dart';
23
import 'package:tekartik_app_cv_sembast/app_cv_sembast.dart';
34
import 'package:tekartik_common_utils/common_utils_import.dart';
45
import 'package:tekartik_firebase/firebase_mixin.dart';
@@ -16,8 +17,13 @@ abstract class FirebaseAuthServiceSembast implements FirebaseAuthService {
1617
}) => FirebaseAuthServiceSembastImpl(databaseFactory: databaseFactory);
1718
}
1819

19-
var _cvInitialized = () {
20+
/// Init db builders
21+
void firebaseAuthSembastInitDbBuilders() {
2022
cvAddConstructors([DbUser.new, DbCurrentUser.new]);
23+
}
24+
25+
var _cvInitialized = () {
26+
firebaseAuthSembastInitDbBuilders();
2127
}();
2228

2329
/// Firebase auth Sembast implementation
@@ -56,6 +62,9 @@ abstract class FirebaseAuthSembast
5662

5763
/// User record
5864
class DbUser extends DbStringRecordBase {
65+
/// Creation date
66+
final created = CvField<Timestamp>('created');
67+
5968
/// Name
6069
final name = CvField<String>('name');
6170

@@ -69,7 +78,7 @@ class DbUser extends DbStringRecordBase {
6978
final isAnonymous = CvField<bool>('isAnonymous');
7079

7180
@override
72-
CvFields get fields => [name, email, emailVerified, isAnonymous];
81+
CvFields get fields => [created, name, email, emailVerified, isAnonymous];
7382
}
7483

7584
/// User mode
@@ -92,7 +101,10 @@ var _userStore = cvStringStoreFactory.store<DbUser>('user');
92101

93102
/// Firebase auth Sembast implementation
94103
class FirebaseAuthSembastImpl
95-
with FirebaseAppProductMixin<FirebaseAuth>, FirebaseAuthMixin
104+
with
105+
FirebaseAppProductMixin<FirebaseAuth>,
106+
FirebaseAuthMixin,
107+
FirebaseAuthLocalAdminDefaultMixin
96108
implements FirebaseAuthSembast {
97109
StreamSubscription? _currentUserRecordSubscription;
98110
StreamSubscription? _currentUserSubscription;
@@ -211,11 +223,11 @@ class FirebaseAuthSembastImpl
211223
}) async {
212224
await _ready;
213225
var dbUser = await _database.transaction((txn) async {
214-
var dbUser = await _userStore.findFirst(
226+
var dbUser = await _txnGetSignInWithEmailAndPasswordUserCredential(
215227
txn,
216-
finder: Finder(filter: Filter.equals(dbUserModel.email.name, email)),
228+
email: email,
229+
password: password,
217230
);
218-
dbUser ??= await _userStore.add(txn, DbUser()..email.v = email);
219231
await firebaseAuthCurrentUserRecord.put(
220232
txn,
221233
DbCurrentUser()..uid.v = dbUser.id,
@@ -228,23 +240,70 @@ class FirebaseAuthSembastImpl
228240
return _FirebaseUserCredentialSembast(dbUser);
229241
}
230242

243+
Future<DbUser> _txnGetSignInWithEmailAndPasswordUserCredential(
244+
Transaction txn, {
245+
required String email,
246+
required String password,
247+
}) async {
248+
var dbUser = await _userStore.findFirst(
249+
txn,
250+
finder: Finder(filter: Filter.equals(dbUserModel.email.name, email)),
251+
);
252+
dbUser ??= await _userStore.add(txn, DbUser()..email.v = email);
253+
return dbUser;
254+
}
255+
231256
@override
232-
Future<UserCredential> signInAnonymously() async {
257+
Future<UserCredential> getSignInWithEmailAndPasswordUserCredential({
258+
required String email,
259+
required String password,
260+
}) async {
233261
await _ready;
234262
var dbUser = await _database.transaction((txn) async {
235-
/// Delete existing
236-
await _userStore.delete(
263+
var dbUser = await _txnGetSignInWithEmailAndPasswordUserCredential(
237264
txn,
238-
finder: Finder(
239-
filter: Filter.equals(dbUserModel.isAnonymous.name, true),
240-
),
241-
);
242-
var dbUser = await _userStore.add(
243-
txn,
244-
DbUser()
245-
..name.v = 'Anonymous'
246-
..isAnonymous.v = true,
265+
email: email,
266+
password: password,
247267
);
268+
return dbUser;
269+
});
270+
271+
return _FirebaseUserCredentialSembast(dbUser);
272+
}
273+
274+
Future<DbUser> _txnGetSignInAnonymouslyUserCredential(Transaction txn) async {
275+
/// Delete old existing
276+
await _userStore.delete(
277+
txn,
278+
finder: Finder(
279+
filter: Filter.and([
280+
Filter.equals(dbUserModel.isAnonymous.name, true),
281+
Filter.or([
282+
Filter.isNull(dbUserModel.created.name),
283+
Filter.lessThan(
284+
dbUserModel.created.name,
285+
Timestamp.now().addDuration(const Duration(days: 30)),
286+
),
287+
]),
288+
]),
289+
),
290+
);
291+
var created = Timestamp.now();
292+
var dbUser = await _userStore.add(
293+
txn,
294+
DbUser()
295+
..created.v = created
296+
..name.v = 'Anonymous ${created.toIso8601String()}'
297+
..isAnonymous.v = true,
298+
);
299+
return dbUser;
300+
}
301+
302+
@override
303+
Future<UserCredential> signInAnonymously() async {
304+
await _ready;
305+
var dbUser = await _database.transaction((txn) async {
306+
var dbUser = await _txnGetSignInAnonymouslyUserCredential(txn);
248307
await firebaseAuthCurrentUserRecord.put(
249308
txn,
250309
DbCurrentUser()..uid.v = dbUser.id,
@@ -257,11 +316,37 @@ class FirebaseAuthSembastImpl
257316
return _FirebaseUserCredentialSembast(dbUser);
258317
}
259318

319+
@override
320+
Future<UserCredential> getSignInAnonymouslyUserCredential() async {
321+
await _ready;
322+
var dbUser = await _database.transaction((txn) async {
323+
var dbUser = await _txnGetSignInAnonymouslyUserCredential(txn);
324+
return dbUser;
325+
});
326+
327+
return _FirebaseUserCredentialSembast(dbUser);
328+
}
329+
260330
@override
261331
Future<void> signOut() async {
262332
// ignore: unnecessary_statements
263333
await _ready;
264-
await firebaseAuthCurrentUserRecord.delete(_database);
334+
335+
await _database.transaction((txn) async {
336+
var currentUser = await firebaseAuthCurrentUserRecord.get(txn);
337+
if (currentUser != null) {
338+
var id = currentUser.uid.v!;
339+
340+
var record = _userStore.record(id);
341+
var dbUser = await record.get(txn);
342+
if (dbUser?.isAnonymous.v == true) {
343+
await record.delete(txn);
344+
}
345+
346+
await firebaseAuthCurrentUserRecord.delete(txn);
347+
}
348+
});
349+
265350
currentUserAdd(null);
266351
}
267352

0 commit comments

Comments
 (0)