From 5668aad9bcc2dba6773f58585aabcf42d5528e93 Mon Sep 17 00:00:00 2001
From: asesidaa <1061472754@qq.com>
Date: Wed, 20 Nov 2024 20:05:53 +0800
Subject: [PATCH] Stage changes
---
Application/Application.csproj | 1 +
Application/DependencyInjection.cs | 16 +++
Application/GlobalUsings.cs | 2 +
.../Handlers/Api/User/DeleteUserCommand.cs | 19 +++
.../Api/User/GetSongLeaderboardQuery.cs | 128 ++++++++++++++++++
Application/Handlers/Api/User/GetUserQuery.cs | 25 ++++
.../Handlers/Api/User/GetUsersQuery.cs | 58 ++++++++
.../Handlers/Game/GetInitialDataQuery.cs | 1 +
Application/Interfaces/IGameDataService.cs | 1 +
Application/Mappers/UserSettingMapper.cs | 33 +++++
.../Models/Game/CommonGetFolderResponse.cs | 4 +-
.../Game/CommonGetShopFolderResponse.cs | 4 +-
.../Game/CommonGetSongIntroductionResponse.cs | 4 +-
Application/Utils/PlaySettingConverter.cs | 43 ++++++
Domain/Models/Base/PaginatedResult.cs | 11 ++
Domain/Models/DanData.cs | 1 +
Domain/Models/{ => GameData}/Costume.cs | 2 +-
.../{ => GameData}/DonCosRewardEntry.cs | 2 +-
Domain/Models/{ => GameData}/DonCosRewards.cs | 2 +-
.../Models/{ => GameData}/EventFolderData.cs | 2 +-
Domain/Models/{ => GameData}/IVerupNo.cs | 2 +-
Domain/Models/{ => GameData}/MusicDetail.cs | 2 +-
.../Models/{ => GameData}/MusicInfoEntry.cs | 2 +-
Domain/Models/{ => GameData}/MusicInfos.cs | 2 +-
Domain/Models/{ => GameData}/MusicOrder.cs | 2 +-
.../Models/{ => GameData}/MusicOrderEntry.cs | 2 +-
Domain/Models/{ => GameData}/NeiroEntry.cs | 2 +-
Domain/Models/{ => GameData}/Neiros.cs | 2 +-
Domain/Models/{ => GameData}/QRCodeData.cs | 2 +-
.../Models/{ => GameData}/ShopFolderData.cs | 2 +-
Domain/Models/{ => GameData}/ShougouEntry.cs | 2 +-
Domain/Models/{ => GameData}/Shougous.cs | 2 +-
.../{ => GameData}/SongIntroductionData.cs | 2 +-
Domain/Models/{ => GameData}/WordList.cs | 2 +-
Domain/Models/{ => GameData}/WordListEntry.cs | 2 +-
Domain/Models/SongLeaderboard.cs | 29 +---
Domain/Models/SongLeaderboardEntry.cs | 27 ++++
Domain/Models/UserSetting.cs | 2 +-
Infrastructure/DependencyInjection.cs | 34 +++++
Infrastructure/Infrastructure.csproj | 2 +
Infrastructure/Services/GameDataService.cs | 1 +
Infrastructure/Services/JwtTokenService.cs | 35 +++++
.../Controllers/WeatherForecastController.cs | 32 -----
Server/Server.csproj | 4 +
Server/Server.http | 6 -
Server/WeatherForecast.cs | 12 --
Server/appsettings.Development.json | 8 --
47 files changed, 477 insertions(+), 104 deletions(-)
create mode 100644 Application/DependencyInjection.cs
create mode 100644 Application/Handlers/Api/User/DeleteUserCommand.cs
create mode 100644 Application/Handlers/Api/User/GetSongLeaderboardQuery.cs
create mode 100644 Application/Handlers/Api/User/GetUserQuery.cs
create mode 100644 Application/Handlers/Api/User/GetUsersQuery.cs
create mode 100644 Application/Mappers/UserSettingMapper.cs
create mode 100644 Application/Utils/PlaySettingConverter.cs
create mode 100644 Domain/Models/Base/PaginatedResult.cs
rename Domain/Models/{ => GameData}/Costume.cs (91%)
rename Domain/Models/{ => GameData}/DonCosRewardEntry.cs (86%)
rename Domain/Models/{ => GameData}/DonCosRewards.cs (83%)
rename Domain/Models/{ => GameData}/EventFolderData.cs (92%)
rename Domain/Models/{ => GameData}/IVerupNo.cs (64%)
rename Domain/Models/{ => GameData}/MusicDetail.cs (96%)
rename Domain/Models/{ => GameData}/MusicInfoEntry.cs (95%)
rename Domain/Models/{ => GameData}/MusicInfos.cs (83%)
rename Domain/Models/{ => GameData}/MusicOrder.cs (82%)
rename Domain/Models/{ => GameData}/MusicOrderEntry.cs (81%)
rename Domain/Models/{ => GameData}/NeiroEntry.cs (80%)
rename Domain/Models/{ => GameData}/Neiros.cs (82%)
rename Domain/Models/{ => GameData}/QRCodeData.cs (85%)
rename Domain/Models/{ => GameData}/ShopFolderData.cs (89%)
rename Domain/Models/{ => GameData}/ShougouEntry.cs (85%)
rename Domain/Models/{ => GameData}/Shougous.cs (82%)
rename Domain/Models/{ => GameData}/SongIntroductionData.cs (92%)
rename Domain/Models/{ => GameData}/WordList.cs (83%)
rename Domain/Models/{ => GameData}/WordListEntry.cs (94%)
create mode 100644 Domain/Models/SongLeaderboardEntry.cs
create mode 100644 Infrastructure/DependencyInjection.cs
create mode 100644 Infrastructure/Services/JwtTokenService.cs
delete mode 100644 Server/Controllers/WeatherForecastController.cs
delete mode 100644 Server/Server.http
delete mode 100644 Server/WeatherForecast.cs
delete mode 100644 Server/appsettings.Development.json
diff --git a/Application/Application.csproj b/Application/Application.csproj
index 56b3fb5..572c37c 100644
--- a/Application/Application.csproj
+++ b/Application/Application.csproj
@@ -10,6 +10,7 @@
+
diff --git a/Application/DependencyInjection.cs b/Application/DependencyInjection.cs
new file mode 100644
index 0000000..ed20bf8
--- /dev/null
+++ b/Application/DependencyInjection.cs
@@ -0,0 +1,16 @@
+using System.Reflection;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Application;
+
+public static class DependencyInjection
+{
+ public static IServiceCollection AddApplication(this IServiceCollection services)
+ {
+ services.AddMediatR(
+ configuration => configuration.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly()));
+
+
+ return services;
+ }
+}
\ No newline at end of file
diff --git a/Application/GlobalUsings.cs b/Application/GlobalUsings.cs
index 9356528..4f8b1b5 100644
--- a/Application/GlobalUsings.cs
+++ b/Application/GlobalUsings.cs
@@ -8,6 +8,8 @@ global using Domain.Common;
global using Domain.Entities;
global using Domain.Enums;
global using Domain.Models;
+global using Domain.Models.Base;
+global using Domain.Models.GameData;
global using MediatR;
global using Microsoft.EntityFrameworkCore;
global using Microsoft.Extensions.Logging;
diff --git a/Application/Handlers/Api/User/DeleteUserCommand.cs b/Application/Handlers/Api/User/DeleteUserCommand.cs
new file mode 100644
index 0000000..b48a7e7
--- /dev/null
+++ b/Application/Handlers/Api/User/DeleteUserCommand.cs
@@ -0,0 +1,19 @@
+namespace Application.Handlers.Api.User;
+
+public record DeleteUserCommand(uint Baid) : IRequest>;
+
+public class DeleteUserCommandHandler(ITaikoDbContext context) : IRequestHandler>
+{
+ public async Task> Handle(DeleteUserCommand request, CancellationToken cancellationToken)
+ {
+ var userDatum = await context.UserData.FindAsync([request.Baid], cancellationToken);
+ if (userDatum == null)
+ {
+ return ApiResult.Failed("User not found.");
+ }
+ context.UserData.Remove(userDatum);
+ await context.SaveChangesAsync(cancellationToken);
+
+ return ApiResult.Succeed(true);
+ }
+}
\ No newline at end of file
diff --git a/Application/Handlers/Api/User/GetSongLeaderboardQuery.cs b/Application/Handlers/Api/User/GetSongLeaderboardQuery.cs
new file mode 100644
index 0000000..cdce2f4
--- /dev/null
+++ b/Application/Handlers/Api/User/GetSongLeaderboardQuery.cs
@@ -0,0 +1,128 @@
+namespace Application.Handlers.Api.User;
+
+using LeaderBoard = PaginatedResult;
+public record GetSongLeaderboardQuery(uint SongId, Difficulty Difficulty, int Baid, int Page, int Limit) : IRequest>;
+
+public class GetSongLeaderboardQueryHandler(ITaikoDbContext context, ILogger logger)
+ : IRequestHandler>
+{
+ public async Task> Handle(GetSongLeaderboardQuery request, CancellationToken cancellationToken)
+ {
+ var totalScores = await context.SongBestData
+ .Where(x => x.SongId == request.SongId && x.Difficulty == request.Difficulty)
+ .CountAsync(cancellationToken);
+
+ var totalPages = (totalScores + request.Limit - 1) / request.Limit;
+
+ var scores = await context.SongBestData
+ .Where(x => x.SongId == request.SongId && x.Difficulty == request.Difficulty)
+ .Select(x => new
+ {
+ x.Baid,
+ x.BestScore,
+ x.BestRate,
+ x.BestCrown,
+ x.BestScoreRank,
+ Rank = context.SongBestData.Count(y => y.SongId == request.SongId && y.Difficulty == request.Difficulty && y.BestScore > x.BestScore) + 1
+ })
+ .OrderByDescending(x => x.BestScore)
+ .ThenByDescending(x => x.BestRate)
+ .ThenByDescending(x => x.BestCrown)
+ .Skip((request.Page - 1) * request.Limit)
+ .Take(request.Limit)
+ .ToListAsync(cancellationToken);
+
+ var userIds = scores.Select(x => x.Baid).Distinct().ToList();
+ var users = await context.UserData
+ .Where(x => userIds.Contains(x.Baid))
+ .ToDictionaryAsync(x => x.Baid, cancellationToken);
+
+ var leaderboard = scores.Select(score =>
+ {
+ var user = users.GetValueOrDefault(score.Baid);
+ return new SongLeaderboardEntry
+ {
+ Rank = score.Rank,
+ Baid = score.Baid,
+ UserName = user?.MyDonName,
+ BestScore = score.BestScore,
+ BestRate = score.BestRate,
+ BestCrown = score.BestCrown,
+ BestScoreRank = score.BestScoreRank
+ };
+ }).ToList();
+
+ var userLeaderboardEntry = context.SongBestData
+ .Where(x => x.SongId == request.SongId && x.Difficulty == request.Difficulty && x.Baid == request.Baid)
+ .Select(x => new SongLeaderboardEntry
+ {
+ Baid = x.Baid,
+ BestScore = x.BestScore,
+ BestRate = x.BestRate,
+ BestCrown = x.BestCrown,
+ BestScoreRank = x.BestScoreRank,
+ Rank = context.SongBestData.Count(y => y.SongId == request.SongId && y.Difficulty == request.Difficulty && y.BestScore > x.BestScore) + 1
+ })
+ .FirstOrDefault();
+ /*foreach (var score in scores)
+ {
+ var user = await context.UserData
+ .Where(x => x.Baid == score.Baid)
+ .FirstOrDefaultAsync(cancellationToken);
+
+ var rank = await context.SongBestData
+ .Where(x => x.SongId == request.SongId && x.Difficulty == request.Difficulty && x.BestScore > score.BestScore)
+ .CountAsync(cancellationToken);
+
+ leaderboard.Add(new SongLeaderboardEntry
+ {
+ Rank = rank + 1,
+ Baid = score.Baid,
+ UserName = user?.MyDonName,
+ BestScore = score.BestScore,
+ BestRate = score.BestRate,
+ BestCrown = score.BestCrown,
+ BestScoreRank = score.BestScoreRank
+ });
+ }*/
+
+ /*SongLeaderboardEntry? userBestScore = null;
+ if (request.Baid != 0)
+ {
+ var score = await context.SongBestData
+ .Where(x => x.SongId == request.SongId && x.Difficulty == request.Difficulty && x.Baid == request.Baid)
+ .FirstOrDefaultAsync(cancellationToken);
+
+ if (score != null)
+ {
+ var user = await context.UserData
+ .Where(x => x.Baid == request.Baid)
+ .FirstOrDefaultAsync(cancellationToken);
+
+ var rank = await context.SongBestData
+ .Where(x => x.SongId == request.SongId && x.Difficulty == request.Difficulty && x.BestScore > score.BestScore)
+ .CountAsync(cancellationToken);
+
+ userBestScore = new SongLeaderboardEntry
+ {
+ Rank = rank + 1,
+ Baid = score.Baid,
+ UserName = user?.MyDonName,
+ BestScore = score.BestScore,
+ BestRate = score.BestRate,
+ BestCrown = score.BestCrown,
+ BestScoreRank = score.BestScoreRank
+ };
+ }
+ }*/
+
+ return ApiResult.Succeed(new LeaderBoard
+ {
+ Data = leaderboard,
+ Current = userLeaderboardEntry,
+ CurrentPage = request.Page,
+ TotalPages = totalPages,
+ TotalCount = totalScores
+ });
+ }
+}
\ No newline at end of file
diff --git a/Application/Handlers/Api/User/GetUserQuery.cs b/Application/Handlers/Api/User/GetUserQuery.cs
new file mode 100644
index 0000000..74ceaa5
--- /dev/null
+++ b/Application/Handlers/Api/User/GetUserQuery.cs
@@ -0,0 +1,25 @@
+namespace Application.Handlers.Api.User;
+
+public record GetUserQuery(uint Baid) : IRequest>;
+
+public class GetUserQueryHandler(ITaikoDbContext context) : IRequestHandler>
+{
+ public async Task> Handle(GetUserQuery request, CancellationToken cancellationToken)
+ {
+ var userDatum = await context.UserData.Include(datum => datum.Cards)
+ .Where(datum => datum.Baid == request.Baid)
+ .FirstOrDefaultAsync(cancellationToken);
+
+ if (userDatum == null)
+ {
+ return ApiResult.Failed("User not found.");
+ }
+
+ return ApiResult.Succeed(new Domain.Models.User
+ {
+ Baid = userDatum.Baid,
+ AccessCodes = userDatum.Cards.Select(card => card.AccessCode).ToList(),
+ IsAdmin = userDatum.IsAdmin
+ });
+ }
+}
\ No newline at end of file
diff --git a/Application/Handlers/Api/User/GetUsersQuery.cs b/Application/Handlers/Api/User/GetUsersQuery.cs
new file mode 100644
index 0000000..68b6318
--- /dev/null
+++ b/Application/Handlers/Api/User/GetUsersQuery.cs
@@ -0,0 +1,58 @@
+using Application.Mappers;
+
+namespace Application.Handlers.Api.User;
+
+using Users = PaginatedResult;
+
+public record GetUsersQuery(int Page, int Limit, string? SearchTerm) : IRequest>;
+
+public class GetUsersQueryHandler(ITaikoDbContext context) : IRequestHandler>
+{
+ public async Task> Handle(GetUsersQuery request, CancellationToken cancellationToken)
+ {
+ var users = new List();
+
+ var cardEntries = await context.Cards.ToListAsync(cancellationToken);
+ var userEntriesQuery = context.UserData.AsQueryable();
+
+ if (!string.IsNullOrEmpty(request.SearchTerm))
+ {
+ var lowerCaseSearchTerm = request.SearchTerm.ToLower();
+ userEntriesQuery = userEntriesQuery.Where(user =>
+ user.Baid.ToString() == lowerCaseSearchTerm ||
+ user.MyDonName.Contains(lowerCaseSearchTerm, StringComparison.CurrentCultureIgnoreCase) ||
+ context.Cards.Any(card => card.Baid == user.Baid &&
+ card.AccessCode.Contains(lowerCaseSearchTerm, StringComparison.CurrentCultureIgnoreCase)));
+ }
+
+ var totalUsers = await userEntriesQuery.CountAsync(cancellationToken);
+ var totalPages = (totalUsers + request.Limit - 1) / request.Limit;
+
+ var userEntries = await userEntriesQuery
+ .OrderBy(user => user.Baid)
+ .Skip((request.Page - 1) * request.Limit)
+ .Take(request.Limit)
+ .ToListAsync(cancellationToken);
+
+ foreach (var user in userEntries)
+ {
+ var userSetting = UserSettingMapper.MapToUserSetting(user);
+
+ users.Add(new Domain.Models.User
+ {
+ Baid = user.Baid,
+ AccessCodes = cardEntries.Where(card => card.Baid == user.Baid).Select(card => card.AccessCode).ToList(),
+ IsAdmin = user.IsAdmin,
+ UserSetting = userSetting
+ });
+ }
+
+ return ApiResult.Succeed( new Users
+ {
+ Data = users,
+ CurrentPage = request.Page,
+ TotalPages = totalPages,
+ TotalCount = totalUsers
+ });
+ }
+}
\ No newline at end of file
diff --git a/Application/Handlers/Game/GetInitialDataQuery.cs b/Application/Handlers/Game/GetInitialDataQuery.cs
index c307fd2..2c87ac8 100644
--- a/Application/Handlers/Game/GetInitialDataQuery.cs
+++ b/Application/Handlers/Game/GetInitialDataQuery.cs
@@ -1,4 +1,5 @@
using System.Collections.Immutable;
+using Domain.Models.GameData;
using Domain.Settings;
using Microsoft.Extensions.Options;
diff --git a/Application/Interfaces/IGameDataService.cs b/Application/Interfaces/IGameDataService.cs
index 4189928..393228d 100644
--- a/Application/Interfaces/IGameDataService.cs
+++ b/Application/Interfaces/IGameDataService.cs
@@ -1,4 +1,5 @@
using System.Collections.Immutable;
+using Domain.Models.GameData;
namespace Application.Interfaces;
diff --git a/Application/Mappers/UserSettingMapper.cs b/Application/Mappers/UserSettingMapper.cs
new file mode 100644
index 0000000..3a94b48
--- /dev/null
+++ b/Application/Mappers/UserSettingMapper.cs
@@ -0,0 +1,33 @@
+using System.Diagnostics.CodeAnalysis;
+using Riok.Mapperly.Abstractions;
+
+namespace Application.Mappers;
+
+[Mapper(AutoUserMappings = false)]
+public static partial class UserSettingMapper
+{
+ [SuppressMessage("Mapper", "RMG020:Source member is not mapped to any target member")]
+ [MapProperty(nameof(UserDatum.TitleFlgArray), nameof(UserSetting.UnlockedTitle))]
+ [MapProperty(nameof(UserDatum.OptionSetting), nameof(UserSetting.PlaySetting), Use = nameof(ShortToPlaySetting))]
+ [MapProperty(nameof(UserDatum.UnlockedKigurumi), nameof(UserSetting.UnlockedKigurumi), Use = nameof(FixUnlock))]
+ [MapProperty(nameof(UserDatum.UnlockedBody), nameof(UserSetting.UnlockedBody), Use = nameof(FixUnlock))]
+ [MapProperty(nameof(UserDatum.UnlockedFace), nameof(UserSetting.UnlockedFace), Use = nameof(FixUnlock))]
+ [MapProperty(nameof(UserDatum.UnlockedHead), nameof(UserSetting.UnlockedHead), Use = nameof(FixUnlock))]
+ [MapProperty(nameof(UserDatum.UnlockedPuchi), nameof(UserSetting.UnlockedPuchi), Use = nameof(FixUnlock))]
+ public static partial UserSetting MapToUserSetting(UserDatum user);
+
+ public static PlaySetting ShortToPlaySetting(short option)
+ {
+ return PlaySettingConverter.ShortToPlaySetting(option);
+ }
+
+ public static List FixUnlock(List unlock)
+ {
+ if (!unlock.Contains(0))
+ {
+ unlock.Add(0);
+ }
+
+ return unlock;
+ }
+}
\ No newline at end of file
diff --git a/Application/Models/Game/CommonGetFolderResponse.cs b/Application/Models/Game/CommonGetFolderResponse.cs
index 478c97e..b17057a 100644
--- a/Application/Models/Game/CommonGetFolderResponse.cs
+++ b/Application/Models/Game/CommonGetFolderResponse.cs
@@ -1,4 +1,6 @@
-namespace Application.Models.Game;
+using Domain.Models.GameData;
+
+namespace Application.Models.Game;
public class CommonGetFolderResponse
{
diff --git a/Application/Models/Game/CommonGetShopFolderResponse.cs b/Application/Models/Game/CommonGetShopFolderResponse.cs
index 60810dd..4b5d396 100644
--- a/Application/Models/Game/CommonGetShopFolderResponse.cs
+++ b/Application/Models/Game/CommonGetShopFolderResponse.cs
@@ -1,4 +1,6 @@
-namespace Application.Models.Game;
+using Domain.Models.GameData;
+
+namespace Application.Models.Game;
public class CommonGetShopFolderResponse
{
diff --git a/Application/Models/Game/CommonGetSongIntroductionResponse.cs b/Application/Models/Game/CommonGetSongIntroductionResponse.cs
index 0461d70..475d111 100644
--- a/Application/Models/Game/CommonGetSongIntroductionResponse.cs
+++ b/Application/Models/Game/CommonGetSongIntroductionResponse.cs
@@ -1,4 +1,6 @@
-namespace Application.Models.Game;
+using Domain.Models.GameData;
+
+namespace Application.Models.Game;
public class CommonGetSongIntroductionResponse
{
diff --git a/Application/Utils/PlaySettingConverter.cs b/Application/Utils/PlaySettingConverter.cs
new file mode 100644
index 0000000..9d3b669
--- /dev/null
+++ b/Application/Utils/PlaySettingConverter.cs
@@ -0,0 +1,43 @@
+using System.Collections.Specialized;
+
+namespace Application.Utils;
+
+public static class PlaySettingConverter
+{
+ public static PlaySetting ShortToPlaySetting(short input)
+ {
+ var bits = new BitVector32(input);
+ var speedSection = BitVector32.CreateSection(15);
+ var vanishSection = BitVector32.CreateSection(1, speedSection);
+ var inverseSection = BitVector32.CreateSection(1, vanishSection);
+ var randomSection = BitVector32.CreateSection(2, inverseSection);
+
+ var randomType = (RandomType)bits[randomSection];
+ randomType.Throw().IfOutOfRange();
+ var result = new PlaySetting
+ {
+ Speed = (uint)bits[speedSection],
+ IsVanishOn = bits[vanishSection] == 1,
+ IsInverseOn = bits[inverseSection] == 1,
+ RandomType = randomType
+ };
+
+ return result;
+ }
+
+ public static short PlaySettingToShort(PlaySetting setting)
+ {
+ var bits = new BitVector32();
+ var speedSection = BitVector32.CreateSection(15);
+ var vanishSection = BitVector32.CreateSection(1, speedSection);
+ var inverseSection = BitVector32.CreateSection(1, vanishSection);
+ var randomSection = BitVector32.CreateSection(2, inverseSection);
+
+ bits[speedSection] = (int)setting.Speed;
+ bits[vanishSection] = setting.IsVanishOn ? 1 : 0;
+ bits[inverseSection] = setting.IsInverseOn ? 1 : 0;
+ bits[randomSection] = (int)setting.RandomType;
+
+ return (short)bits.Data;
+ }
+}
\ No newline at end of file
diff --git a/Domain/Models/Base/PaginatedResult.cs b/Domain/Models/Base/PaginatedResult.cs
new file mode 100644
index 0000000..af9bee8
--- /dev/null
+++ b/Domain/Models/Base/PaginatedResult.cs
@@ -0,0 +1,11 @@
+namespace Domain.Models.Base;
+
+public class PaginatedResult
+{
+ public List Data { get; set; } = [];
+ public T? Current;
+
+ public int CurrentPage { get; set; }
+ public int TotalPages { get; set; }
+ public int TotalCount { get; set; }
+}
\ No newline at end of file
diff --git a/Domain/Models/DanData.cs b/Domain/Models/DanData.cs
index 32651ec..b28f240 100644
--- a/Domain/Models/DanData.cs
+++ b/Domain/Models/DanData.cs
@@ -1,4 +1,5 @@
using System.Text.Json.Serialization;
+using Domain.Models.GameData;
namespace Domain.Models;
diff --git a/Domain/Models/Costume.cs b/Domain/Models/GameData/Costume.cs
similarity index 91%
rename from Domain/Models/Costume.cs
rename to Domain/Models/GameData/Costume.cs
index 0744b13..958d592 100644
--- a/Domain/Models/Costume.cs
+++ b/Domain/Models/GameData/Costume.cs
@@ -1,4 +1,4 @@
-namespace Domain.Models;
+namespace Domain.Models.GameData;
public class Costume
{
diff --git a/Domain/Models/DonCosRewardEntry.cs b/Domain/Models/GameData/DonCosRewardEntry.cs
similarity index 86%
rename from Domain/Models/DonCosRewardEntry.cs
rename to Domain/Models/GameData/DonCosRewardEntry.cs
index ccdf21f..8da0d4f 100644
--- a/Domain/Models/DonCosRewardEntry.cs
+++ b/Domain/Models/GameData/DonCosRewardEntry.cs
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;
-namespace Domain.Models;
+namespace Domain.Models.GameData;
public class DonCosRewardEntry
{
diff --git a/Domain/Models/DonCosRewards.cs b/Domain/Models/GameData/DonCosRewards.cs
similarity index 83%
rename from Domain/Models/DonCosRewards.cs
rename to Domain/Models/GameData/DonCosRewards.cs
index 28931b5..d4f5530 100644
--- a/Domain/Models/DonCosRewards.cs
+++ b/Domain/Models/GameData/DonCosRewards.cs
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;
-namespace Domain.Models;
+namespace Domain.Models.GameData;
public class DonCosRewards
{
diff --git a/Domain/Models/EventFolderData.cs b/Domain/Models/GameData/EventFolderData.cs
similarity index 92%
rename from Domain/Models/EventFolderData.cs
rename to Domain/Models/GameData/EventFolderData.cs
index 2ba7cdc..2254173 100644
--- a/Domain/Models/EventFolderData.cs
+++ b/Domain/Models/GameData/EventFolderData.cs
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;
-namespace Domain.Models;
+namespace Domain.Models.GameData;
public class EventFolderData : IVerupNo
{
diff --git a/Domain/Models/IVerupNo.cs b/Domain/Models/GameData/IVerupNo.cs
similarity index 64%
rename from Domain/Models/IVerupNo.cs
rename to Domain/Models/GameData/IVerupNo.cs
index 6d63ff1..cdf8f5e 100644
--- a/Domain/Models/IVerupNo.cs
+++ b/Domain/Models/GameData/IVerupNo.cs
@@ -1,4 +1,4 @@
-namespace Domain.Models;
+namespace Domain.Models.GameData;
public interface IVerupNo
{
diff --git a/Domain/Models/MusicDetail.cs b/Domain/Models/GameData/MusicDetail.cs
similarity index 96%
rename from Domain/Models/MusicDetail.cs
rename to Domain/Models/GameData/MusicDetail.cs
index 932a776..df5826a 100644
--- a/Domain/Models/MusicDetail.cs
+++ b/Domain/Models/GameData/MusicDetail.cs
@@ -1,6 +1,6 @@
using Domain.Enums;
-namespace Domain.Models;
+namespace Domain.Models.GameData;
public class MusicDetail
{
diff --git a/Domain/Models/MusicInfoEntry.cs b/Domain/Models/GameData/MusicInfoEntry.cs
similarity index 95%
rename from Domain/Models/MusicInfoEntry.cs
rename to Domain/Models/GameData/MusicInfoEntry.cs
index 808a0ab..5029684 100644
--- a/Domain/Models/MusicInfoEntry.cs
+++ b/Domain/Models/GameData/MusicInfoEntry.cs
@@ -1,7 +1,7 @@
using System.Text.Json.Serialization;
using Domain.Enums;
-namespace Domain.Models;
+namespace Domain.Models.GameData;
public class MusicInfoEntry
{
diff --git a/Domain/Models/MusicInfos.cs b/Domain/Models/GameData/MusicInfos.cs
similarity index 83%
rename from Domain/Models/MusicInfos.cs
rename to Domain/Models/GameData/MusicInfos.cs
index 704f783..bb298c5 100644
--- a/Domain/Models/MusicInfos.cs
+++ b/Domain/Models/GameData/MusicInfos.cs
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;
-namespace Domain.Models;
+namespace Domain.Models.GameData;
public class MusicInfos
{
diff --git a/Domain/Models/MusicOrder.cs b/Domain/Models/GameData/MusicOrder.cs
similarity index 82%
rename from Domain/Models/MusicOrder.cs
rename to Domain/Models/GameData/MusicOrder.cs
index 13c67f5..aa48be1 100644
--- a/Domain/Models/MusicOrder.cs
+++ b/Domain/Models/GameData/MusicOrder.cs
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;
-namespace Domain.Models;
+namespace Domain.Models.GameData;
public class MusicOrder
{
diff --git a/Domain/Models/MusicOrderEntry.cs b/Domain/Models/GameData/MusicOrderEntry.cs
similarity index 81%
rename from Domain/Models/MusicOrderEntry.cs
rename to Domain/Models/GameData/MusicOrderEntry.cs
index faa2baf..e72be46 100644
--- a/Domain/Models/MusicOrderEntry.cs
+++ b/Domain/Models/GameData/MusicOrderEntry.cs
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;
-namespace Domain.Models;
+namespace Domain.Models.GameData;
public class MusicOrderEntry
{
diff --git a/Domain/Models/NeiroEntry.cs b/Domain/Models/GameData/NeiroEntry.cs
similarity index 80%
rename from Domain/Models/NeiroEntry.cs
rename to Domain/Models/GameData/NeiroEntry.cs
index e87ba3c..606c0fe 100644
--- a/Domain/Models/NeiroEntry.cs
+++ b/Domain/Models/GameData/NeiroEntry.cs
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;
-namespace Domain.Models;
+namespace Domain.Models.GameData;
public class NeiroEntry
{
diff --git a/Domain/Models/Neiros.cs b/Domain/Models/GameData/Neiros.cs
similarity index 82%
rename from Domain/Models/Neiros.cs
rename to Domain/Models/GameData/Neiros.cs
index c4a821a..d03b13c 100644
--- a/Domain/Models/Neiros.cs
+++ b/Domain/Models/GameData/Neiros.cs
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;
-namespace Domain.Models;
+namespace Domain.Models.GameData;
public class Neiros
{
diff --git a/Domain/Models/QRCodeData.cs b/Domain/Models/GameData/QRCodeData.cs
similarity index 85%
rename from Domain/Models/QRCodeData.cs
rename to Domain/Models/GameData/QRCodeData.cs
index b46fce3..ed4a75b 100644
--- a/Domain/Models/QRCodeData.cs
+++ b/Domain/Models/GameData/QRCodeData.cs
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;
-namespace Domain.Models;
+namespace Domain.Models.GameData;
public class QRCodeData
{
diff --git a/Domain/Models/ShopFolderData.cs b/Domain/Models/GameData/ShopFolderData.cs
similarity index 89%
rename from Domain/Models/ShopFolderData.cs
rename to Domain/Models/GameData/ShopFolderData.cs
index 3b12247..bc1c822 100644
--- a/Domain/Models/ShopFolderData.cs
+++ b/Domain/Models/GameData/ShopFolderData.cs
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;
-namespace Domain.Models;
+namespace Domain.Models.GameData;
public class ShopFolderData
{
diff --git a/Domain/Models/ShougouEntry.cs b/Domain/Models/GameData/ShougouEntry.cs
similarity index 85%
rename from Domain/Models/ShougouEntry.cs
rename to Domain/Models/GameData/ShougouEntry.cs
index 0ccd0d9..383c15e 100644
--- a/Domain/Models/ShougouEntry.cs
+++ b/Domain/Models/GameData/ShougouEntry.cs
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;
-namespace Domain.Models;
+namespace Domain.Models.GameData;
public class ShougouEntry
{
diff --git a/Domain/Models/Shougous.cs b/Domain/Models/GameData/Shougous.cs
similarity index 82%
rename from Domain/Models/Shougous.cs
rename to Domain/Models/GameData/Shougous.cs
index 895c53f..b60b491 100644
--- a/Domain/Models/Shougous.cs
+++ b/Domain/Models/GameData/Shougous.cs
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;
-namespace Domain.Models;
+namespace Domain.Models.GameData;
public class Shougous
{
diff --git a/Domain/Models/SongIntroductionData.cs b/Domain/Models/GameData/SongIntroductionData.cs
similarity index 92%
rename from Domain/Models/SongIntroductionData.cs
rename to Domain/Models/GameData/SongIntroductionData.cs
index 6cc10cc..ea69f3d 100644
--- a/Domain/Models/SongIntroductionData.cs
+++ b/Domain/Models/GameData/SongIntroductionData.cs
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;
-namespace Domain.Models;
+namespace Domain.Models.GameData;
public class SongIntroductionData : IVerupNo
{
diff --git a/Domain/Models/WordList.cs b/Domain/Models/GameData/WordList.cs
similarity index 83%
rename from Domain/Models/WordList.cs
rename to Domain/Models/GameData/WordList.cs
index aff8b07..5301bcf 100644
--- a/Domain/Models/WordList.cs
+++ b/Domain/Models/GameData/WordList.cs
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;
-namespace Domain.Models;
+namespace Domain.Models.GameData;
public class WordList
{
diff --git a/Domain/Models/WordListEntry.cs b/Domain/Models/GameData/WordListEntry.cs
similarity index 94%
rename from Domain/Models/WordListEntry.cs
rename to Domain/Models/GameData/WordListEntry.cs
index b3a43bd..c26a156 100644
--- a/Domain/Models/WordListEntry.cs
+++ b/Domain/Models/GameData/WordListEntry.cs
@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;
-namespace Domain.Models;
+namespace Domain.Models.GameData;
public class WordListEntry
{
diff --git a/Domain/Models/SongLeaderboard.cs b/Domain/Models/SongLeaderboard.cs
index 1df16b5..4e823c3 100644
--- a/Domain/Models/SongLeaderboard.cs
+++ b/Domain/Models/SongLeaderboard.cs
@@ -1,27 +1,10 @@
-using Domain.Enums;
-
-namespace Domain.Models;
+namespace Domain.Models;
public class SongLeaderboard
{
- public int Rank { get; set; }
-
- public uint Baid { get; set; }
-
- public uint BestScore { get; set; }
-
- public uint BestRate { get; set; }
-
- public CrownType BestCrown { get; set; }
-
- public ScoreRank BestScoreRank { get; set; }
-
- public uint GoodCount { get; set; }
- public uint OkCount { get; set; }
- public uint MissCount { get; set; }
- public uint ComboCount { get; set; }
- public uint HitCount { get; set; }
- public uint DrumrollCount { get; set; }
-
- public string? UserName { get; set; }
+ public List LeaderboardData { get; set; } = [];
+ public SongLeaderboardEntry? UserScore { get; set; }
+ public int CurrentPage { get; set; }
+ public int TotalPages { get; set; }
+ public int TotalScores { get; set; }
}
\ No newline at end of file
diff --git a/Domain/Models/SongLeaderboardEntry.cs b/Domain/Models/SongLeaderboardEntry.cs
new file mode 100644
index 0000000..9630c10
--- /dev/null
+++ b/Domain/Models/SongLeaderboardEntry.cs
@@ -0,0 +1,27 @@
+using Domain.Enums;
+
+namespace Domain.Models;
+
+public class SongLeaderboardEntry
+{
+ public int Rank { get; set; }
+
+ public uint Baid { get; set; }
+
+ public uint BestScore { get; set; }
+
+ public uint BestRate { get; set; }
+
+ public CrownType BestCrown { get; set; }
+
+ public ScoreRank BestScoreRank { get; set; }
+
+ public uint GoodCount { get; set; }
+ public uint OkCount { get; set; }
+ public uint MissCount { get; set; }
+ public uint ComboCount { get; set; }
+ public uint HitCount { get; set; }
+ public uint DrumrollCount { get; set; }
+
+ public string? UserName { get; set; }
+}
\ No newline at end of file
diff --git a/Domain/Models/UserSetting.cs b/Domain/Models/UserSetting.cs
index 3a33b44..30dec9f 100644
--- a/Domain/Models/UserSetting.cs
+++ b/Domain/Models/UserSetting.cs
@@ -64,5 +64,5 @@ public class UserSetting
public uint ColorLimb { get; set; }
- public DateTime LastPlayDateTime { get; set; }
+ public DateTime LastPlayDatetime { get; set; }
}
\ No newline at end of file
diff --git a/Infrastructure/DependencyInjection.cs b/Infrastructure/DependencyInjection.cs
new file mode 100644
index 0000000..a17b952
--- /dev/null
+++ b/Infrastructure/DependencyInjection.cs
@@ -0,0 +1,34 @@
+using Application.Interfaces;
+using Domain.Common;
+using Infrastructure.Persistence;
+using Infrastructure.Services;
+using Infrastructure.Utils;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Infrastructure;
+
+public static class DependencyInjection
+{
+ public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration)
+ {
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddDbContext(option =>
+ {
+ var dbName = configuration["DbFileName"];
+ if (string.IsNullOrEmpty(dbName))
+ {
+ dbName = Constants.DefaultDbName;
+ }
+
+ var path = Path.Combine(PathHelper.GetRootPath(), dbName);
+ option.UseSqlite($"Data Source={path}");
+ });
+ services.AddScoped(provider =>
+ provider.GetService() ?? throw new InvalidOperationException());
+
+ return services;
+ }
+}
\ No newline at end of file
diff --git a/Infrastructure/Infrastructure.csproj b/Infrastructure/Infrastructure.csproj
index 10f4a2b..c07a6f8 100644
--- a/Infrastructure/Infrastructure.csproj
+++ b/Infrastructure/Infrastructure.csproj
@@ -15,6 +15,8 @@
all
runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
diff --git a/Infrastructure/Services/GameDataService.cs b/Infrastructure/Services/GameDataService.cs
index 2893ff9..8ea9e22 100644
--- a/Infrastructure/Services/GameDataService.cs
+++ b/Infrastructure/Services/GameDataService.cs
@@ -5,6 +5,7 @@ using System.Text.Json;
using Application.Interfaces;
using Domain.Common;
using Domain.Models;
+using Domain.Models.GameData;
using Domain.Settings;
using Infrastructure.Utils;
using Microsoft.Extensions.Options;
diff --git a/Infrastructure/Services/JwtTokenService.cs b/Infrastructure/Services/JwtTokenService.cs
new file mode 100644
index 0000000..8ac702d
--- /dev/null
+++ b/Infrastructure/Services/JwtTokenService.cs
@@ -0,0 +1,35 @@
+using System.IdentityModel.Tokens.Jwt;
+using System.Security.Claims;
+using System.Text;
+using Application.Interfaces;
+using Domain.Settings;
+using Microsoft.Extensions.Options;
+using Microsoft.IdentityModel.Tokens;
+
+namespace Infrastructure.Services;
+
+public class JwtTokenService(IOptions options) : IJwtTokenService
+{
+ public string GenerateToken(uint baid, bool isAdmin)
+ {
+ var authSettings = options.Value;
+ var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(authSettings.JwtKey));
+ var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
+
+ var claims = new List
+ {
+ new(ClaimTypes.Name, baid.ToString()),
+ new(ClaimTypes.Role, isAdmin ? "Admin" : "User")
+ };
+
+ var token = new JwtSecurityToken(
+ issuer: authSettings.JwtIssuer,
+ audience: authSettings.JwtAudience,
+ expires: DateTime.UtcNow.AddHours(24),
+ signingCredentials: credentials,
+ claims: claims
+ );
+
+ return new JwtSecurityTokenHandler().WriteToken(token);
+ }
+}
\ No newline at end of file
diff --git a/Server/Controllers/WeatherForecastController.cs b/Server/Controllers/WeatherForecastController.cs
deleted file mode 100644
index f5b475e..0000000
--- a/Server/Controllers/WeatherForecastController.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-using Microsoft.AspNetCore.Mvc;
-
-namespace Server.Controllers;
-
-[ApiController]
-[Route("[controller]")]
-public class WeatherForecastController : ControllerBase
-{
- private static readonly string[] Summaries = new[]
- {
- "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
- };
-
- private readonly ILogger _logger;
-
- public WeatherForecastController(ILogger logger)
- {
- _logger = logger;
- }
-
- [HttpGet(Name = "GetWeatherForecast")]
- public IEnumerable Get()
- {
- return Enumerable.Range(1, 5).Select(index => new WeatherForecast
- {
- Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
- TemperatureC = Random.Shared.Next(-20, 55),
- Summary = Summaries[Random.Shared.Next(Summaries.Length)]
- })
- .ToArray();
- }
-}
\ No newline at end of file
diff --git a/Server/Server.csproj b/Server/Server.csproj
index e89945e..06e001a 100644
--- a/Server/Server.csproj
+++ b/Server/Server.csproj
@@ -10,4 +10,8 @@
+
+
+
+
diff --git a/Server/Server.http b/Server/Server.http
deleted file mode 100644
index b36c8ea..0000000
--- a/Server/Server.http
+++ /dev/null
@@ -1,6 +0,0 @@
-@Server_HostAddress = http://localhost:5247
-
-GET {{Server_HostAddress}}/weatherforecast/
-Accept: application/json
-
-###
diff --git a/Server/WeatherForecast.cs b/Server/WeatherForecast.cs
deleted file mode 100644
index 82e72a1..0000000
--- a/Server/WeatherForecast.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-namespace Server;
-
-public class WeatherForecast
-{
- public DateOnly Date { get; set; }
-
- public int TemperatureC { get; set; }
-
- public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
-
- public string? Summary { get; set; }
-}
\ No newline at end of file
diff --git a/Server/appsettings.Development.json b/Server/appsettings.Development.json
deleted file mode 100644
index 0c208ae..0000000
--- a/Server/appsettings.Development.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "Logging": {
- "LogLevel": {
- "Default": "Information",
- "Microsoft.AspNetCore": "Warning"
- }
- }
-}