Some checks are pending
Backend CI / test (push) Waiting to run
Backend CI / build (push) Blocked by required conditions
Deploy Admin Panel / Deploy Admin Panel (push) Waiting to run
Deploy Admin Panel / Admin Panel Verification (push) Blocked by required conditions
Deploy Mnemo Cards / Deploy Backend (push) Waiting to run
Deploy Mnemo Cards / Deploy Web App (push) Blocked by required conditions
Deploy Mnemo Cards / Final Verification (push) Blocked by required conditions
155 lines
No EOL
4.5 KiB
Dart
155 lines
No EOL
4.5 KiB
Dart
import 'package:drift_postgres/drift_postgres.dart';
|
|
import 'package:injectable/injectable.dart';
|
|
import 'package:drift/drift.dart' as drift;
|
|
import 'package:mnemo_cards_backend/database/database.dart';
|
|
import 'package:mnemo_cards_common_backend/mnemo_cards_common_backend.dart';
|
|
import 'package:mnemo_cards_common/mnemo_cards_common.dart';
|
|
|
|
import '../packs/free_packs_distributor.dart';
|
|
import '../statistics/session_tracker.dart';
|
|
import '../statistics/statistics_calculator.dart';
|
|
import '../statistics/achievement_manager.dart';
|
|
import 'secure.dart';
|
|
import 'user_drift_extension.dart';
|
|
|
|
Map<String?, DateTime> _onlineUsers = {};
|
|
|
|
@lazySingleton
|
|
class UserManager {
|
|
final AppDatabase _db;
|
|
final FreePacksDistributor _freePacksDistributor;
|
|
final SessionTracker _sessionTracker;
|
|
final StatisticsCalculator _statisticsCalculator;
|
|
final AchievementManager _achievementManager;
|
|
|
|
UserManager(
|
|
this._db,
|
|
this._freePacksDistributor,
|
|
this._sessionTracker,
|
|
this._statisticsCalculator,
|
|
this._achievementManager,
|
|
);
|
|
|
|
Future<UserModel?> fetchUser(String id) async {
|
|
final user = await _db.userDao.getUserById(id);
|
|
if (user == null) return null;
|
|
return await user.toUserModel();
|
|
}
|
|
|
|
DateTime? lastOnline(String id) => _onlineUsers[id];
|
|
|
|
Future<String> createOrGetAuthToken(UserModel user, String externalId) async {
|
|
if (user.id == null) {
|
|
throw Exception('Cant create token for empty id');
|
|
}
|
|
final now = DateTime.now();
|
|
final token = await _db.userDao.getTokenByUserId(user.id!);
|
|
if (token != null) {
|
|
if (token.expires.dateTime.isAfter(now)) {
|
|
return token.token;
|
|
}
|
|
await _db.userDao.deleteToken(token.id);
|
|
}
|
|
final userToken = Secure.token();
|
|
await _db.userDao.createToken(
|
|
TokensCompanion.insert(
|
|
token: userToken,
|
|
externalUserId: externalId,
|
|
userId: user.id!,
|
|
expires: PgDateTime(now.add(const Duration(days: 360))),
|
|
),
|
|
);
|
|
return userToken;
|
|
}
|
|
|
|
Future<UserModel?> getUserByToken(String authToken) async {
|
|
final token = await _db.userDao.getTokenByValue(authToken);
|
|
if (token == null) {
|
|
return null;
|
|
}
|
|
final now = DateTime.now();
|
|
if (token.expires.dateTime.isBefore(now)) {
|
|
await _db.userDao.deleteToken(token.id);
|
|
return null;
|
|
}
|
|
final user = await fetchUser(token.userId);
|
|
if (user != null) {
|
|
_onlineUsers[token.userId] = now;
|
|
if (_onlineUsers.length > 300) {
|
|
updateOnlineUsers();
|
|
}
|
|
}
|
|
return user;
|
|
}
|
|
|
|
Future<void> updateOnlineUsers() async {
|
|
if (_onlineUsers.isEmpty) {
|
|
return;
|
|
}
|
|
|
|
final userIds = _onlineUsers.keys.whereNotNull().toList();
|
|
|
|
for (final userId in userIds) {
|
|
final lastOnline = _onlineUsers[userId];
|
|
if (lastOnline != null) {
|
|
await _db.userDao.updateUserDataPartial(
|
|
UserDatasCompanion(
|
|
userId: drift.Value(userId),
|
|
lastTimeOnline: drift.Value(PgDateTime(lastOnline)),
|
|
updatedAt: drift.Value(PgDateTime(DateTime.now())),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
_onlineUsers.clear();
|
|
}
|
|
|
|
Future<(UserModel, String)> createOrGetUser({
|
|
required String externalId,
|
|
required String email,
|
|
String? name,
|
|
}) async {
|
|
// Check if user exists by externalId
|
|
final existingUser = await _db.userDao.getUserByExternalId(externalId);
|
|
if (existingUser != null) {
|
|
print('User found $name $email');
|
|
final userModel = await existingUser.toUserModel();
|
|
final token = await createOrGetAuthToken(userModel, externalId);
|
|
return (userModel, token);
|
|
}
|
|
|
|
print('Creating new user $name $email');
|
|
|
|
// Create new user
|
|
final userCompanion = UsersCompanion.insert(
|
|
externalUserId: externalId,
|
|
name: drift.Value(name),
|
|
email: drift.Value(email),
|
|
);
|
|
|
|
final userId = await _db.userDao.createUser(userCompanion);
|
|
|
|
// Create user data
|
|
await _db.userDao.createUserData(
|
|
UserDatasCompanion.insert(
|
|
userId: userId,
|
|
registrationDate: drift.Value(PgDateTime(DateTime.now())),
|
|
),
|
|
);
|
|
|
|
final user = await _db.userDao.getUserById(userId);
|
|
if (user == null) {
|
|
throw Exception('Failed to create user');
|
|
}
|
|
|
|
final userModel = await user.toUserModel();
|
|
final token = await createOrGetAuthToken(userModel, externalId);
|
|
|
|
// Give free packs to new user
|
|
await _freePacksDistributor.giveFreePacksToUser(userModel);
|
|
|
|
print('User $name $email created successfully');
|
|
return (userModel, token);
|
|
}
|
|
} |