1
0
mirror of synced 2024-11-24 06:50:15 +01:00

Test token table refactor

This commit is contained in:
asesidaa 2024-03-10 01:18:43 +08:00
parent 8901e92e55
commit be1d6f1581
11 changed files with 702 additions and 59 deletions

View File

@ -10,6 +10,7 @@ public partial class TaikoDbContext
public virtual DbSet<DanStageScoreDatum> DanStageScoreData { get; set; } = null!;
public virtual DbSet<AiScoreDatum> AiScoreData { get; set; } = null!;
public virtual DbSet<AiSectionScoreDatum> AiSectionScoreData { get; set; } = null!;
public virtual DbSet<Token> Tokens { get; set; } = null!;
partial void OnModelCreatingPartial(ModelBuilder modelBuilder)
{
@ -60,5 +61,16 @@ public partial class TaikoDbContext
.HasForeignKey(d => new { d.Baid, d.SongId, d.Difficulty })
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity<Token>(entity =>
{
entity.HasKey(e => new { e.Baid, e.Id });
entity.HasOne(d => d.Datum)
.WithMany(p => p.Tokens)
.HasPrincipalKey(p => p.Baid)
.HasForeignKey(d => d.Baid)
.OnDelete(DeleteBehavior.Cascade);
});
}
}

View File

@ -0,0 +1,12 @@
namespace GameDatabase.Entities;
public class Token
{
public uint Baid { get; set; }
public int Id { get; set; }
public int Count { get; set; }
public virtual UserDatum? Datum { get; set; }
}

View File

@ -31,7 +31,7 @@ namespace GameDatabase.Entities
public bool DisplayAchievement { get; set; }
public Difficulty AchievementDisplayDifficulty { get; set; }
public int AiWinCount { get; set; }
public string TokenCountDict { get; set; } = "{}";
public List<Token> Tokens { get; set; } = new();
public string UnlockedSongIdList { get; set; } = "[]";
public bool IsAdmin { get; set; }
}

View File

@ -0,0 +1,519 @@
// <auto-generated />
using System;
using GameDatabase.Context;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace GameDatabase.Migrations
{
[DbContext(typeof(TaikoDbContext))]
[Migration("20240309102758_SeparateTokens")]
partial class SeparateTokens
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "8.0.0-rc.2.23480.1");
modelBuilder.Entity("GameDatabase.Entities.AiScoreDatum", b =>
{
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("SongId")
.HasColumnType("INTEGER");
b.Property<uint>("Difficulty")
.HasColumnType("INTEGER");
b.Property<bool>("IsWin")
.HasColumnType("INTEGER");
b.HasKey("Baid", "SongId", "Difficulty");
b.ToTable("AiScoreData");
});
modelBuilder.Entity("GameDatabase.Entities.AiSectionScoreDatum", b =>
{
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("SongId")
.HasColumnType("INTEGER");
b.Property<uint>("Difficulty")
.HasColumnType("INTEGER");
b.Property<int>("SectionIndex")
.HasColumnType("INTEGER");
b.Property<int>("Crown")
.HasColumnType("INTEGER");
b.Property<uint>("DrumrollCount")
.HasColumnType("INTEGER");
b.Property<uint>("GoodCount")
.HasColumnType("INTEGER");
b.Property<bool>("IsWin")
.HasColumnType("INTEGER");
b.Property<uint>("MissCount")
.HasColumnType("INTEGER");
b.Property<uint>("OkCount")
.HasColumnType("INTEGER");
b.Property<uint>("Score")
.HasColumnType("INTEGER");
b.HasKey("Baid", "SongId", "Difficulty", "SectionIndex");
b.ToTable("AiSectionScoreData");
});
modelBuilder.Entity("GameDatabase.Entities.Card", b =>
{
b.Property<string>("AccessCode")
.HasColumnType("TEXT");
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.HasKey("AccessCode");
b.HasIndex("Baid");
b.ToTable("Card", (string)null);
});
modelBuilder.Entity("GameDatabase.Entities.Credential", b =>
{
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Salt")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Baid");
b.ToTable("Credential", (string)null);
});
modelBuilder.Entity("GameDatabase.Entities.DanScoreDatum", b =>
{
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("DanId")
.HasColumnType("INTEGER");
b.Property<int>("DanType")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasDefaultValue(1);
b.Property<uint>("ArrivalSongCount")
.HasColumnType("INTEGER");
b.Property<uint>("ClearState")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasDefaultValue(0u);
b.Property<uint>("ComboCountTotal")
.HasColumnType("INTEGER");
b.Property<uint>("SoulGaugeTotal")
.HasColumnType("INTEGER");
b.HasKey("Baid", "DanId", "DanType");
b.ToTable("DanScoreData");
});
modelBuilder.Entity("GameDatabase.Entities.DanStageScoreDatum", b =>
{
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("DanId")
.HasColumnType("INTEGER");
b.Property<int>("DanType")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasDefaultValue(1);
b.Property<uint>("SongNumber")
.HasColumnType("INTEGER");
b.Property<uint>("BadCount")
.HasColumnType("INTEGER");
b.Property<uint>("ComboCount")
.HasColumnType("INTEGER");
b.Property<uint>("DrumrollCount")
.HasColumnType("INTEGER");
b.Property<uint>("GoodCount")
.HasColumnType("INTEGER");
b.Property<uint>("HighScore")
.HasColumnType("INTEGER");
b.Property<uint>("OkCount")
.HasColumnType("INTEGER");
b.Property<uint>("PlayScore")
.HasColumnType("INTEGER");
b.Property<uint>("TotalHitCount")
.HasColumnType("INTEGER");
b.HasKey("Baid", "DanId", "DanType", "SongNumber");
b.ToTable("DanStageScoreData");
});
modelBuilder.Entity("GameDatabase.Entities.SongBestDatum", b =>
{
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("SongId")
.HasColumnType("INTEGER");
b.Property<uint>("Difficulty")
.HasColumnType("INTEGER");
b.Property<uint>("BestCrown")
.HasColumnType("INTEGER");
b.Property<uint>("BestRate")
.HasColumnType("INTEGER");
b.Property<uint>("BestScore")
.HasColumnType("INTEGER");
b.Property<uint>("BestScoreRank")
.HasColumnType("INTEGER");
b.HasKey("Baid", "SongId", "Difficulty");
b.ToTable("SongBestData");
});
modelBuilder.Entity("GameDatabase.Entities.SongPlayDatum", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("ComboCount")
.HasColumnType("INTEGER");
b.Property<uint>("Crown")
.HasColumnType("INTEGER");
b.Property<uint>("Difficulty")
.HasColumnType("INTEGER");
b.Property<uint>("DrumrollCount")
.HasColumnType("INTEGER");
b.Property<uint>("GoodCount")
.HasColumnType("INTEGER");
b.Property<uint>("HitCount")
.HasColumnType("INTEGER");
b.Property<uint>("MissCount")
.HasColumnType("INTEGER");
b.Property<uint>("OkCount")
.HasColumnType("INTEGER");
b.Property<DateTime>("PlayTime")
.HasColumnType("datetime");
b.Property<uint>("Score")
.HasColumnType("INTEGER");
b.Property<uint>("ScoreRank")
.HasColumnType("INTEGER");
b.Property<uint>("ScoreRate")
.HasColumnType("INTEGER");
b.Property<bool>("Skipped")
.HasColumnType("INTEGER");
b.Property<uint>("SongId")
.HasColumnType("INTEGER");
b.Property<uint>("SongNumber")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("Baid");
b.ToTable("SongPlayData");
});
modelBuilder.Entity("GameDatabase.Entities.Token", b =>
{
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<int>("Id")
.HasColumnType("INTEGER");
b.Property<int>("Count")
.HasColumnType("INTEGER");
b.HasKey("Baid", "Id");
b.ToTable("Tokens");
});
modelBuilder.Entity("GameDatabase.Entities.UserDatum", b =>
{
b.Property<uint>("Baid")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<uint>("AchievementDisplayDifficulty")
.HasColumnType("INTEGER");
b.Property<int>("AiWinCount")
.HasColumnType("INTEGER");
b.Property<uint>("ColorBody")
.HasColumnType("INTEGER");
b.Property<uint>("ColorFace")
.HasColumnType("INTEGER");
b.Property<uint>("ColorLimb")
.HasColumnType("INTEGER");
b.Property<string>("CostumeData")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("CostumeFlgArray")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("DifficultyPlayedArray")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("DifficultySettingArray")
.IsRequired()
.HasColumnType("TEXT");
b.Property<bool>("DisplayAchievement")
.HasColumnType("INTEGER");
b.Property<bool>("DisplayDan")
.HasColumnType("INTEGER");
b.Property<string>("FavoriteSongsArray")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("GenericInfoFlgArray")
.IsRequired()
.HasColumnType("TEXT");
b.Property<bool>("IsAdmin")
.HasColumnType("INTEGER");
b.Property<bool>("IsSkipOn")
.HasColumnType("INTEGER");
b.Property<bool>("IsVoiceOn")
.HasColumnType("INTEGER");
b.Property<DateTime>("LastPlayDatetime")
.HasColumnType("datetime");
b.Property<uint>("LastPlayMode")
.HasColumnType("INTEGER");
b.Property<string>("MyDonName")
.IsRequired()
.HasColumnType("TEXT");
b.Property<uint>("MyDonNameLanguage")
.HasColumnType("INTEGER");
b.Property<int>("NotesPosition")
.HasColumnType("INTEGER");
b.Property<short>("OptionSetting")
.HasColumnType("INTEGER");
b.Property<uint>("SelectedToneId")
.HasColumnType("INTEGER");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("TitleFlgArray")
.IsRequired()
.HasColumnType("TEXT");
b.Property<uint>("TitlePlateId")
.HasColumnType("INTEGER");
b.Property<string>("ToneFlgArray")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("UnlockedSongIdList")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Baid");
b.ToTable("UserData");
});
modelBuilder.Entity("GameDatabase.Entities.AiScoreDatum", b =>
{
b.HasOne("GameDatabase.Entities.UserDatum", "Ba")
.WithMany()
.HasForeignKey("Baid")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Ba");
});
modelBuilder.Entity("GameDatabase.Entities.AiSectionScoreDatum", b =>
{
b.HasOne("GameDatabase.Entities.AiScoreDatum", "Parent")
.WithMany("AiSectionScoreData")
.HasForeignKey("Baid", "SongId", "Difficulty")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Parent");
});
modelBuilder.Entity("GameDatabase.Entities.Card", b =>
{
b.HasOne("GameDatabase.Entities.UserDatum", "Ba")
.WithMany()
.HasForeignKey("Baid")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Ba");
});
modelBuilder.Entity("GameDatabase.Entities.Credential", b =>
{
b.HasOne("GameDatabase.Entities.UserDatum", "Ba")
.WithMany()
.HasForeignKey("Baid")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Ba");
});
modelBuilder.Entity("GameDatabase.Entities.DanScoreDatum", b =>
{
b.HasOne("GameDatabase.Entities.UserDatum", "Ba")
.WithMany()
.HasForeignKey("Baid")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Ba");
});
modelBuilder.Entity("GameDatabase.Entities.DanStageScoreDatum", b =>
{
b.HasOne("GameDatabase.Entities.DanScoreDatum", "Parent")
.WithMany("DanStageScoreData")
.HasForeignKey("Baid", "DanId", "DanType")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Parent");
});
modelBuilder.Entity("GameDatabase.Entities.SongBestDatum", b =>
{
b.HasOne("GameDatabase.Entities.UserDatum", "Ba")
.WithMany()
.HasForeignKey("Baid")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Ba");
});
modelBuilder.Entity("GameDatabase.Entities.SongPlayDatum", b =>
{
b.HasOne("GameDatabase.Entities.UserDatum", "Ba")
.WithMany()
.HasForeignKey("Baid")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Ba");
});
modelBuilder.Entity("GameDatabase.Entities.Token", b =>
{
b.HasOne("GameDatabase.Entities.UserDatum", "Datum")
.WithMany("Tokens")
.HasForeignKey("Baid")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Datum");
});
modelBuilder.Entity("GameDatabase.Entities.AiScoreDatum", b =>
{
b.Navigation("AiSectionScoreData");
});
modelBuilder.Entity("GameDatabase.Entities.DanScoreDatum", b =>
{
b.Navigation("DanStageScoreData");
});
modelBuilder.Entity("GameDatabase.Entities.UserDatum", b =>
{
b.Navigation("Tokens");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,71 @@
using System.Text.Json;
using GameDatabase.Context;
using GameDatabase.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace GameDatabase.Migrations
{
internal record Pair(uint Baid, string TokenCountDict);
/// <inheritdoc />
public partial class SeparateTokens : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
using var context = new TaikoDbContext();
var tokenJsons = context.Database
.SqlQuery<Pair>($"SELECT Baid, TokenCountDict FROM UserData")
.ToList();
migrationBuilder.CreateTable(
name: "Tokens",
columns: table => new
{
Baid = table.Column<uint>(type: "INTEGER", nullable: false),
Id = table.Column<int>(type: "INTEGER", nullable: false),
Count = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Tokens", x => new { x.Baid, x.Id });
table.ForeignKey(
name: "FK_Tokens_UserData_Baid",
column: x => x.Baid,
principalTable: "UserData",
principalColumn: "Baid",
onDelete: ReferentialAction.Cascade);
});
foreach (var (baid, tokenCountDict) in tokenJsons)
{
var tokenDict = JsonSerializer.Deserialize<Dictionary<int, int>>(tokenCountDict);
foreach (var (key, value) in tokenDict)
{
migrationBuilder.InsertData(
table: "Tokens",
columns: new[] { "Baid", "Id", "Count" },
values: new object[] { baid, key, value });
}
}
migrationBuilder.DropColumn(
name: "TokenCountDict",
table: "UserData");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Tokens");
migrationBuilder.AddColumn<string>(
name: "TokenCountDict",
table: "UserData",
type: "TEXT",
nullable: false,
defaultValue: "");
}
}
}

View File

@ -19,7 +19,7 @@ namespace TaikoLocalServer.Migrations
modelBuilder.Entity("GameDatabase.Entities.AiScoreDatum", b =>
{
b.Property<ulong>("Baid")
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("SongId")
@ -38,7 +38,7 @@ namespace TaikoLocalServer.Migrations
modelBuilder.Entity("GameDatabase.Entities.AiSectionScoreDatum", b =>
{
b.Property<ulong>("Baid")
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("SongId")
@ -81,7 +81,7 @@ namespace TaikoLocalServer.Migrations
b.Property<string>("AccessCode")
.HasColumnType("TEXT");
b.Property<ulong>("Baid")
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.HasKey("AccessCode");
@ -93,7 +93,7 @@ namespace TaikoLocalServer.Migrations
modelBuilder.Entity("GameDatabase.Entities.Credential", b =>
{
b.Property<ulong>("Baid")
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<string>("Password")
@ -111,7 +111,7 @@ namespace TaikoLocalServer.Migrations
modelBuilder.Entity("GameDatabase.Entities.DanScoreDatum", b =>
{
b.Property<ulong>("Baid")
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("DanId")
@ -143,7 +143,7 @@ namespace TaikoLocalServer.Migrations
modelBuilder.Entity("GameDatabase.Entities.DanStageScoreDatum", b =>
{
b.Property<ulong>("Baid")
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("DanId")
@ -188,7 +188,7 @@ namespace TaikoLocalServer.Migrations
modelBuilder.Entity("GameDatabase.Entities.SongBestDatum", b =>
{
b.Property<ulong>("Baid")
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("SongId")
@ -220,7 +220,7 @@ namespace TaikoLocalServer.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<ulong>("Baid")
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("ComboCount")
@ -275,9 +275,25 @@ namespace TaikoLocalServer.Migrations
b.ToTable("SongPlayData");
});
modelBuilder.Entity("GameDatabase.Entities.Token", b =>
{
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<int>("Id")
.HasColumnType("INTEGER");
b.Property<int>("Count")
.HasColumnType("INTEGER");
b.HasKey("Baid", "Id");
b.ToTable("Tokens");
});
modelBuilder.Entity("GameDatabase.Entities.UserDatum", b =>
{
b.Property<ulong>("Baid")
b.Property<uint>("Baid")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
@ -368,10 +384,6 @@ namespace TaikoLocalServer.Migrations
b.Property<uint>("TitlePlateId")
.HasColumnType("INTEGER");
b.Property<string>("TokenCountDict")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("ToneFlgArray")
.IsRequired()
.HasColumnType("TEXT");
@ -473,6 +485,17 @@ namespace TaikoLocalServer.Migrations
b.Navigation("Ba");
});
modelBuilder.Entity("GameDatabase.Entities.Token", b =>
{
b.HasOne("GameDatabase.Entities.UserDatum", "Datum")
.WithMany("Tokens")
.HasForeignKey("Baid")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Datum");
});
modelBuilder.Entity("GameDatabase.Entities.AiScoreDatum", b =>
{
b.Navigation("AiSectionScoreData");
@ -482,6 +505,11 @@ namespace TaikoLocalServer.Migrations
{
b.Navigation("DanStageScoreData");
});
modelBuilder.Entity("GameDatabase.Entities.UserDatum", b =>
{
b.Navigation("Tokens");
});
#pragma warning restore 612, 618
}
}

View File

@ -1,4 +1,5 @@
using System.Text.Json;
using GameDatabase.Entities;
using Throw;
namespace TaikoLocalServer.Controllers.Game;
@ -23,32 +24,25 @@ public class AddTokenCountController : BaseController<AddTokenCountController>
var user = await userDatumService.GetFirstUserDatumOrNull(request.Baid);
user.ThrowIfNull($"User with baid {request.Baid} does not exist!");
var tokenCountDict = new Dictionary<uint, int>();
try
{
tokenCountDict = !string.IsNullOrEmpty(user.TokenCountDict)
? JsonSerializer.Deserialize<Dictionary<uint, int>>(user.TokenCountDict)
: new Dictionary<uint, int>();
}
catch (JsonException e)
{
Logger.LogError(e, "Parsing TokenCountDict data for user with baid {Request} failed!", request.Baid);
}
tokenCountDict.ThrowIfNull("TokenCountDict should never be null");
foreach (var addTokenCountData in request.AryAddTokenCountDatas)
{
var tokenId = addTokenCountData.TokenId;
var addTokenCount = addTokenCountData.AddTokenCount;
if (tokenCountDict.ContainsKey(tokenId))
tokenCountDict[tokenId] += addTokenCount;
var token = user.Tokens.FirstOrDefault(t => t.Id == tokenId);
if (token != null)
{
token.Count += addTokenCount;
}
else
tokenCountDict.Add(tokenId, addTokenCount);
{
user.Tokens.Add(new Token
{
Id = (int)tokenId,
Count = addTokenCount
});
}
}
user.TokenCountDict = JsonSerializer.Serialize(tokenCountDict);
await userDatumService.UpdateUserDatum(user);
var response = new AddTokenCountResponse

View File

@ -1,4 +1,5 @@
using System.Text.Json;
using GameDatabase.Entities;
using Throw;
namespace TaikoLocalServer.Controllers.Game;
@ -60,20 +61,6 @@ public class GetTokenCountController : BaseController<GetTokenCountController>
machina4TokenId
};
var tokenCountDict = new Dictionary<uint, int>();
try
{
tokenCountDict = !string.IsNullOrEmpty(user.TokenCountDict)
? JsonSerializer.Deserialize<Dictionary<uint, int>>(user.TokenCountDict)
: new Dictionary<uint, int>();
}
catch (JsonException e)
{
Logger.LogError(e, "Parsing TokenCountDict data for user with baid {Request} failed!", request.Baid);
}
tokenCountDict.ThrowIfNull("TokenCountDict should never be null");
var response = new GetTokenCountResponse
{
Result = 1
@ -83,15 +70,22 @@ public class GetTokenCountController : BaseController<GetTokenCountController>
{
if (tokenDataId <= 0) continue;
var castedTokenDataId = (uint)tokenDataId;
tokenCountDict.TryAdd(castedTokenDataId, 0);
if (user.Tokens.All(token => token.Id != castedTokenDataId))
{
user.Tokens.Add(new Token
{
Id = (int)castedTokenDataId,
Count = 0
});
}
var tokenCount = user.Tokens.First(token => token.Id == castedTokenDataId).Count;
response.AryTokenCountDatas.Add(new GetTokenCountResponse.TokenCountData
{
TokenCount = tokenCountDict[castedTokenDataId],
TokenCount = tokenCount,
TokenId = castedTokenDataId
});
}
user.TokenCountDict = JsonSerializer.Serialize(tokenCountDict);
await userDatumService.UpdateUserDatum(user);
return Ok(response);

View File

@ -43,7 +43,6 @@ public class MyDonEntryController : BaseController<MyDonEntryController>
TitleFlgArray = "[]",
CostumeFlgArray = "[[0],[0],[0],[0],[0]]",
GenericInfoFlgArray = "[]",
TokenCountDict = "{}",
UnlockedSongIdList = "[]"
};
await userDatumService.InsertUserDatum(newUser);

View File

@ -23,7 +23,7 @@ public class SongPurchaseController : BaseController<SongPurchaseController>
var user = await userDatumService.GetFirstUserDatumOrNull(request.Baid);
user.ThrowIfNull($"User with baid {request.Baid} does not exist!");
var tokenCountDict = new Dictionary<uint, int>();
/*var tokenCountDict = new Dictionary<uint, int>();
try
{
tokenCountDict = !string.IsNullOrEmpty(user.TokenCountDict)
@ -35,7 +35,7 @@ public class SongPurchaseController : BaseController<SongPurchaseController>
Logger.LogError(e, "Parsing TokenCountDict data for user with baid {Request} failed!", request.Baid);
}
tokenCountDict.ThrowIfNull("TokenCountDict should never be null");
tokenCountDict.ThrowIfNull("TokenCountDict should never be null");*/
Logger.LogInformation("Original UnlockedSongIdList: {UnlockedSongIdList}", user.UnlockedSongIdList);
@ -53,11 +53,21 @@ public class SongPurchaseController : BaseController<SongPurchaseController>
unlockedSongIdList.ThrowIfNull("UnlockedSongIdList should never be null");
if (tokenCountDict.ContainsKey(request.TokenId)) tokenCountDict[request.TokenId] -= (int)request.Price;
//if (tokenCountDict.ContainsKey(request.TokenId)) tokenCountDict[request.TokenId] -= (int)request.Price;
var token = user.Tokens.FirstOrDefault(t => t.Id == request.TokenId);
if (token is not null && token.Count >= request.Price)
{
token.Count -= (int)request.Price;
}
else
{
Logger.LogError("User with baid {Baid} does not have enough tokens to purchase song with id {SongNo}!", request.Baid, request.SongNo);
return Ok(new SongPurchaseResponse { Result = 0 });
}
if (!unlockedSongIdList.Contains(request.SongNo)) unlockedSongIdList.Add(request.SongNo);
user.TokenCountDict = JsonSerializer.Serialize(tokenCountDict);
user.UnlockedSongIdList = JsonSerializer.Serialize(unlockedSongIdList);
Logger.LogInformation("Updated UnlockedSongIdList: {UnlockedSongIdList}", user.UnlockedSongIdList);
@ -67,7 +77,7 @@ public class SongPurchaseController : BaseController<SongPurchaseController>
var response = new SongPurchaseResponse
{
Result = 1,
TokenCount = tokenCountDict[request.TokenId]
TokenCount = token.Count
};
return Ok(response);

View File

@ -19,12 +19,16 @@ public class UserDatumService : IUserDatumService
public async Task<UserDatum?> GetFirstUserDatumOrNull(uint baid)
{
return await context.UserData.FindAsync(baid);
return await context.UserData
.Include(d => d.Tokens)
.FirstOrDefaultAsync(d => d.Baid == baid);
}
public async Task<UserDatum> GetFirstUserDatumOrDefault(uint baid)
{
return await context.UserData.FindAsync(baid) ?? new UserDatum();
return await context.UserData
.Include(d => d.Tokens)
.FirstOrDefaultAsync(d => d.Baid == baid) ?? new UserDatum();
}
public async Task<List<UserDatum>> GetAllUserData()