mnemo_cards/mnemo_cards_backend/lib/user/user_manager_drift.dart
Dmitry 77b4ce91b5
Some checks are pending
Backend CI / test (push) Waiting to run
Backend CI / build (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
postgress
2025-12-13 16:27:05 +03:00

160 lines
No EOL
4.5 KiB
Dart

import 'dart:developer';
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 '../main.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<int?, 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(int id) async {
final user = await _db.userDao.getUserById(id);
if (user == null) return null;
return await user.toUserModel();
}
DateTime? lastOnline(int 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.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: 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.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(lastOnline),
updatedAt: drift.Value(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(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);
}
// TODO: Implement remaining methods as needed
// updateUserSettings, addTestStatistics, editUser, deleteUser
}