From 9d58e71e0699fffad95bc8358355d505070a2819 Mon Sep 17 00:00:00 2001 From: asesidaa <1061472754@qq.com> Date: Wed, 15 Feb 2023 02:14:19 +0800 Subject: [PATCH] Basically finish migration for server, implement play number rank, wait for testing --- Application/Application.csproj | 5 +- .../Extensions/XmlSerializationExtensions.cs | 14 ++ Application/Common/Helpers/TimeHelper.cs | 5 + Application/DependencyInjection.cs | 23 ++ Application/Dto/PlayNumRankDto.cs | 33 +++ .../Game/Card/CardRequestHandlerBase.cs | 3 - Application/Game/Card/Read/ReadCardQuery.cs | 3 +- .../Game/Card/Write/WriteCardBDataCommand.cs | 2 +- .../Game/Card/Write/WriteCardDetailCommand.cs | 2 +- Application/Game/Rank/GetEventRankQuery.cs | 43 ++++ .../Game/Rank/GetGlobalScoreRankQuery.cs | 43 ++++ .../Game/Rank/GetMonthlyScoreRankQuery.cs | 43 ++++ Application/Game/Rank/GetPlayNumRankQuery.cs | 68 ++++++ .../Game/Rank/GetTenpoScoreRankQuery.cs | 43 ++++ Application/Game/Rank/RankStatus.cs | 21 ++ Application/Game/Server/CertifyCommand.cs | 2 +- Application/Interfaces/ICardDbContext.cs | 2 + Application/Jobs/UpdatePlayNumRankJob.cs | 65 ++++++ Application/Mappers/PlayNumRankMapper.cs | 13 ++ Domain/Entities/PlayNumRank.cs | 19 ++ .../20230214162154_AddPlayNumRank.Designer.cs | 215 ++++++++++++++++++ .../20230214162154_AddPlayNumRank.cs | 39 ++++ .../Migrations/CardDbContextModelSnapshot.cs | 33 +++ Infrastructure/Persistence/CardDbContext.cs | 19 ++ .../Controllers/Game/RankingController.cs | 37 +-- .../Filters/ApiExceptionFilterAttributes.cs | 2 +- MainServer/Program.cs | 5 +- 27 files changed, 774 insertions(+), 28 deletions(-) create mode 100644 Application/Dto/PlayNumRankDto.cs create mode 100644 Application/Game/Rank/GetEventRankQuery.cs create mode 100644 Application/Game/Rank/GetGlobalScoreRankQuery.cs create mode 100644 Application/Game/Rank/GetMonthlyScoreRankQuery.cs create mode 100644 Application/Game/Rank/GetPlayNumRankQuery.cs create mode 100644 Application/Game/Rank/GetTenpoScoreRankQuery.cs create mode 100644 Application/Game/Rank/RankStatus.cs create mode 100644 Application/Jobs/UpdatePlayNumRankJob.cs create mode 100644 Application/Mappers/PlayNumRankMapper.cs create mode 100644 Domain/Entities/PlayNumRank.cs create mode 100644 Infrastructure/Migrations/20230214162154_AddPlayNumRank.Designer.cs create mode 100644 Infrastructure/Migrations/20230214162154_AddPlayNumRank.cs diff --git a/Application/Application.csproj b/Application/Application.csproj index 0322e9c..a8f1596 100644 --- a/Application/Application.csproj +++ b/Application/Application.csproj @@ -18,12 +18,9 @@ + - - - - diff --git a/Application/Common/Extensions/XmlSerializationExtensions.cs b/Application/Common/Extensions/XmlSerializationExtensions.cs index 7a39b30..ceada69 100644 --- a/Application/Common/Extensions/XmlSerializationExtensions.cs +++ b/Application/Common/Extensions/XmlSerializationExtensions.cs @@ -28,6 +28,20 @@ public static class XmlSerializationExtensions } return buffer.ToString(); } + + public static string SerializeCardData(this T source) where T : class + { + var buffer = new StringBuilder(); + using (var writer = new ChoXmlWriter(buffer).UseXmlSerialization()) + { + writer.Configuration.OmitXmlDeclaration = false; + writer.Configuration.DoNotEmitXmlNamespace = true; + writer.Configuration.IgnoreRootName = true; + writer.Write(source); + } + return buffer.ToString(); + } + public static string SerializeCardDataList(this IEnumerable source, string xpath) where T : class { var buffer = new StringBuilder(); diff --git a/Application/Common/Helpers/TimeHelper.cs b/Application/Common/Helpers/TimeHelper.cs index 0f81959..b5d31bf 100644 --- a/Application/Common/Helpers/TimeHelper.cs +++ b/Application/Common/Helpers/TimeHelper.cs @@ -6,4 +6,9 @@ public static class TimeHelper { return DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"); } + + public static string DateToString(DateTime time) + { + return time.ToString("yyyy-MM-dd"); + } } \ No newline at end of file diff --git a/Application/DependencyInjection.cs b/Application/DependencyInjection.cs index 6e630d0..242bb3b 100644 --- a/Application/DependencyInjection.cs +++ b/Application/DependencyInjection.cs @@ -2,8 +2,10 @@ using Application.Common.Behaviours; using Application.Game.Card; using Application.Interfaces; +using Application.Jobs; using MediatR; using Microsoft.Extensions.DependencyInjection; +using Quartz; namespace Application; @@ -15,6 +17,27 @@ public static class DependencyInjection services.AddScoped(); services.AddTransient(typeof(IPipelineBehavior<,>), typeof(UnhandledExceptionBehaviour<,>)); + services.AddQuartz(q => + { + q.UseMicrosoftDependencyInjectionJobFactory(); + var jobKey = new JobKey("UpdatePlayNumRankJob"); + q.AddJob(options => options.WithIdentity(jobKey)); + + q.AddTrigger(options => + { + options.ForJob(jobKey) + .WithIdentity("UpdatePlayNumRankJob-trigger") + .StartNow() + .WithSimpleSchedule(x => + { + x.WithIntervalInHours(24).RepeatForever(); + }); + }); + }); + services.AddQuartzHostedService(options => + { + options.WaitForJobsToComplete = true; + }); return services; } } \ No newline at end of file diff --git a/Application/Dto/PlayNumRankDto.cs b/Application/Dto/PlayNumRankDto.cs new file mode 100644 index 0000000..4170897 --- /dev/null +++ b/Application/Dto/PlayNumRankDto.cs @@ -0,0 +1,33 @@ +using System.Xml.Serialization; + +namespace Application.Dto; + +public class PlayNumRankDto +{ + [XmlAttribute(AttributeName = "id")] + public int Id { get; set; } + + [XmlElement("rank")] + public int Rank { get; set; } + + [XmlElement("rank2")] + public int Rank2 { get; set; } + + [XmlElement("prev_rank")] + public int PrevRank { get; set; } + + [XmlElement("prev_rank2")] + public int PrevRank2 { get; set; } + + [XmlElement("pcol1")] + public int Pcol1 { get; set; } + + [XmlElement("score_bi1")] + public int ScoreBi1 { get; set; } + + [XmlElement("title")] + public string Title { get; set; } = string.Empty; + + [XmlElement("artist")] + public string Artist { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/Application/Game/Card/CardRequestHandlerBase.cs b/Application/Game/Card/CardRequestHandlerBase.cs index b8f1bcb..c5f7912 100644 --- a/Application/Game/Card/CardRequestHandlerBase.cs +++ b/Application/Game/Card/CardRequestHandlerBase.cs @@ -1,9 +1,6 @@ using Application.Common.Models; using Application.Interfaces; using Domain.Config; -using MediatR; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; namespace Application.Game.Card; diff --git a/Application/Game/Card/Read/ReadCardQuery.cs b/Application/Game/Card/Read/ReadCardQuery.cs index 8a67286..661ab51 100644 --- a/Application/Game/Card/Read/ReadCardQuery.cs +++ b/Application/Game/Card/Read/ReadCardQuery.cs @@ -1,6 +1,7 @@ using Application.Common.Extensions; using Application.Common.Models; using Application.Interfaces; +using Application.Mappers; using Domain.Enums; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; @@ -26,7 +27,7 @@ public class ReadCardQueryHandler : CardRequestHandlerBase(new ServiceError($"Card id: {request.CardId} does not exist!", (int)CardReturnCode.CardNotRegistered)); } - var result = card.SerializeCardData("/root/card"); + var result = card.CardMainToCardDto().SerializeCardData("/root/card"); return new ServiceResult(result); } diff --git a/Application/Game/Card/Write/WriteCardBDataCommand.cs b/Application/Game/Card/Write/WriteCardBDataCommand.cs index 7005108..9d7f078 100644 --- a/Application/Game/Card/Write/WriteCardBDataCommand.cs +++ b/Application/Game/Card/Write/WriteCardBDataCommand.cs @@ -33,7 +33,7 @@ public class WriteCardBDataCommandHandler : CardRequestHandlerBase(); var data = dto.DtoToCardBDatum(); data.CardId = request.CardId; - CardDbContext.CardBdata.Upsert(data); + await CardDbContext.CardBdata.Upsert(data).RunAsync(cancellationToken); await CardDbContext.SaveChangesAsync(cancellationToken); diff --git a/Application/Game/Card/Write/WriteCardDetailCommand.cs b/Application/Game/Card/Write/WriteCardDetailCommand.cs index 6f90d08..f71ac4b 100644 --- a/Application/Game/Card/Write/WriteCardDetailCommand.cs +++ b/Application/Game/Card/Write/WriteCardDetailCommand.cs @@ -34,7 +34,7 @@ public class WriteCardDetailCommandHandler : CardRequestHandlerBase; + +public class GetEventRankQueryHandler : IRequestHandlerWrapper +{ + public Task> Handle(GetEventRankQuery request, CancellationToken cancellationToken) + { + var container = new EventRankContainer + { + Ranks = new List(), + Status = new RankStatus + { + TableName = "TenpoScoreRank", + StartDate = TimeHelper.DateToString(DateTime.Today), + EndDate = TimeHelper.DateToString(DateTime.Today), + Rows = 0, + Status = 0 + } + }; + + return Task.FromResult(new ServiceResult(container.SerializeCardData())); + } +} + +[XmlRoot("root")] +public class EventRankContainer +{ + [XmlArray(ElementName = "event_rank")] + [XmlArrayItem(ElementName = "record")] + // ReSharper disable once UnusedAutoPropertyAccessor.Global + public List Ranks { get; init; } = new(); + + [XmlElement("ranking_status")] + public RankStatus Status { get; set; } = new(); +} + diff --git a/Application/Game/Rank/GetGlobalScoreRankQuery.cs b/Application/Game/Rank/GetGlobalScoreRankQuery.cs new file mode 100644 index 0000000..2cc68a5 --- /dev/null +++ b/Application/Game/Rank/GetGlobalScoreRankQuery.cs @@ -0,0 +1,43 @@ +using System.Xml.Serialization; +using Application.Common.Extensions; +using Application.Common.Helpers; +using Application.Common.Models; +using Application.Interfaces; + +namespace Application.Game.Rank; + +public record GetGlobalScoreRankQuery() : IRequestWrapper; + +public class GetGlobalScoreRankQueryHandler : IRequestHandlerWrapper +{ + public Task> Handle(GetGlobalScoreRankQuery request, CancellationToken cancellationToken) + { + var container = new GlobalScoreRankContainer + { + Ranks = new List(), + Status = new RankStatus + { + TableName = "TenpoScoreRank", + StartDate = TimeHelper.DateToString(DateTime.Today), + EndDate = TimeHelper.DateToString(DateTime.Today), + Rows = 0, + Status = 0 + } + }; + + return Task.FromResult(new ServiceResult(container.SerializeCardData())); + } +} + +[XmlRoot("root")] +public class GlobalScoreRankContainer +{ + [XmlArray(ElementName = "score_rank")] + [XmlArrayItem(ElementName = "record")] + // ReSharper disable once UnusedAutoPropertyAccessor.Global + public List Ranks { get; init; } = new(); + + [XmlElement("ranking_status")] + public RankStatus Status { get; set; } = new(); +} + diff --git a/Application/Game/Rank/GetMonthlyScoreRankQuery.cs b/Application/Game/Rank/GetMonthlyScoreRankQuery.cs new file mode 100644 index 0000000..354d3bf --- /dev/null +++ b/Application/Game/Rank/GetMonthlyScoreRankQuery.cs @@ -0,0 +1,43 @@ +using System.Xml.Serialization; +using Application.Common.Extensions; +using Application.Common.Helpers; +using Application.Common.Models; +using Application.Interfaces; + +namespace Application.Game.Rank; + +public record GetMonthlyScoreRankQuery() : IRequestWrapper; + +public class GetMonthlyScoreRankQueryHandler : IRequestHandlerWrapper +{ + public Task> Handle(GetMonthlyScoreRankQuery request, CancellationToken cancellationToken) + { + var container = new MonthlyScoreRankContainer + { + Ranks = new List(), + Status = new RankStatus + { + TableName = "TenpoScoreRank", + StartDate = TimeHelper.DateToString(DateTime.Today), + EndDate = TimeHelper.DateToString(DateTime.Today), + Rows = 0, + Status = 0 + } + }; + + return Task.FromResult(new ServiceResult(container.SerializeCardData())); + } +} + +[XmlRoot("root")] +public class MonthlyScoreRankContainer +{ + [XmlArray(ElementName = "m_score_rank")] + [XmlArrayItem(ElementName = "record")] + // ReSharper disable once UnusedAutoPropertyAccessor.Global + public List Ranks { get; init; } = new(); + + [XmlElement("ranking_status")] + public RankStatus Status { get; set; } = new(); +} + diff --git a/Application/Game/Rank/GetPlayNumRankQuery.cs b/Application/Game/Rank/GetPlayNumRankQuery.cs new file mode 100644 index 0000000..36c6d88 --- /dev/null +++ b/Application/Game/Rank/GetPlayNumRankQuery.cs @@ -0,0 +1,68 @@ +using System.Diagnostics; +using System.Xml.Serialization; +using Application.Common.Extensions; +using Application.Common.Helpers; +using Application.Common.Models; +using Application.Dto; +using Application.Interfaces; +using Application.Mappers; +using Microsoft.EntityFrameworkCore; + +namespace Application.Game.Rank; + +public record GetPlayNumRankQuery(): IRequestWrapper; + +public class GetPlayNumRankQueryHandler : IRequestHandlerWrapper +{ + private readonly ICardDbContext cardDbContext; + + public GetPlayNumRankQueryHandler(ICardDbContext cardDbContext) + { + this.cardDbContext = cardDbContext; + } + + public async Task> Handle(GetPlayNumRankQuery request, CancellationToken cancellationToken) + { + var ranks = await cardDbContext.PlayNumRanks.OrderBy(rank => rank.Rank) + .Take(30).ToListAsync(cancellationToken: cancellationToken); + + var status = new RankStatus + { + TableName = "PlayNumRank", + StartDate = TimeHelper.DateToString(Process.GetCurrentProcess().StartTime.Date), + EndDate = TimeHelper.DateToString(DateTime.Today), + Rows = ranks.Count, + Status = 1 + }; + + var dtoList = ranks.Select((rank, i) => + { + var dto = rank.PlayNumRankToDto(); + dto.Id = i; + return dto; + }).ToList(); + + var container = new PlayNumRankContainer + { + Ranks = dtoList, + Status = status + }; + + var result = container.SerializeCardData(); + + return new ServiceResult(result); + } +} + +[XmlRoot("root")] +public class PlayNumRankContainer +{ + [XmlArray(ElementName = "play_num_rank")] + [XmlArrayItem(ElementName = "record")] + // ReSharper disable once UnusedAutoPropertyAccessor.Global + public List Ranks { get; init; } = new(); + + [XmlElement("ranking_status")] + public RankStatus Status { get; set; } = new(); +} + diff --git a/Application/Game/Rank/GetTenpoScoreRankQuery.cs b/Application/Game/Rank/GetTenpoScoreRankQuery.cs new file mode 100644 index 0000000..2988cd4 --- /dev/null +++ b/Application/Game/Rank/GetTenpoScoreRankQuery.cs @@ -0,0 +1,43 @@ +using System.Xml.Serialization; +using Application.Common.Extensions; +using Application.Common.Helpers; +using Application.Common.Models; +using Application.Dto; +using Application.Interfaces; + +namespace Application.Game.Rank; + +public record GetTenpoScoreRankQuery() : IRequestWrapper; + +public class GetTenpoScoreRankQueryHandler : IRequestHandlerWrapper +{ + public Task> Handle(GetTenpoScoreRankQuery request, CancellationToken cancellationToken) + { + var container = new TenpoScoreRankContainer + { + Ranks = new List(), + Status = new RankStatus + { + TableName = "TenpoScoreRank", + StartDate = TimeHelper.DateToString(DateTime.Today), + EndDate = TimeHelper.DateToString(DateTime.Today), + Rows = 0, + Status = 0 + } + }; + + return Task.FromResult(new ServiceResult(container.SerializeCardData())); + } +} + +[XmlRoot("root")] +public class TenpoScoreRankContainer +{ + [XmlArray(ElementName = "t_score_rank")] + [XmlArrayItem(ElementName = "record")] + // ReSharper disable once UnusedAutoPropertyAccessor.Global + public List Ranks { get; init; } = new(); + + [XmlElement("ranking_status")] + public RankStatus Status { get; set; } = new(); +} diff --git a/Application/Game/Rank/RankStatus.cs b/Application/Game/Rank/RankStatus.cs new file mode 100644 index 0000000..e66de8d --- /dev/null +++ b/Application/Game/Rank/RankStatus.cs @@ -0,0 +1,21 @@ +using System.Xml.Serialization; + +namespace Application.Game.Rank; + +public class RankStatus +{ + [XmlElement("table_name")] + public string TableName { get; set; } = string.Empty; + + [XmlElement("start_date")] + public string StartDate { get; set; } = string.Empty; + + [XmlElement("end_date")] + public string EndDate { get; set; } = string.Empty; + + [XmlElement("status")] + public int Status { get; set; } + + [XmlElement("rows")] + public int Rows { get; set; } +} \ No newline at end of file diff --git a/Application/Game/Server/CertifyCommand.cs b/Application/Game/Server/CertifyCommand.cs index 220a44e..e8f7fe5 100644 --- a/Application/Game/Server/CertifyCommand.cs +++ b/Application/Game/Server/CertifyCommand.cs @@ -57,7 +57,7 @@ public partial class CertifyCommandHandler : IRequestHandler CardPlayCounts { get; set; } + public DbSet PlayNumRanks { get; set; } + public Task SaveChangesAsync(CancellationToken cancellationToken); diff --git a/Application/Jobs/UpdatePlayNumRankJob.cs b/Application/Jobs/UpdatePlayNumRankJob.cs new file mode 100644 index 0000000..69d842e --- /dev/null +++ b/Application/Jobs/UpdatePlayNumRankJob.cs @@ -0,0 +1,65 @@ +using System.Diagnostics.CodeAnalysis; +using Application.Interfaces; +using Domain.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using Quartz; + +namespace Application.Jobs; + +public class UpdatePlayNumRankJob : IJob +{ + private readonly ILogger logger; + + private readonly ICardDbContext cardDbContext; + + private readonly IMusicDbContext musicDbContext; + + public UpdatePlayNumRankJob(ILogger logger, ICardDbContext cardDbContext, + IMusicDbContext musicDbContext) + { + this.logger = logger; + this.cardDbContext = cardDbContext; + this.musicDbContext = musicDbContext; + } + + public async Task Execute(IJobExecutionContext context) + { + logger.LogInformation("Start maintaining play num rank"); + await UpdatePlayNumRank(); + } + + + [SuppressMessage("ReSharper.DPA", "DPA0007: Large number of DB records", + Justification = "All music will be read")] + private async Task UpdatePlayNumRank() + { + var playRecords = await cardDbContext.CardDetails + .Where(detail => detail.Pcol1 == 20).ToListAsync(); + + var playNumRanks = new List(); + var musics = await musicDbContext.MusicUnlocks.ToListAsync(); + foreach (var music in musics) + { + var playCount = playRecords + .Where(detail => detail.Pcol2 == music.MusicId) + .Sum(detail => detail.ScoreUi1); + var playNumRank = new PlayNumRank + { + MusicId = (int)music.MusicId, + Artist = music.Artist ?? string.Empty, + Title = music.Title, + PlayCount = (int)playCount + }; + playNumRanks.Add(playNumRank); + } + playNumRanks = playNumRanks.OrderByDescending(rank => rank.PlayCount).ToList(); + var result = playNumRanks.Select((rank, i) => + { + rank.Rank = i+1; + return rank; + }).ToList(); + await cardDbContext.PlayNumRanks.UpsertRange(result).RunAsync(); + await cardDbContext.SaveChangesAsync(new CancellationToken()); + } +} \ No newline at end of file diff --git a/Application/Mappers/PlayNumRankMapper.cs b/Application/Mappers/PlayNumRankMapper.cs new file mode 100644 index 0000000..bfa3ca1 --- /dev/null +++ b/Application/Mappers/PlayNumRankMapper.cs @@ -0,0 +1,13 @@ +using Application.Dto; +using Domain.Entities; +using Riok.Mapperly.Abstractions; + +namespace Application.Mappers; + +[Mapper] +public static partial class PlayNumRankMapper +{ + [MapProperty(nameof(PlayNumRank.MusicId), nameof(PlayNumRankDto.Pcol1))] + [MapProperty(nameof(PlayNumRank.PlayCount), nameof(PlayNumRankDto.ScoreBi1))] + public static partial PlayNumRankDto PlayNumRankToDto(this PlayNumRank rank); +} \ No newline at end of file diff --git a/Domain/Entities/PlayNumRank.cs b/Domain/Entities/PlayNumRank.cs new file mode 100644 index 0000000..4c6802a --- /dev/null +++ b/Domain/Entities/PlayNumRank.cs @@ -0,0 +1,19 @@ +namespace Domain.Entities; + +public class PlayNumRank +{ + public int MusicId { get; set; } + + public int PlayCount { get; set; } + + public int Rank { get; set; } + + public int Rank2 { get; set; } + + public int PrevRank { get; set; } + public int PrevRank2 { get; set; } + + public string Title { get; set; } = string.Empty; + + public string Artist { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/Infrastructure/Migrations/20230214162154_AddPlayNumRank.Designer.cs b/Infrastructure/Migrations/20230214162154_AddPlayNumRank.Designer.cs new file mode 100644 index 0000000..49ed8b5 --- /dev/null +++ b/Infrastructure/Migrations/20230214162154_AddPlayNumRank.Designer.cs @@ -0,0 +1,215 @@ +// +using Infrastructure.Persistence; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace Infrastructure.Migrations +{ + [DbContext(typeof(CardDbContext))] + [Migration("20230214162154_AddPlayNumRank")] + partial class AddPlayNumRank + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "7.0.2"); + + modelBuilder.Entity("Domain.Entities.CardBdatum", b => + { + b.Property("CardId") + .HasColumnType("INTEGER") + .HasColumnName("card_id"); + + b.Property("Bdata") + .HasColumnType("TEXT") + .HasColumnName("bdata"); + + b.Property("BdataSize") + .HasColumnType("INTEGER") + .HasColumnName("bdata_size"); + + b.HasKey("CardId"); + + b.ToTable("card_bdata", (string)null); + }); + + modelBuilder.Entity("Domain.Entities.CardDetail", b => + { + b.Property("CardId") + .HasColumnType("INTEGER") + .HasColumnName("card_id"); + + b.Property("Pcol1") + .HasColumnType("INTEGER") + .HasColumnName("pcol1"); + + b.Property("Pcol2") + .HasColumnType("INTEGER") + .HasColumnName("pcol2"); + + b.Property("Pcol3") + .HasColumnType("INTEGER") + .HasColumnName("pcol3"); + + b.Property("Fcol1") + .HasColumnType("INTEGER") + .HasColumnName("fcol1"); + + b.Property("Fcol2") + .HasColumnType("INTEGER") + .HasColumnName("fcol2"); + + b.Property("Fcol3") + .HasColumnType("INTEGER") + .HasColumnName("fcol3"); + + b.Property("LastPlayTenpoId") + .HasColumnType("TEXT") + .HasColumnName("last_play_tenpo_id"); + + b.Property("LastPlayTime") + .HasColumnType("INTEGER") + .HasColumnName("last_play_time"); + + b.Property("ScoreBi1") + .HasColumnType("INTEGER") + .HasColumnName("score_bi1"); + + b.Property("ScoreI1") + .HasColumnType("INTEGER") + .HasColumnName("score_i1"); + + b.Property("ScoreUi1") + .HasColumnType("INTEGER") + .HasColumnName("score_ui1"); + + b.Property("ScoreUi2") + .HasColumnType("INTEGER") + .HasColumnName("score_ui2"); + + b.Property("ScoreUi3") + .HasColumnType("INTEGER") + .HasColumnName("score_ui3"); + + b.Property("ScoreUi4") + .HasColumnType("INTEGER") + .HasColumnName("score_ui4"); + + b.Property("ScoreUi5") + .HasColumnType("INTEGER") + .HasColumnName("score_ui5"); + + b.Property("ScoreUi6") + .HasColumnType("INTEGER") + .HasColumnName("score_ui6"); + + b.HasKey("CardId", "Pcol1", "Pcol2", "Pcol3"); + + b.ToTable("card_detail", (string)null); + }); + + modelBuilder.Entity("Domain.Entities.CardMain", b => + { + b.Property("CardId") + .HasColumnType("INTEGER") + .HasColumnName("card_id"); + + b.Property("AchieveStatus") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("achieve_status"); + + b.Property("Created") + .HasColumnType("TEXT") + .HasColumnName("created"); + + b.Property("Fcol1") + .HasColumnType("INTEGER") + .HasColumnName("fcol1"); + + b.Property("Fcol2") + .HasColumnType("INTEGER") + .HasColumnName("fcol2"); + + b.Property("Fcol3") + .HasColumnType("INTEGER") + .HasColumnName("fcol3"); + + b.Property("Modified") + .HasColumnType("TEXT") + .HasColumnName("modified"); + + b.Property("PlayerName") + .IsRequired() + .HasColumnType("TEXT") + .HasColumnName("player_name"); + + b.Property("ScoreI1") + .HasColumnType("INTEGER") + .HasColumnName("score_i1"); + + b.HasKey("CardId"); + + b.ToTable("card_main", (string)null); + }); + + modelBuilder.Entity("Domain.Entities.CardPlayCount", b => + { + b.Property("CardId") + .HasColumnType("INTEGER") + .HasColumnName("card_id"); + + b.Property("LastPlayedTime") + .HasColumnType("INTEGER") + .HasColumnName("last_played_time"); + + b.Property("PlayCount") + .HasColumnType("INTEGER") + .HasColumnName("play_count"); + + b.HasKey("CardId"); + + b.ToTable("CardPlayCount", (string)null); + }); + + modelBuilder.Entity("Domain.Entities.PlayNumRank", b => + { + b.Property("MusicId") + .HasColumnType("INTEGER"); + + b.Property("Artist") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("PlayCount") + .HasColumnType("INTEGER"); + + b.Property("PrevRank") + .HasColumnType("INTEGER"); + + b.Property("PrevRank2") + .HasColumnType("INTEGER"); + + b.Property("Rank") + .HasColumnType("INTEGER"); + + b.Property("Rank2") + .HasColumnType("INTEGER"); + + b.Property("Title") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("MusicId"); + + b.ToTable("PlayNumRank", (string)null); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Infrastructure/Migrations/20230214162154_AddPlayNumRank.cs b/Infrastructure/Migrations/20230214162154_AddPlayNumRank.cs new file mode 100644 index 0000000..c38033b --- /dev/null +++ b/Infrastructure/Migrations/20230214162154_AddPlayNumRank.cs @@ -0,0 +1,39 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Infrastructure.Migrations +{ + /// + public partial class AddPlayNumRank : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "PlayNumRank", + columns: table => new + { + MusicId = table.Column(type: "INTEGER", nullable: false), + PlayCount = table.Column(type: "INTEGER", nullable: false), + Rank = table.Column(type: "INTEGER", nullable: false), + Rank2 = table.Column(type: "INTEGER", nullable: false), + PrevRank = table.Column(type: "INTEGER", nullable: false), + PrevRank2 = table.Column(type: "INTEGER", nullable: false), + Title = table.Column(type: "TEXT", nullable: false), + Artist = table.Column(type: "TEXT", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_PlayNumRank", x => x.MusicId); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "PlayNumRank"); + } + } +} diff --git a/Infrastructure/Migrations/CardDbContextModelSnapshot.cs b/Infrastructure/Migrations/CardDbContextModelSnapshot.cs index ddc76ce..60b4594 100644 --- a/Infrastructure/Migrations/CardDbContextModelSnapshot.cs +++ b/Infrastructure/Migrations/CardDbContextModelSnapshot.cs @@ -173,6 +173,39 @@ namespace Infrastructure.Migrations b.ToTable("CardPlayCount", (string)null); }); + + modelBuilder.Entity("Domain.Entities.PlayNumRank", b => + { + b.Property("MusicId") + .HasColumnType("INTEGER"); + + b.Property("Artist") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("PlayCount") + .HasColumnType("INTEGER"); + + b.Property("PrevRank") + .HasColumnType("INTEGER"); + + b.Property("PrevRank2") + .HasColumnType("INTEGER"); + + b.Property("Rank") + .HasColumnType("INTEGER"); + + b.Property("Rank2") + .HasColumnType("INTEGER"); + + b.Property("Title") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("MusicId"); + + b.ToTable("PlayNumRank", (string)null); + }); #pragma warning restore 612, 618 } } diff --git a/Infrastructure/Persistence/CardDbContext.cs b/Infrastructure/Persistence/CardDbContext.cs index 542b43b..d57e821 100644 --- a/Infrastructure/Persistence/CardDbContext.cs +++ b/Infrastructure/Persistence/CardDbContext.cs @@ -25,6 +25,8 @@ public partial class CardDbContext : DbContext, ICardDbContext public virtual DbSet CardPlayCounts { get; set; } = null!; + public virtual DbSet PlayNumRanks { get; set; } = null!; + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { if (optionsBuilder.IsConfigured) @@ -111,6 +113,23 @@ public partial class CardDbContext : DbContext, ICardDbContext entity.Property(e => e.PlayCount).HasColumnName("play_count"); }); + modelBuilder.Entity(entity => + { + entity.HasKey(e => e.MusicId); + + entity.ToTable("PlayNumRank"); + + entity.Property(e => e.MusicId).ValueGeneratedNever(); + entity.Property(e => e.PlayCount); + entity.Property(e => e.Artist); + entity.Property(e => e.Title); + entity.Property(e => e.Rank); + entity.Property(e => e.Rank2); + entity.Property(e => e.PrevRank); + entity.Property(e => e.PrevRank2); + }); + + OnModelCreatingPartial(modelBuilder); } diff --git a/MainServer/Controllers/Game/RankingController.cs b/MainServer/Controllers/Game/RankingController.cs index 48bca02..d7b5c19 100644 --- a/MainServer/Controllers/Game/RankingController.cs +++ b/MainServer/Controllers/Game/RankingController.cs @@ -1,4 +1,6 @@ -using Domain.Enums; +using Application.Common.Models; +using Application.Game.Rank; +using Domain.Enums; using Microsoft.AspNetCore.Mvc; using Throw; @@ -14,21 +16,26 @@ public class RankingController : BaseController var type = (RankingCommandType)rankType; type.Throw().IfOutOfRange(); - switch (type) + var result = type switch { - case RankingCommandType.GlobalRank: - break; - case RankingCommandType.PlayNumRank: - break; - case RankingCommandType.EventRank: - break; - case RankingCommandType.MonthlyRank: - break; - case RankingCommandType.ShopRank: - break; - default: - throw new ArgumentOutOfRangeException(nameof(type), type, "Should not happen!"); + RankingCommandType.GlobalRank => await Mediator.Send(new GetGlobalScoreRankQuery()), + RankingCommandType.PlayNumRank => await Mediator.Send(new GetPlayNumRankQuery()), + RankingCommandType.EventRank => await Mediator.Send(new GetEventRankQuery()), + RankingCommandType.MonthlyRank => await Mediator.Send(new GetMonthlyScoreRankQuery()), + RankingCommandType.ShopRank => await Mediator.Send(new GetTenpoScoreRankQuery()), + _ => throw new ArgumentOutOfRangeException(nameof(type), type, "Should not happen!") + }; + + if (result.Succeeded) + { + var normalResult = "1\n" + + $"{result.Data}"; + return Ok(normalResult); } - return ""; + + // Here error is not null since Succeeded => Error is null; + var errorMessage = $"{result.Error!.Code}\n" + + $"{result.Error!.Message}"; + return Ok(errorMessage); } } \ No newline at end of file diff --git a/MainServer/Filters/ApiExceptionFilterAttributes.cs b/MainServer/Filters/ApiExceptionFilterAttributes.cs index 9dfe2bf..b8965bd 100644 --- a/MainServer/Filters/ApiExceptionFilterAttributes.cs +++ b/MainServer/Filters/ApiExceptionFilterAttributes.cs @@ -64,7 +64,7 @@ public class ApiExceptionFilterService : ExceptionFilterAttribute private void HandleArgumentOutOfRangeException(ExceptionContext context) { - logger.LogError(context.Exception, ""); + logger.LogError(context.Exception, "Get an argument out of bound exception"); var exception = context.Exception as ArgumentOutOfRangeException; Debug.Assert(exception != null, nameof(exception) + " != null"); diff --git a/MainServer/Program.cs b/MainServer/Program.cs index f5d26e6..e10870e 100644 --- a/MainServer/Program.cs +++ b/MainServer/Program.cs @@ -108,7 +108,10 @@ try contentTypeProvider.Mappings[".cmp"] = "text/plain"; contentTypeProvider.Mappings[".evt"] = "text/plain"; - app.UseStaticFiles(); + app.UseStaticFiles(new StaticFileOptions + { + ContentTypeProvider = contentTypeProvider + }); app.MapControllers();