using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.Extensions.Options; using MongoDB.Driver; using SharpCompress.Common; using UGQDatabase.Models; using UGQDataAccess.Settings; using ServerCommon.UGQ; using System.Drawing; using UGQDataAccess.Repository.Models; using UGQDataAccess.Repository.Query; namespace UGQDataAccess.Repository; public enum AccountSortType { CreatedAtAsc, CreatedAtDesc, } public class AccountRepository : BaseRepository { private const string CollectionName = "Account"; public AccountRepository(IMongoClient mongoClient, IOptions settings) : base(mongoClient, settings.Value.DatabaseName, CollectionName) { } public async Task getByAccountId(string accountId) { var filter = Builders.Filter .Eq(x => x.AccountId, accountId); return await Collection.Find(filter).FirstOrDefaultAsync(); } public async Task get(string userGuid) { var filter = Builders.Filter .Eq(x => x.UserGuid, userGuid); return await Collection.Find(filter).FirstOrDefaultAsync(); } public async Task getAllCount() { var builder = Builders.Filter; var filter = builder.Empty; var result = await Collection.Find(filter).CountDocumentsAsync(); return result; } public async Task getOrInsertForGameUser(string userGuid) { var filter = Builders.Filter .Eq(x => x.UserGuid, userGuid); var update = Builders.Update .SetOnInsert(x => x.UserGuid, userGuid) .SetOnInsert(x => x.Nickname, "") .SetOnInsert(x => x.GradeType, UgqGradeType.Amature) .SetOnInsert(x => x.AdditionalSlotCount, 0) .SetOnInsert(x => x.UpdatedAt, DateTime.UtcNow) .SetOnInsert(x => x.CreatedAt, DateTime.UtcNow); var option = new FindOneAndUpdateOptions { IsUpsert = true, ReturnDocument = ReturnDocument.After }; return await Collection.FindOneAndUpdateAsync(filter, update, option); } public async Task getOrInsert(string userGuid, string nickname, string accountId) { var filter = Builders.Filter .Eq(x => x.UserGuid, userGuid); var update = Builders.Update .SetOnInsert(x => x.UserGuid, userGuid) .Set(x => x.Nickname, nickname) .Set(x => x.AccountId, accountId) .SetOnInsert(x => x.AdditionalSlotCount, 0) .SetOnInsert(x => x.GradeType, UgqGradeType.Amature) .SetOnInsert(x => x.UpdatedAt, DateTime.UtcNow) .SetOnInsert(x => x.CreatedAt, DateTime.UtcNow); var option = new FindOneAndUpdateOptions { IsUpsert = true, ReturnDocument = ReturnDocument.After }; return await Collection.FindOneAndUpdateAsync(filter, update, option); } public async Task modifyAccountGrade(string userGuid, UgqGradeType grade) { var filter = Builders.Filter .Eq(x => x.UserGuid, userGuid); var update = Builders.Update .Set(x => x.UpdatedAt, DateTime.UtcNow) .Set(x => x.GradeType, grade); var options = new FindOneAndUpdateOptions { ReturnDocument = ReturnDocument.After, }; return await Collection.FindOneAndUpdateAsync(filter, update, options); } public async Task promoteAccountGrade(string userGuid, UgqGradeType before, UgqGradeType after) { var filterBuilder = Builders.Filter; var filter = filterBuilder.Eq(x => x.UserGuid, userGuid) & (filterBuilder.Exists(x => x.GradeType, false) | filterBuilder.Eq(x => x.GradeType, before)); var update = Builders.Update .Set(x => x.UpdatedAt, DateTime.UtcNow) .Set(x => x.GradeType, after); var options = new FindOneAndUpdateOptions { ReturnDocument = ReturnDocument.After, }; return await Collection.FindOneAndUpdateAsync(filter, update, options); } public async Task addSlotCount(string userGuid, int? slotCountVersion, int addCount) { var filterBuilder = Builders.Filter; var filter = filterBuilder.Eq(x => x.UserGuid, userGuid) & filterBuilder.Eq(x => x.SlotCountVersion, slotCountVersion); var update = Builders.Update .Set(x => x.UpdatedAt, DateTime.UtcNow) .Inc(x => x.AdditionalSlotCount, addCount) .Inc(x => x.SlotCountVersion, 1); var options = new FindOneAndUpdateOptions { ReturnDocument = ReturnDocument.After, }; return await Collection.FindOneAndUpdateAsync(filter, update, options); } public async Task incCreatorPoint(string userGuid, int? creatorPointVersion, double amount) { var filterBuilder = Builders.Filter; var filter = filterBuilder.Eq(x => x.UserGuid, userGuid) & filterBuilder.Eq(x => x.CreatorPointVersion, creatorPointVersion); var update = Builders.Update .Set(x => x.UpdatedAt, DateTime.UtcNow) .Inc(x => x.CreatorPoint, amount) .Inc(x => x.CreatorPointVersion, 1); var options = new FindOneAndUpdateOptions { ReturnDocument = ReturnDocument.After, }; return await Collection.FindOneAndUpdateAsync(filter, update, options); } public async Task saveRefreshToken(string userGuid, string refreshToken, DateTime? refreshTokenExpryTime) { var filter = Builders.Filter .Eq(x => x.UserGuid, userGuid); var updateBuilder = Builders.Update; var update = Builders.Update .Set(x => x.UpdatedAt, DateTime.UtcNow) .Set(x => x.RefreshToken, refreshToken); if(refreshTokenExpryTime != null) update = updateBuilder.Combine(update, updateBuilder.Set(x => x.RefreshTokenExpiryTime, refreshTokenExpryTime)); var options = new FindOneAndUpdateOptions { ReturnDocument = ReturnDocument.After, }; var updated = await Collection.FindOneAndUpdateAsync(filter, update, options); return updated; } public async Task deleteRefreshToken(string userGuid) { var filter = Builders.Filter .Eq(x => x.UserGuid, userGuid); var updateBuilder = Builders.Update; var update = Builders.Update .Set(x => x.UpdatedAt, DateTime.UtcNow) .Set(x => x.RefreshToken, "") .Set(x => x.RefreshTokenExpiryTime, DateTime.Now); var options = new FindOneAndUpdateOptions { ReturnDocument = ReturnDocument.After, }; var updated = await Collection.FindOneAndUpdateAsync(filter, update, options); return updated; } public async Task getAccounts(int pageNumber, int pageSize, string? serachText, AccountSortType sortType) { pageNumber = pageNumber < 1 ? 1 : pageNumber; var filter = Builders.Filter.Empty; var sortBuilder = Builders.Sort; SortDefinition sort; switch (sortType) { case AccountSortType.CreatedAtDesc: sort = Builders.Sort.Descending("CreatedAt"); break; case AccountSortType.CreatedAtAsc: sort = Builders.Sort.Ascending("CreatedAt"); break; default: sort = Builders.Sort.Descending("CreatedAt"); break; } var countFacet = AggregateFacet.Create("count", new EmptyPipelineDefinition() .Count() ); var pagingFacet = AggregateFacet.Create("paging", new EmptyPipelineDefinition() .Sort(sort) .Skip((pageNumber - 1) * pageSize) .Limit(pageSize) ); var pipeline = AccountQuery.allAccountPipeline( filter, AccountQuery.AccountItemResultProjection) .Facet(countFacet, pagingFacet); var aggregation = await (await Collection.AggregateAsync(pipeline)).ToListAsync(); var count = aggregation.First() .Facets.First(x => x.Name == "count") .Output() ?.FirstOrDefault() ?.Count; var paging = aggregation.First() .Facets.First(x => x.Name == "paging") .Output(); int totalPages = 0; if (count != null) totalPages = (int)Math.Ceiling((double)count / pageSize); var result = await (await Collection.AggregateAsync(pipeline)).ToListAsync(); return new AllAccountQueryResult { PageNumber = pageNumber, PageSize = pageSize, TotalPages = totalPages, Items = paging.ToList(), }; } }