using AuthApi.Models; using MongoDB.Bson; using MongoDB.Driver; using System.Text.RegularExpressions; namespace AuthApi.Services; public class UserService { private readonly IMongoCollection _col; public UserService(IConfiguration cfg) { var cs = cfg["MongoDB:ConnectionString"] ?? "mongodb://127.0.0.1:27017"; var dbName = cfg["MongoDB:DatabaseName"] ?? "GameDb"; var client = new MongoClient(cs); var db = client.GetDatabase(dbName); _col = db.GetCollection("Users"); var keys = Builders.IndexKeys.Ascending(u => u.Username); _col.Indexes.CreateOne(new CreateIndexModel(keys, new CreateIndexOptions { Unique = true })); var steamKeys = Builders.IndexKeys.Ascending(u => u.SteamId); _col.Indexes.CreateOne(new CreateIndexModel(steamKeys, new CreateIndexOptions { Unique = true, PartialFilterExpression = new BsonDocument("SteamId", new BsonDocument("$type", "string")) })); } public async Task GetByUsernameAsync(string username) => await _col.Find(u => u.Username == username).FirstOrDefaultAsync(); public async Task GetByIdAsync(string id) => await _col.Find(u => u.Id == id).FirstOrDefaultAsync(); public async Task GetByEmailAsync(string email) => await _col.Find(u => u.Email == email).FirstOrDefaultAsync(); public async Task> GetByLoginCandidatesAsync(string login) { var normalized = login.Trim(); var usernameMatch = await GetByUsernameAsync(normalized); if (usernameMatch is not null) return [usernameMatch]; var emailPattern = new BsonRegularExpression($"^{Regex.Escape(normalized)}$", "i"); return await _col.Find(Builders.Filter.Regex(u => u.Email, emailPattern)).ToListAsync(); } public async Task GetBySteamIdAsync(string steamId) => await _col.Find(u => u.SteamId == steamId).FirstOrDefaultAsync(); public Task CreateAsync(User user) => _col.InsertOneAsync(user); public Task UpdateAsync(User user) => _col.ReplaceOneAsync(u => u.Id == user.Id, user); public async Task TryLinkSteamAsync(string userId, string steamId, string refreshToken, DateTime refreshExpiry) { var filter = Builders.Filter.Eq(u => u.Id, userId) & (Builders.Filter.Eq(u => u.SteamId, null) | Builders.Filter.Eq(u => u.SteamId, steamId)); var update = Builders.Update .Set(u => u.SteamId, steamId) .Set(u => u.RefreshToken, refreshToken) .Set(u => u.RefreshTokenExpiry, refreshExpiry); var result = await _col.UpdateOneAsync(filter, update); return result.MatchedCount == 1; } public Task DeleteAsync(string id) => _col.DeleteOneAsync(u => u.Id == id); public Task> GetAllAsync() => _col.Find(FilterDefinition.Empty).ToListAsync(); }