diff --git a/GameDatabase/Entities/UserDatum.cs b/GameDatabase/Entities/UserDatum.cs index fed00bc..a39f448 100644 --- a/GameDatabase/Entities/UserDatum.cs +++ b/GameDatabase/Entities/UserDatum.cs @@ -33,5 +33,6 @@ namespace GameDatabase.Entities public int AiWinCount { get; set; } public string TokenCountDict { get; set; } = "{}"; public string UnlockedSongIdList { get; set; } = "[]"; + public bool IsAdmin { get; set; } } } \ No newline at end of file diff --git a/GameDatabase/Migrations/20231218152045_AddIsAdminToUserDatum.Designer.cs b/GameDatabase/Migrations/20231218152045_AddIsAdminToUserDatum.Designer.cs new file mode 100644 index 0000000..54a7fa9 --- /dev/null +++ b/GameDatabase/Migrations/20231218152045_AddIsAdminToUserDatum.Designer.cs @@ -0,0 +1,491 @@ +// +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("20231218152045_AddIsAdminToUserDatum")] + partial class AddIsAdminToUserDatum + { + /// + 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("Baid") + .HasColumnType("INTEGER"); + + b.Property("SongId") + .HasColumnType("INTEGER"); + + b.Property("Difficulty") + .HasColumnType("INTEGER"); + + b.Property("IsWin") + .HasColumnType("INTEGER"); + + b.HasKey("Baid", "SongId", "Difficulty"); + + b.ToTable("AiScoreData"); + }); + + modelBuilder.Entity("GameDatabase.Entities.AiSectionScoreDatum", b => + { + b.Property("Baid") + .HasColumnType("INTEGER"); + + b.Property("SongId") + .HasColumnType("INTEGER"); + + b.Property("Difficulty") + .HasColumnType("INTEGER"); + + b.Property("SectionIndex") + .HasColumnType("INTEGER"); + + b.Property("Crown") + .HasColumnType("INTEGER"); + + b.Property("DrumrollCount") + .HasColumnType("INTEGER"); + + b.Property("GoodCount") + .HasColumnType("INTEGER"); + + b.Property("IsWin") + .HasColumnType("INTEGER"); + + b.Property("MissCount") + .HasColumnType("INTEGER"); + + b.Property("OkCount") + .HasColumnType("INTEGER"); + + b.Property("Score") + .HasColumnType("INTEGER"); + + b.HasKey("Baid", "SongId", "Difficulty", "SectionIndex"); + + b.ToTable("AiSectionScoreData"); + }); + + modelBuilder.Entity("GameDatabase.Entities.Card", b => + { + b.Property("AccessCode") + .HasColumnType("TEXT"); + + b.Property("Baid") + .HasColumnType("INTEGER"); + + b.HasKey("AccessCode"); + + b.HasIndex("Baid"); + + b.ToTable("Card", (string)null); + }); + + modelBuilder.Entity("GameDatabase.Entities.Credential", b => + { + b.Property("Baid") + .HasColumnType("INTEGER"); + + b.Property("Password") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("Salt") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Baid"); + + b.ToTable("Credential", (string)null); + }); + + modelBuilder.Entity("GameDatabase.Entities.DanScoreDatum", b => + { + b.Property("Baid") + .HasColumnType("INTEGER"); + + b.Property("DanId") + .HasColumnType("INTEGER"); + + b.Property("DanType") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(1); + + b.Property("ArrivalSongCount") + .HasColumnType("INTEGER"); + + b.Property("ClearState") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(0u); + + b.Property("ComboCountTotal") + .HasColumnType("INTEGER"); + + b.Property("SoulGaugeTotal") + .HasColumnType("INTEGER"); + + b.HasKey("Baid", "DanId", "DanType"); + + b.ToTable("DanScoreData"); + }); + + modelBuilder.Entity("GameDatabase.Entities.DanStageScoreDatum", b => + { + b.Property("Baid") + .HasColumnType("INTEGER"); + + b.Property("DanId") + .HasColumnType("INTEGER"); + + b.Property("DanType") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(1); + + b.Property("SongNumber") + .HasColumnType("INTEGER"); + + b.Property("BadCount") + .HasColumnType("INTEGER"); + + b.Property("ComboCount") + .HasColumnType("INTEGER"); + + b.Property("DrumrollCount") + .HasColumnType("INTEGER"); + + b.Property("GoodCount") + .HasColumnType("INTEGER"); + + b.Property("HighScore") + .HasColumnType("INTEGER"); + + b.Property("OkCount") + .HasColumnType("INTEGER"); + + b.Property("PlayScore") + .HasColumnType("INTEGER"); + + b.Property("TotalHitCount") + .HasColumnType("INTEGER"); + + b.HasKey("Baid", "DanId", "DanType", "SongNumber"); + + b.ToTable("DanStageScoreData"); + }); + + modelBuilder.Entity("GameDatabase.Entities.SongBestDatum", b => + { + b.Property("Baid") + .HasColumnType("INTEGER"); + + b.Property("SongId") + .HasColumnType("INTEGER"); + + b.Property("Difficulty") + .HasColumnType("INTEGER"); + + b.Property("BestCrown") + .HasColumnType("INTEGER"); + + b.Property("BestRate") + .HasColumnType("INTEGER"); + + b.Property("BestScore") + .HasColumnType("INTEGER"); + + b.Property("BestScoreRank") + .HasColumnType("INTEGER"); + + b.HasKey("Baid", "SongId", "Difficulty"); + + b.ToTable("SongBestData"); + }); + + modelBuilder.Entity("GameDatabase.Entities.SongPlayDatum", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Baid") + .HasColumnType("INTEGER"); + + b.Property("ComboCount") + .HasColumnType("INTEGER"); + + b.Property("Crown") + .HasColumnType("INTEGER"); + + b.Property("Difficulty") + .HasColumnType("INTEGER"); + + b.Property("DrumrollCount") + .HasColumnType("INTEGER"); + + b.Property("GoodCount") + .HasColumnType("INTEGER"); + + b.Property("HitCount") + .HasColumnType("INTEGER"); + + b.Property("MissCount") + .HasColumnType("INTEGER"); + + b.Property("OkCount") + .HasColumnType("INTEGER"); + + b.Property("PlayTime") + .HasColumnType("datetime"); + + b.Property("Score") + .HasColumnType("INTEGER"); + + b.Property("ScoreRank") + .HasColumnType("INTEGER"); + + b.Property("ScoreRate") + .HasColumnType("INTEGER"); + + b.Property("Skipped") + .HasColumnType("INTEGER"); + + b.Property("SongId") + .HasColumnType("INTEGER"); + + b.Property("SongNumber") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("Baid"); + + b.ToTable("SongPlayData"); + }); + + modelBuilder.Entity("GameDatabase.Entities.UserDatum", b => + { + b.Property("Baid") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("AchievementDisplayDifficulty") + .HasColumnType("INTEGER"); + + b.Property("AiWinCount") + .HasColumnType("INTEGER"); + + b.Property("ColorBody") + .HasColumnType("INTEGER"); + + b.Property("ColorFace") + .HasColumnType("INTEGER"); + + b.Property("ColorLimb") + .HasColumnType("INTEGER"); + + b.Property("CostumeData") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CostumeFlgArray") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DifficultyPlayedArray") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DifficultySettingArray") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DisplayAchievement") + .HasColumnType("INTEGER"); + + b.Property("DisplayDan") + .HasColumnType("INTEGER"); + + b.Property("FavoriteSongsArray") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("GenericInfoFlgArray") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("IsAdmin") + .HasColumnType("INTEGER"); + + b.Property("IsSkipOn") + .HasColumnType("INTEGER"); + + b.Property("IsVoiceOn") + .HasColumnType("INTEGER"); + + b.Property("LastPlayDatetime") + .HasColumnType("datetime"); + + b.Property("LastPlayMode") + .HasColumnType("INTEGER"); + + b.Property("MyDonName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("MyDonNameLanguage") + .HasColumnType("INTEGER"); + + b.Property("NotesPosition") + .HasColumnType("INTEGER"); + + b.Property("OptionSetting") + .HasColumnType("INTEGER"); + + b.Property("SelectedToneId") + .HasColumnType("INTEGER"); + + b.Property("Title") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("TitleFlgArray") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("TitlePlateId") + .HasColumnType("INTEGER"); + + b.Property("TokenCountDict") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ToneFlgArray") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("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.AiScoreDatum", b => + { + b.Navigation("AiSectionScoreData"); + }); + + modelBuilder.Entity("GameDatabase.Entities.DanScoreDatum", b => + { + b.Navigation("DanStageScoreData"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/GameDatabase/Migrations/20231218152045_AddIsAdminToUserDatum.cs b/GameDatabase/Migrations/20231218152045_AddIsAdminToUserDatum.cs new file mode 100644 index 0000000..26be68b --- /dev/null +++ b/GameDatabase/Migrations/20231218152045_AddIsAdminToUserDatum.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace GameDatabase.Migrations +{ + /// + public partial class AddIsAdminToUserDatum : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "IsAdmin", + table: "UserData", + type: "INTEGER", + nullable: false, + defaultValue: false); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "IsAdmin", + table: "UserData"); + } + } +} diff --git a/GameDatabase/Migrations/TaikoDbContextModelSnapshot.cs b/GameDatabase/Migrations/TaikoDbContextModelSnapshot.cs index 4ac180c..f0e4507 100644 --- a/GameDatabase/Migrations/TaikoDbContextModelSnapshot.cs +++ b/GameDatabase/Migrations/TaikoDbContextModelSnapshot.cs @@ -326,6 +326,9 @@ namespace TaikoLocalServer.Migrations .IsRequired() .HasColumnType("TEXT"); + b.Property("IsAdmin") + .HasColumnType("INTEGER"); + b.Property("IsSkipOn") .HasColumnType("INTEGER"); diff --git a/SharedProject/Models/User.cs b/SharedProject/Models/User.cs index b59026b..2dedcc4 100644 --- a/SharedProject/Models/User.cs +++ b/SharedProject/Models/User.cs @@ -5,4 +5,6 @@ public class User public uint Baid { get; set; } public List AccessCodes { get; set; } = new(); + + public bool IsAdmin { get; set; } } \ No newline at end of file diff --git a/TaikoLocalServer/Services/CardService.cs b/TaikoLocalServer/Services/CardService.cs index 58a17de..c9b1bcf 100644 --- a/TaikoLocalServer/Services/CardService.cs +++ b/TaikoLocalServer/Services/CardService.cs @@ -28,28 +28,13 @@ public class CardService : ICardService public async Task> GetUsersFromCards() { var cardEntries = await context.Cards.ToListAsync(); - List users = new(); - var found = false; - foreach (var cardEntry in cardEntries) + var userEntries = await context.UserData.ToListAsync(); + var users = userEntries.Select(userEntry => new User { - foreach (var user in users.Where(user => user.Baid == cardEntry.Baid)) - { - user.AccessCodes.Add(cardEntry.AccessCode); - found = true; - } - - if (!found) - { - var user = new User - { - Baid = (uint)cardEntry.Baid, - AccessCodes = new List {cardEntry.AccessCode} - }; - users.Add(user); - } - - found = false; - } + Baid = (uint)userEntry.Baid, + AccessCodes = cardEntries.Where(cardEntry => cardEntry.Baid == userEntry.Baid).Select(cardEntry => cardEntry.AccessCode).ToList(), + IsAdmin = userEntry.IsAdmin + }).ToList(); return users; } diff --git a/TaikoWebUI/Pages/Users.razor b/TaikoWebUI/Pages/Users.razor index 9a1e59d..61bbc60 100644 --- a/TaikoWebUI/Pages/Users.razor +++ b/TaikoWebUI/Pages/Users.razor @@ -54,6 +54,12 @@ IconColor="@Color.Primary"> Manage Access Codes + + + Change Password + @if (LoginService.AllowUserDelete) { @@ -156,6 +162,12 @@ IconColor="@Color.Primary"> Manage Access Codes + + + Change Password + @if (LoginService.AllowUserDelete) { diff --git a/TaikoWebUI/Services/LoginService.cs b/TaikoWebUI/Services/LoginService.cs index e2b0ff4..94bd83f 100644 --- a/TaikoWebUI/Services/LoginService.cs +++ b/TaikoWebUI/Services/LoginService.cs @@ -7,8 +7,6 @@ namespace TaikoWebUI.Services; public class LoginService { - private readonly string adminPassword; - private readonly string adminUsername; public bool LoginRequired { get; } public bool OnlyAdmin { get; } private readonly int boundAccessCodeUpperLimit; @@ -21,8 +19,6 @@ public class LoginService IsLoggedIn = false; IsAdmin = false; var webUiSettings = settings.Value; - adminUsername = webUiSettings.AdminUsername; - adminPassword = webUiSettings.AdminPassword; LoginRequired = webUiSettings.LoginRequired; OnlyAdmin = webUiSettings.OnlyAdmin; boundAccessCodeUpperLimit = webUiSettings.BoundAccessCodeUpperLimit; @@ -37,24 +33,16 @@ public class LoginService public int Login(string inputCardNum, string inputPassword, DashboardResponse response) { - if (inputCardNum == adminUsername && inputPassword == adminPassword) - { - IsLoggedIn = true; - IsAdmin = true; - return 1; - } - - if (OnlyAdmin) return 0; - foreach (var user in response.Users.Where(user => user.AccessCodes.Contains(inputCardNum))) { foreach (var userCredential in response.UserCredentials.Where(userCredential => userCredential.Baid == user.Baid)) { if (userCredential.Password == "") return 4; if (ComputeHash(inputPassword, userCredential.Salt) != userCredential.Password) return 2; + IsAdmin = user.IsAdmin; + if (!IsAdmin && OnlyAdmin) return 0; IsLoggedIn = true; LoggedInUser = user; - IsAdmin = false; return 1; } } diff --git a/TaikoWebUI/Settings/WebUiSettings.cs b/TaikoWebUI/Settings/WebUiSettings.cs index 5bbf4d5..874688b 100644 --- a/TaikoWebUI/Settings/WebUiSettings.cs +++ b/TaikoWebUI/Settings/WebUiSettings.cs @@ -3,8 +3,6 @@ public class WebUiSettings { public bool LoginRequired { get; set; } - public string AdminUsername { get; set; } = string.Empty; - public string AdminPassword { get; set; } = string.Empty; public bool OnlyAdmin { get; set; } public int BoundAccessCodeUpperLimit { get; set; } public bool RegisterWithLastPlayTime { get; set; } diff --git a/TaikoWebUI/wwwroot/appsettings.json b/TaikoWebUI/wwwroot/appsettings.json index a84a7b7..5c6140f 100644 --- a/TaikoWebUI/wwwroot/appsettings.json +++ b/TaikoWebUI/wwwroot/appsettings.json @@ -1,8 +1,6 @@ { "WebUiSettings": { "LoginRequired": "false", - "AdminUserName": "admin", - "AdminPassword": "admin", "OnlyAdmin": "false", "BoundAccessCodeUpperLimit": "3", "RegisterWithLastPlayTime": "false",