From b4719a56aa9a9bdd7f37223e1152333f7229e8e6 Mon Sep 17 00:00:00 2001 From: Simon <63975668+Simyon264@users.noreply.github.com> Date: Tue, 12 Nov 2024 01:04:55 +0100 Subject: [PATCH] rawr --- ...LeaderboardPositionGeneratedAt.Designer.cs | 721 +++++++++++++++++ ...11230023_LeaderboardPositionGeneratedAt.cs | 30 + ...41111230147_LeaderboardIndexes.Designer.cs | 725 +++++++++++++++++ .../20241111230147_LeaderboardIndexes.cs | 36 + ...1234000_LeaderboardRangeOption.Designer.cs | 730 ++++++++++++++++++ .../20241111234000_LeaderboardRangeOption.cs | 38 + .../ReplayDbContextModelSnapshot.cs | 12 + .../Data/Models/LeaderboardPosition.cs | 16 +- ReplayBrowser/Pages/Leaderboard.razor | 6 +- ReplayBrowser/Services/LeaderboardService.cs | 119 +-- 10 files changed, 2376 insertions(+), 57 deletions(-) create mode 100644 ReplayBrowser/Data/Migrations/20241111230023_LeaderboardPositionGeneratedAt.Designer.cs create mode 100644 ReplayBrowser/Data/Migrations/20241111230023_LeaderboardPositionGeneratedAt.cs create mode 100644 ReplayBrowser/Data/Migrations/20241111230147_LeaderboardIndexes.Designer.cs create mode 100644 ReplayBrowser/Data/Migrations/20241111230147_LeaderboardIndexes.cs create mode 100644 ReplayBrowser/Data/Migrations/20241111234000_LeaderboardRangeOption.Designer.cs create mode 100644 ReplayBrowser/Data/Migrations/20241111234000_LeaderboardRangeOption.cs diff --git a/ReplayBrowser/Data/Migrations/20241111230023_LeaderboardPositionGeneratedAt.Designer.cs b/ReplayBrowser/Data/Migrations/20241111230023_LeaderboardPositionGeneratedAt.Designer.cs new file mode 100644 index 0000000..954cf3a --- /dev/null +++ b/ReplayBrowser/Data/Migrations/20241111230023_LeaderboardPositionGeneratedAt.Designer.cs @@ -0,0 +1,721 @@ +// +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using NpgsqlTypes; +using ReplayBrowser.Data; + +#nullable disable + +namespace Server.Migrations +{ + [DbContext(typeof(ReplayDbContext))] + [Migration("20241111230023_LeaderboardPositionGeneratedAt")] + partial class LeaderboardPositionGeneratedAt + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.2") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property>("FavoriteReplays") + .IsRequired() + .HasColumnType("integer[]"); + + b.Property("Guid") + .HasColumnType("uuid"); + + b.Property("IsAdmin") + .HasColumnType("boolean"); + + b.Property("Protected") + .HasColumnType("boolean"); + + b.Property>("SavedProfiles") + .IsRequired() + .HasColumnType("uuid[]"); + + b.Property("SettingsId") + .HasColumnType("integer"); + + b.Property("Username") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("SettingsId"); + + b.HasIndex("Username"); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.AccountSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property>("Friends") + .IsRequired() + .HasColumnType("uuid[]"); + + b.Property("RedactInformation") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("AccountSettings"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.HistoryEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("integer"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("Details") + .HasColumnType("text"); + + b.Property("Time") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.ToTable("HistoryEntry"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.Webhook", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("integer"); + + b.Property("Servers") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("Url") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.ToTable("Webhook"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.WebhookHistory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ResponseBody") + .IsRequired() + .HasColumnType("text"); + + b.Property("ResponseCode") + .HasColumnType("integer"); + + b.Property("SentAt") + .HasColumnType("timestamp with time zone"); + + b.Property("WebhookId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("WebhookId"); + + b.ToTable("WebhookHistory"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.CharacterData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CharacterName") + .IsRequired() + .HasColumnType("text"); + + b.Property("CollectedPlayerDataPlayerGuid") + .HasColumnType("uuid"); + + b.Property("LastPlayed") + .HasColumnType("timestamp with time zone"); + + b.Property("RoundsPlayed") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("CollectedPlayerDataPlayerGuid"); + + b.ToTable("CharacterData"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.CollectedPlayerData", b => + { + b.Property("PlayerGuid") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("GeneratedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsWatched") + .HasColumnType("boolean"); + + b.Property("LastSeen") + .HasColumnType("timestamp with time zone"); + + b.Property("PlayerDataId") + .HasColumnType("integer"); + + b.Property("TotalAntagRoundsPlayed") + .HasColumnType("integer"); + + b.Property("TotalEstimatedPlaytime") + .HasColumnType("interval"); + + b.Property("TotalRoundsPlayed") + .HasColumnType("integer"); + + b.HasKey("PlayerGuid"); + + b.HasIndex("PlayerDataId"); + + b.HasIndex("PlayerGuid") + .IsUnique(); + + b.ToTable("PlayerProfiles"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.GdprRequest", b => + { + b.Property("Guid") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.HasKey("Guid"); + + b.ToTable("GdprRequests"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.JobCountData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CollectedPlayerDataPlayerGuid") + .HasColumnType("uuid"); + + b.Property("JobPrototype") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastPlayed") + .HasColumnType("timestamp with time zone"); + + b.Property("RoundsPlayed") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("CollectedPlayerDataPlayerGuid"); + + b.ToTable("JobCountData"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.JobDepartment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Department") + .IsRequired() + .HasColumnType("text"); + + b.Property("Job") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Job") + .IsUnique(); + + b.ToTable("JobDepartments"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.LeaderboardDefinition", b => + { + b.Property("Name") + .HasColumnType("text"); + + b.Property("ExtraInfo") + .HasColumnType("text"); + + b.Property("NameColumn") + .IsRequired() + .HasColumnType("text"); + + b.Property("TrackedData") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Name"); + + b.ToTable("LeaderboardDefinitions"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.LeaderboardPosition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Count") + .HasColumnType("integer"); + + b.Property("GeneratedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LeaderboardDefinitionName") + .IsRequired() + .HasColumnType("text"); + + b.Property("PlayerGuid") + .HasColumnType("uuid"); + + b.Property("Position") + .HasColumnType("integer"); + + b.Property>("Servers") + .IsRequired() + .HasColumnType("text[]"); + + b.Property("Username") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("LeaderboardDefinitionName"); + + b.ToTable("Leaderboards"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Notice", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("EndDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Message") + .IsRequired() + .HasColumnType("text"); + + b.Property("StartDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Notices"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.ParsedReplay", b => + { + b.Property("Name") + .HasColumnType("text"); + + b.HasKey("Name"); + + b.ToTable("ParsedReplays"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Player", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Antag") + .HasColumnType("boolean"); + + b.Property>("AntagPrototypes") + .IsRequired() + .HasColumnType("text[]"); + + b.Property("EffectiveJobId") + .HasColumnType("integer"); + + b.Property>("JobPrototypes") + .IsRequired() + .HasColumnType("text[]"); + + b.Property("ParticipantId") + .HasColumnType("integer"); + + b.Property("PlayerIcName") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("EffectiveJobId"); + + b.HasIndex("ParticipantId"); + + b.HasIndex("PlayerIcName"); + + b.ToTable("Players"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.PlayerData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("PlayerGuid") + .HasColumnType("uuid"); + + b.Property("Username") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("PlayerData"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Replay", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Date") + .HasColumnType("timestamp with time zone"); + + b.Property("Duration") + .IsRequired() + .HasColumnType("text"); + + b.Property("EndTick") + .HasColumnType("integer"); + + b.Property("EndTime") + .IsRequired() + .HasColumnType("text"); + + b.Property("FileCount") + .HasColumnType("integer"); + + b.Property("Gamemode") + .IsRequired() + .HasColumnType("text"); + + b.Property("Link") + .IsRequired() + .HasColumnType("text"); + + b.Property("Map") + .HasColumnType("text"); + + b.Property>("Maps") + .HasColumnType("text[]"); + + b.Property("RoundEndText") + .HasColumnType("text"); + + b.Property("RoundEndTextSearchVector") + .IsRequired() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("tsvector") + .HasAnnotation("Npgsql:TsVectorConfig", "english") + .HasAnnotation("Npgsql:TsVectorProperties", new[] { "RoundEndText" }); + + b.Property("RoundId") + .HasColumnType("integer"); + + b.Property("ServerId") + .IsRequired() + .HasColumnType("text"); + + b.Property("ServerName") + .HasColumnType("text"); + + b.Property("Size") + .HasColumnType("integer"); + + b.Property("UncompressedSize") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("Gamemode"); + + b.HasIndex("Map"); + + b.HasIndex("RoundEndTextSearchVector"); + + NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex("RoundEndTextSearchVector"), "GIN"); + + b.HasIndex("ServerId"); + + b.HasIndex("ServerName"); + + b.ToTable("Replays"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.ReplayParticipant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("PlayerGuid") + .HasColumnType("uuid"); + + b.Property("ReplayId") + .HasColumnType("integer"); + + b.Property("Username") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ReplayId"); + + b.HasIndex("Username"); + + b.HasIndex("PlayerGuid", "ReplayId") + .IsUnique(); + + b.ToTable("ReplayParticipants"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.ServerToken", b => + { + b.Property("Token") + .HasColumnType("text"); + + b.HasKey("Token"); + + b.HasIndex("Token"); + + b.ToTable("ServerTokens"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.Account", b => + { + b.HasOne("ReplayBrowser.Data.Models.Account.AccountSettings", "Settings") + .WithMany() + .HasForeignKey("SettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Settings"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.HistoryEntry", b => + { + b.HasOne("ReplayBrowser.Data.Models.Account.Account", "Account") + .WithMany("History") + .HasForeignKey("AccountId"); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.Webhook", b => + { + b.HasOne("ReplayBrowser.Data.Models.Account.Account", null) + .WithMany("Webhooks") + .HasForeignKey("AccountId"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.WebhookHistory", b => + { + b.HasOne("ReplayBrowser.Data.Models.Account.Webhook", "Webhook") + .WithMany("Logs") + .HasForeignKey("WebhookId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Webhook"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.CharacterData", b => + { + b.HasOne("ReplayBrowser.Data.Models.CollectedPlayerData", null) + .WithMany("Characters") + .HasForeignKey("CollectedPlayerDataPlayerGuid"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.CollectedPlayerData", b => + { + b.HasOne("ReplayBrowser.Data.Models.PlayerData", "PlayerData") + .WithMany() + .HasForeignKey("PlayerDataId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("PlayerData"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.JobCountData", b => + { + b.HasOne("ReplayBrowser.Data.Models.CollectedPlayerData", null) + .WithMany("JobCount") + .HasForeignKey("CollectedPlayerDataPlayerGuid"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.LeaderboardPosition", b => + { + b.HasOne("ReplayBrowser.Data.Models.LeaderboardDefinition", "LeaderboardDefinition") + .WithMany() + .HasForeignKey("LeaderboardDefinitionName") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("LeaderboardDefinition"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Player", b => + { + b.HasOne("ReplayBrowser.Data.Models.JobDepartment", "EffectiveJob") + .WithMany() + .HasForeignKey("EffectiveJobId"); + + b.HasOne("ReplayBrowser.Data.Models.ReplayParticipant", "Participant") + .WithMany("Players") + .HasForeignKey("ParticipantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EffectiveJob"); + + b.Navigation("Participant"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.ReplayParticipant", b => + { + b.HasOne("ReplayBrowser.Data.Models.Replay", "Replay") + .WithMany("RoundParticipants") + .HasForeignKey("ReplayId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Replay"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.Account", b => + { + b.Navigation("History"); + + b.Navigation("Webhooks"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.Webhook", b => + { + b.Navigation("Logs"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.CollectedPlayerData", b => + { + b.Navigation("Characters"); + + b.Navigation("JobCount"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Replay", b => + { + b.Navigation("RoundParticipants"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.ReplayParticipant", b => + { + b.Navigation("Players"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ReplayBrowser/Data/Migrations/20241111230023_LeaderboardPositionGeneratedAt.cs b/ReplayBrowser/Data/Migrations/20241111230023_LeaderboardPositionGeneratedAt.cs new file mode 100644 index 0000000..95fadb0 --- /dev/null +++ b/ReplayBrowser/Data/Migrations/20241111230023_LeaderboardPositionGeneratedAt.cs @@ -0,0 +1,30 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Server.Migrations +{ + /// + public partial class LeaderboardPositionGeneratedAt : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "GeneratedAt", + table: "Leaderboards", + type: "timestamp with time zone", + nullable: false, + defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "GeneratedAt", + table: "Leaderboards"); + } + } +} diff --git a/ReplayBrowser/Data/Migrations/20241111230147_LeaderboardIndexes.Designer.cs b/ReplayBrowser/Data/Migrations/20241111230147_LeaderboardIndexes.Designer.cs new file mode 100644 index 0000000..4b5a357 --- /dev/null +++ b/ReplayBrowser/Data/Migrations/20241111230147_LeaderboardIndexes.Designer.cs @@ -0,0 +1,725 @@ +// +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using NpgsqlTypes; +using ReplayBrowser.Data; + +#nullable disable + +namespace Server.Migrations +{ + [DbContext(typeof(ReplayDbContext))] + [Migration("20241111230147_LeaderboardIndexes")] + partial class LeaderboardIndexes + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.2") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property>("FavoriteReplays") + .IsRequired() + .HasColumnType("integer[]"); + + b.Property("Guid") + .HasColumnType("uuid"); + + b.Property("IsAdmin") + .HasColumnType("boolean"); + + b.Property("Protected") + .HasColumnType("boolean"); + + b.Property>("SavedProfiles") + .IsRequired() + .HasColumnType("uuid[]"); + + b.Property("SettingsId") + .HasColumnType("integer"); + + b.Property("Username") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("SettingsId"); + + b.HasIndex("Username"); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.AccountSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property>("Friends") + .IsRequired() + .HasColumnType("uuid[]"); + + b.Property("RedactInformation") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("AccountSettings"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.HistoryEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("integer"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("Details") + .HasColumnType("text"); + + b.Property("Time") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.ToTable("HistoryEntry"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.Webhook", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("integer"); + + b.Property("Servers") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("Url") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.ToTable("Webhook"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.WebhookHistory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ResponseBody") + .IsRequired() + .HasColumnType("text"); + + b.Property("ResponseCode") + .HasColumnType("integer"); + + b.Property("SentAt") + .HasColumnType("timestamp with time zone"); + + b.Property("WebhookId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("WebhookId"); + + b.ToTable("WebhookHistory"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.CharacterData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CharacterName") + .IsRequired() + .HasColumnType("text"); + + b.Property("CollectedPlayerDataPlayerGuid") + .HasColumnType("uuid"); + + b.Property("LastPlayed") + .HasColumnType("timestamp with time zone"); + + b.Property("RoundsPlayed") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("CollectedPlayerDataPlayerGuid"); + + b.ToTable("CharacterData"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.CollectedPlayerData", b => + { + b.Property("PlayerGuid") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("GeneratedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsWatched") + .HasColumnType("boolean"); + + b.Property("LastSeen") + .HasColumnType("timestamp with time zone"); + + b.Property("PlayerDataId") + .HasColumnType("integer"); + + b.Property("TotalAntagRoundsPlayed") + .HasColumnType("integer"); + + b.Property("TotalEstimatedPlaytime") + .HasColumnType("interval"); + + b.Property("TotalRoundsPlayed") + .HasColumnType("integer"); + + b.HasKey("PlayerGuid"); + + b.HasIndex("PlayerDataId"); + + b.HasIndex("PlayerGuid") + .IsUnique(); + + b.ToTable("PlayerProfiles"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.GdprRequest", b => + { + b.Property("Guid") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.HasKey("Guid"); + + b.ToTable("GdprRequests"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.JobCountData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CollectedPlayerDataPlayerGuid") + .HasColumnType("uuid"); + + b.Property("JobPrototype") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastPlayed") + .HasColumnType("timestamp with time zone"); + + b.Property("RoundsPlayed") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("CollectedPlayerDataPlayerGuid"); + + b.ToTable("JobCountData"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.JobDepartment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Department") + .IsRequired() + .HasColumnType("text"); + + b.Property("Job") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Job") + .IsUnique(); + + b.ToTable("JobDepartments"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.LeaderboardDefinition", b => + { + b.Property("Name") + .HasColumnType("text"); + + b.Property("ExtraInfo") + .HasColumnType("text"); + + b.Property("NameColumn") + .IsRequired() + .HasColumnType("text"); + + b.Property("TrackedData") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Name"); + + b.ToTable("LeaderboardDefinitions"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.LeaderboardPosition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Count") + .HasColumnType("integer"); + + b.Property("GeneratedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LeaderboardDefinitionName") + .IsRequired() + .HasColumnType("text"); + + b.Property("PlayerGuid") + .HasColumnType("uuid"); + + b.Property("Position") + .HasColumnType("integer"); + + b.Property>("Servers") + .IsRequired() + .HasColumnType("text[]"); + + b.Property("Username") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("GeneratedAt"); + + b.HasIndex("LeaderboardDefinitionName"); + + b.HasIndex("Servers"); + + b.ToTable("Leaderboards"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Notice", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("EndDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Message") + .IsRequired() + .HasColumnType("text"); + + b.Property("StartDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Notices"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.ParsedReplay", b => + { + b.Property("Name") + .HasColumnType("text"); + + b.HasKey("Name"); + + b.ToTable("ParsedReplays"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Player", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Antag") + .HasColumnType("boolean"); + + b.Property>("AntagPrototypes") + .IsRequired() + .HasColumnType("text[]"); + + b.Property("EffectiveJobId") + .HasColumnType("integer"); + + b.Property>("JobPrototypes") + .IsRequired() + .HasColumnType("text[]"); + + b.Property("ParticipantId") + .HasColumnType("integer"); + + b.Property("PlayerIcName") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("EffectiveJobId"); + + b.HasIndex("ParticipantId"); + + b.HasIndex("PlayerIcName"); + + b.ToTable("Players"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.PlayerData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("PlayerGuid") + .HasColumnType("uuid"); + + b.Property("Username") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("PlayerData"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Replay", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Date") + .HasColumnType("timestamp with time zone"); + + b.Property("Duration") + .IsRequired() + .HasColumnType("text"); + + b.Property("EndTick") + .HasColumnType("integer"); + + b.Property("EndTime") + .IsRequired() + .HasColumnType("text"); + + b.Property("FileCount") + .HasColumnType("integer"); + + b.Property("Gamemode") + .IsRequired() + .HasColumnType("text"); + + b.Property("Link") + .IsRequired() + .HasColumnType("text"); + + b.Property("Map") + .HasColumnType("text"); + + b.Property>("Maps") + .HasColumnType("text[]"); + + b.Property("RoundEndText") + .HasColumnType("text"); + + b.Property("RoundEndTextSearchVector") + .IsRequired() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("tsvector") + .HasAnnotation("Npgsql:TsVectorConfig", "english") + .HasAnnotation("Npgsql:TsVectorProperties", new[] { "RoundEndText" }); + + b.Property("RoundId") + .HasColumnType("integer"); + + b.Property("ServerId") + .IsRequired() + .HasColumnType("text"); + + b.Property("ServerName") + .HasColumnType("text"); + + b.Property("Size") + .HasColumnType("integer"); + + b.Property("UncompressedSize") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("Gamemode"); + + b.HasIndex("Map"); + + b.HasIndex("RoundEndTextSearchVector"); + + NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex("RoundEndTextSearchVector"), "GIN"); + + b.HasIndex("ServerId"); + + b.HasIndex("ServerName"); + + b.ToTable("Replays"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.ReplayParticipant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("PlayerGuid") + .HasColumnType("uuid"); + + b.Property("ReplayId") + .HasColumnType("integer"); + + b.Property("Username") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ReplayId"); + + b.HasIndex("Username"); + + b.HasIndex("PlayerGuid", "ReplayId") + .IsUnique(); + + b.ToTable("ReplayParticipants"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.ServerToken", b => + { + b.Property("Token") + .HasColumnType("text"); + + b.HasKey("Token"); + + b.HasIndex("Token"); + + b.ToTable("ServerTokens"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.Account", b => + { + b.HasOne("ReplayBrowser.Data.Models.Account.AccountSettings", "Settings") + .WithMany() + .HasForeignKey("SettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Settings"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.HistoryEntry", b => + { + b.HasOne("ReplayBrowser.Data.Models.Account.Account", "Account") + .WithMany("History") + .HasForeignKey("AccountId"); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.Webhook", b => + { + b.HasOne("ReplayBrowser.Data.Models.Account.Account", null) + .WithMany("Webhooks") + .HasForeignKey("AccountId"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.WebhookHistory", b => + { + b.HasOne("ReplayBrowser.Data.Models.Account.Webhook", "Webhook") + .WithMany("Logs") + .HasForeignKey("WebhookId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Webhook"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.CharacterData", b => + { + b.HasOne("ReplayBrowser.Data.Models.CollectedPlayerData", null) + .WithMany("Characters") + .HasForeignKey("CollectedPlayerDataPlayerGuid"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.CollectedPlayerData", b => + { + b.HasOne("ReplayBrowser.Data.Models.PlayerData", "PlayerData") + .WithMany() + .HasForeignKey("PlayerDataId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("PlayerData"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.JobCountData", b => + { + b.HasOne("ReplayBrowser.Data.Models.CollectedPlayerData", null) + .WithMany("JobCount") + .HasForeignKey("CollectedPlayerDataPlayerGuid"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.LeaderboardPosition", b => + { + b.HasOne("ReplayBrowser.Data.Models.LeaderboardDefinition", "LeaderboardDefinition") + .WithMany() + .HasForeignKey("LeaderboardDefinitionName") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("LeaderboardDefinition"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Player", b => + { + b.HasOne("ReplayBrowser.Data.Models.JobDepartment", "EffectiveJob") + .WithMany() + .HasForeignKey("EffectiveJobId"); + + b.HasOne("ReplayBrowser.Data.Models.ReplayParticipant", "Participant") + .WithMany("Players") + .HasForeignKey("ParticipantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EffectiveJob"); + + b.Navigation("Participant"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.ReplayParticipant", b => + { + b.HasOne("ReplayBrowser.Data.Models.Replay", "Replay") + .WithMany("RoundParticipants") + .HasForeignKey("ReplayId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Replay"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.Account", b => + { + b.Navigation("History"); + + b.Navigation("Webhooks"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.Webhook", b => + { + b.Navigation("Logs"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.CollectedPlayerData", b => + { + b.Navigation("Characters"); + + b.Navigation("JobCount"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Replay", b => + { + b.Navigation("RoundParticipants"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.ReplayParticipant", b => + { + b.Navigation("Players"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ReplayBrowser/Data/Migrations/20241111230147_LeaderboardIndexes.cs b/ReplayBrowser/Data/Migrations/20241111230147_LeaderboardIndexes.cs new file mode 100644 index 0000000..e57493f --- /dev/null +++ b/ReplayBrowser/Data/Migrations/20241111230147_LeaderboardIndexes.cs @@ -0,0 +1,36 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Server.Migrations +{ + /// + public partial class LeaderboardIndexes : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateIndex( + name: "IX_Leaderboards_GeneratedAt", + table: "Leaderboards", + column: "GeneratedAt"); + + migrationBuilder.CreateIndex( + name: "IX_Leaderboards_Servers", + table: "Leaderboards", + column: "Servers"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_Leaderboards_GeneratedAt", + table: "Leaderboards"); + + migrationBuilder.DropIndex( + name: "IX_Leaderboards_Servers", + table: "Leaderboards"); + } + } +} diff --git a/ReplayBrowser/Data/Migrations/20241111234000_LeaderboardRangeOption.Designer.cs b/ReplayBrowser/Data/Migrations/20241111234000_LeaderboardRangeOption.Designer.cs new file mode 100644 index 0000000..2bf7eeb --- /dev/null +++ b/ReplayBrowser/Data/Migrations/20241111234000_LeaderboardRangeOption.Designer.cs @@ -0,0 +1,730 @@ +// +using System; +using System.Collections.Generic; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using NpgsqlTypes; +using ReplayBrowser.Data; + +#nullable disable + +namespace Server.Migrations +{ + [DbContext(typeof(ReplayDbContext))] + [Migration("20241111234000_LeaderboardRangeOption")] + partial class LeaderboardRangeOption + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.2") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.Account", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property>("FavoriteReplays") + .IsRequired() + .HasColumnType("integer[]"); + + b.Property("Guid") + .HasColumnType("uuid"); + + b.Property("IsAdmin") + .HasColumnType("boolean"); + + b.Property("Protected") + .HasColumnType("boolean"); + + b.Property>("SavedProfiles") + .IsRequired() + .HasColumnType("uuid[]"); + + b.Property("SettingsId") + .HasColumnType("integer"); + + b.Property("Username") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Guid") + .IsUnique(); + + b.HasIndex("SettingsId"); + + b.HasIndex("Username"); + + b.ToTable("Accounts"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.AccountSettings", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property>("Friends") + .IsRequired() + .HasColumnType("uuid[]"); + + b.Property("RedactInformation") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.ToTable("AccountSettings"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.HistoryEntry", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("integer"); + + b.Property("Action") + .IsRequired() + .HasColumnType("text"); + + b.Property("Details") + .HasColumnType("text"); + + b.Property("Time") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.ToTable("HistoryEntry"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.Webhook", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AccountId") + .HasColumnType("integer"); + + b.Property("Servers") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .HasColumnType("smallint"); + + b.Property("Url") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("AccountId"); + + b.ToTable("Webhook"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.WebhookHistory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ResponseBody") + .IsRequired() + .HasColumnType("text"); + + b.Property("ResponseCode") + .HasColumnType("integer"); + + b.Property("SentAt") + .HasColumnType("timestamp with time zone"); + + b.Property("WebhookId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("WebhookId"); + + b.ToTable("WebhookHistory"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.CharacterData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CharacterName") + .IsRequired() + .HasColumnType("text"); + + b.Property("CollectedPlayerDataPlayerGuid") + .HasColumnType("uuid"); + + b.Property("LastPlayed") + .HasColumnType("timestamp with time zone"); + + b.Property("RoundsPlayed") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("CollectedPlayerDataPlayerGuid"); + + b.ToTable("CharacterData"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.CollectedPlayerData", b => + { + b.Property("PlayerGuid") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("GeneratedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("IsWatched") + .HasColumnType("boolean"); + + b.Property("LastSeen") + .HasColumnType("timestamp with time zone"); + + b.Property("PlayerDataId") + .HasColumnType("integer"); + + b.Property("TotalAntagRoundsPlayed") + .HasColumnType("integer"); + + b.Property("TotalEstimatedPlaytime") + .HasColumnType("interval"); + + b.Property("TotalRoundsPlayed") + .HasColumnType("integer"); + + b.HasKey("PlayerGuid"); + + b.HasIndex("PlayerDataId"); + + b.HasIndex("PlayerGuid") + .IsUnique(); + + b.ToTable("PlayerProfiles"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.GdprRequest", b => + { + b.Property("Guid") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.HasKey("Guid"); + + b.ToTable("GdprRequests"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.JobCountData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CollectedPlayerDataPlayerGuid") + .HasColumnType("uuid"); + + b.Property("JobPrototype") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastPlayed") + .HasColumnType("timestamp with time zone"); + + b.Property("RoundsPlayed") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("CollectedPlayerDataPlayerGuid"); + + b.ToTable("JobCountData"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.JobDepartment", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Department") + .IsRequired() + .HasColumnType("text"); + + b.Property("Job") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Job") + .IsUnique(); + + b.ToTable("JobDepartments"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.LeaderboardDefinition", b => + { + b.Property("Name") + .HasColumnType("text"); + + b.Property("ExtraInfo") + .HasColumnType("text"); + + b.Property("NameColumn") + .IsRequired() + .HasColumnType("text"); + + b.Property("TrackedData") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Name"); + + b.ToTable("LeaderboardDefinitions"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.LeaderboardPosition", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Count") + .HasColumnType("integer"); + + b.Property("GeneratedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("LeaderboardDefinitionName") + .IsRequired() + .HasColumnType("text"); + + b.Property("PlayerGuid") + .HasColumnType("uuid"); + + b.Property("Position") + .HasColumnType("integer"); + + b.Property("RangeOption") + .HasColumnType("integer"); + + b.Property>("Servers") + .IsRequired() + .HasColumnType("text[]"); + + b.Property("Username") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("GeneratedAt"); + + b.HasIndex("LeaderboardDefinitionName"); + + b.HasIndex("RangeOption"); + + b.HasIndex("Servers"); + + b.ToTable("Leaderboards"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Notice", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("EndDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Message") + .IsRequired() + .HasColumnType("text"); + + b.Property("StartDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Notices"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.ParsedReplay", b => + { + b.Property("Name") + .HasColumnType("text"); + + b.HasKey("Name"); + + b.ToTable("ParsedReplays"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Player", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Antag") + .HasColumnType("boolean"); + + b.Property>("AntagPrototypes") + .IsRequired() + .HasColumnType("text[]"); + + b.Property("EffectiveJobId") + .HasColumnType("integer"); + + b.Property>("JobPrototypes") + .IsRequired() + .HasColumnType("text[]"); + + b.Property("ParticipantId") + .HasColumnType("integer"); + + b.Property("PlayerIcName") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("EffectiveJobId"); + + b.HasIndex("ParticipantId"); + + b.HasIndex("PlayerIcName"); + + b.ToTable("Players"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.PlayerData", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("PlayerGuid") + .HasColumnType("uuid"); + + b.Property("Username") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("PlayerData"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Replay", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Date") + .HasColumnType("timestamp with time zone"); + + b.Property("Duration") + .IsRequired() + .HasColumnType("text"); + + b.Property("EndTick") + .HasColumnType("integer"); + + b.Property("EndTime") + .IsRequired() + .HasColumnType("text"); + + b.Property("FileCount") + .HasColumnType("integer"); + + b.Property("Gamemode") + .IsRequired() + .HasColumnType("text"); + + b.Property("Link") + .IsRequired() + .HasColumnType("text"); + + b.Property("Map") + .HasColumnType("text"); + + b.Property>("Maps") + .HasColumnType("text[]"); + + b.Property("RoundEndText") + .HasColumnType("text"); + + b.Property("RoundEndTextSearchVector") + .IsRequired() + .ValueGeneratedOnAddOrUpdate() + .HasColumnType("tsvector") + .HasAnnotation("Npgsql:TsVectorConfig", "english") + .HasAnnotation("Npgsql:TsVectorProperties", new[] { "RoundEndText" }); + + b.Property("RoundId") + .HasColumnType("integer"); + + b.Property("ServerId") + .IsRequired() + .HasColumnType("text"); + + b.Property("ServerName") + .HasColumnType("text"); + + b.Property("Size") + .HasColumnType("integer"); + + b.Property("UncompressedSize") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("Gamemode"); + + b.HasIndex("Map"); + + b.HasIndex("RoundEndTextSearchVector"); + + NpgsqlIndexBuilderExtensions.HasMethod(b.HasIndex("RoundEndTextSearchVector"), "GIN"); + + b.HasIndex("ServerId"); + + b.HasIndex("ServerName"); + + b.ToTable("Replays"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.ReplayParticipant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("PlayerGuid") + .HasColumnType("uuid"); + + b.Property("ReplayId") + .HasColumnType("integer"); + + b.Property("Username") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("ReplayId"); + + b.HasIndex("Username"); + + b.HasIndex("PlayerGuid", "ReplayId") + .IsUnique(); + + b.ToTable("ReplayParticipants"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.ServerToken", b => + { + b.Property("Token") + .HasColumnType("text"); + + b.HasKey("Token"); + + b.HasIndex("Token"); + + b.ToTable("ServerTokens"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.Account", b => + { + b.HasOne("ReplayBrowser.Data.Models.Account.AccountSettings", "Settings") + .WithMany() + .HasForeignKey("SettingsId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Settings"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.HistoryEntry", b => + { + b.HasOne("ReplayBrowser.Data.Models.Account.Account", "Account") + .WithMany("History") + .HasForeignKey("AccountId"); + + b.Navigation("Account"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.Webhook", b => + { + b.HasOne("ReplayBrowser.Data.Models.Account.Account", null) + .WithMany("Webhooks") + .HasForeignKey("AccountId"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.WebhookHistory", b => + { + b.HasOne("ReplayBrowser.Data.Models.Account.Webhook", "Webhook") + .WithMany("Logs") + .HasForeignKey("WebhookId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Webhook"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.CharacterData", b => + { + b.HasOne("ReplayBrowser.Data.Models.CollectedPlayerData", null) + .WithMany("Characters") + .HasForeignKey("CollectedPlayerDataPlayerGuid"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.CollectedPlayerData", b => + { + b.HasOne("ReplayBrowser.Data.Models.PlayerData", "PlayerData") + .WithMany() + .HasForeignKey("PlayerDataId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("PlayerData"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.JobCountData", b => + { + b.HasOne("ReplayBrowser.Data.Models.CollectedPlayerData", null) + .WithMany("JobCount") + .HasForeignKey("CollectedPlayerDataPlayerGuid"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.LeaderboardPosition", b => + { + b.HasOne("ReplayBrowser.Data.Models.LeaderboardDefinition", "LeaderboardDefinition") + .WithMany() + .HasForeignKey("LeaderboardDefinitionName") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("LeaderboardDefinition"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Player", b => + { + b.HasOne("ReplayBrowser.Data.Models.JobDepartment", "EffectiveJob") + .WithMany() + .HasForeignKey("EffectiveJobId"); + + b.HasOne("ReplayBrowser.Data.Models.ReplayParticipant", "Participant") + .WithMany("Players") + .HasForeignKey("ParticipantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EffectiveJob"); + + b.Navigation("Participant"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.ReplayParticipant", b => + { + b.HasOne("ReplayBrowser.Data.Models.Replay", "Replay") + .WithMany("RoundParticipants") + .HasForeignKey("ReplayId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Replay"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.Account", b => + { + b.Navigation("History"); + + b.Navigation("Webhooks"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Account.Webhook", b => + { + b.Navigation("Logs"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.CollectedPlayerData", b => + { + b.Navigation("Characters"); + + b.Navigation("JobCount"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.Replay", b => + { + b.Navigation("RoundParticipants"); + }); + + modelBuilder.Entity("ReplayBrowser.Data.Models.ReplayParticipant", b => + { + b.Navigation("Players"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/ReplayBrowser/Data/Migrations/20241111234000_LeaderboardRangeOption.cs b/ReplayBrowser/Data/Migrations/20241111234000_LeaderboardRangeOption.cs new file mode 100644 index 0000000..6ee01dc --- /dev/null +++ b/ReplayBrowser/Data/Migrations/20241111234000_LeaderboardRangeOption.cs @@ -0,0 +1,38 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Server.Migrations +{ + /// + public partial class LeaderboardRangeOption : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "RangeOption", + table: "Leaderboards", + type: "integer", + nullable: false, + defaultValue: 0); + + migrationBuilder.CreateIndex( + name: "IX_Leaderboards_RangeOption", + table: "Leaderboards", + column: "RangeOption"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_Leaderboards_RangeOption", + table: "Leaderboards"); + + migrationBuilder.DropColumn( + name: "RangeOption", + table: "Leaderboards"); + } + } +} diff --git a/ReplayBrowser/Data/Migrations/ReplayDbContextModelSnapshot.cs b/ReplayBrowser/Data/Migrations/ReplayDbContextModelSnapshot.cs index 7d12d25..d3bd0e6 100644 --- a/ReplayBrowser/Data/Migrations/ReplayDbContextModelSnapshot.cs +++ b/ReplayBrowser/Data/Migrations/ReplayDbContextModelSnapshot.cs @@ -333,6 +333,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Count") .HasColumnType("integer"); + b.Property("GeneratedAt") + .HasColumnType("timestamp with time zone"); + b.Property("LeaderboardDefinitionName") .IsRequired() .HasColumnType("text"); @@ -343,6 +346,9 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Property("Position") .HasColumnType("integer"); + b.Property("RangeOption") + .HasColumnType("integer"); + b.Property>("Servers") .IsRequired() .HasColumnType("text[]"); @@ -353,8 +359,14 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasKey("Id"); + b.HasIndex("GeneratedAt"); + b.HasIndex("LeaderboardDefinitionName"); + b.HasIndex("RangeOption"); + + b.HasIndex("Servers"); + b.ToTable("Leaderboards"); }); diff --git a/ReplayBrowser/Data/Models/LeaderboardPosition.cs b/ReplayBrowser/Data/Models/LeaderboardPosition.cs index b01e175..e506b93 100644 --- a/ReplayBrowser/Data/Models/LeaderboardPosition.cs +++ b/ReplayBrowser/Data/Models/LeaderboardPosition.cs @@ -1,5 +1,6 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; +using ReplayBrowser.Models; namespace ReplayBrowser.Data.Models; @@ -11,6 +12,7 @@ public class LeaderboardPosition : IEntityTypeConfiguration /// The servers that this position is for. /// public required List Servers { get; set; } = null!; + public required RangeOption RangeOption { get; set; } = RangeOption.AllTime; /// /// The number next to the position. For example "most times played" would be a count of how many times the player has played. @@ -32,12 +34,11 @@ public class LeaderboardPosition : IEntityTypeConfiguration /// public string Username { get; set; } = null!; + public DateTime GeneratedAt { get; set; } = DateTime.UtcNow; public string LeaderboardDefinitionName { get; set; } = null!; public LeaderboardDefinition LeaderboardDefinition { get; set; } = null!; - - public void Configure(EntityTypeBuilder builder) { builder.HasOne(lp => lp.LeaderboardDefinition) @@ -45,10 +46,19 @@ public void Configure(EntityTypeBuilder builder) .HasForeignKey(lp => lp.LeaderboardDefinitionName); builder.HasKey(x => x.Id); - builder.Property(x => x.Servers).IsRequired(); + builder.Property(x => x.Servers) + .IsRequired(); + builder.Property(x => x.Count).IsRequired(); builder.Property(x => x.Position).IsRequired(); builder.Property(x => x.PlayerGuid).IsRequired(false); builder.Property(x => x.Username).IsRequired(); + builder.Property(x => x.GeneratedAt).IsRequired(); + builder.Property(x => x.RangeOption).IsRequired(); + + builder.HasIndex(x => x.Servers); + builder.HasIndex(x => x.LeaderboardDefinitionName); + builder.HasIndex(x => x.GeneratedAt); + builder.HasIndex(x => x.RangeOption); } } \ No newline at end of file diff --git a/ReplayBrowser/Pages/Leaderboard.razor b/ReplayBrowser/Pages/Leaderboard.razor index d1d2547..bdc12b5 100644 --- a/ReplayBrowser/Pages/Leaderboard.razor +++ b/ReplayBrowser/Pages/Leaderboard.razor @@ -114,7 +114,7 @@ else
- @if(LeaderboardData.Length == 0) + @if(!LeaderboardData.Any()) {