Skip to content

Commit

Permalink
DB leaderboards (#66)
Browse files Browse the repository at this point in the history
* DB leaderboards initial commit

* Clarify message

* uuuhhh AMONG US
  • Loading branch information
Simyon264 authored Nov 11, 2024
1 parent 6896760 commit a965fbf
Show file tree
Hide file tree
Showing 9 changed files with 1,177 additions and 84 deletions.

Large diffs are not rendered by default.

70 changes: 70 additions & 0 deletions ReplayBrowser/Data/Migrations/20241111013501_DbLeaderboards.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;

#nullable disable

namespace Server.Migrations
{
/// <inheritdoc />
public partial class DbLeaderboards : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "LeaderboardDefinitions",
columns: table => new
{
Name = table.Column<string>(type: "text", nullable: false),
TrackedData = table.Column<string>(type: "text", nullable: false),
ExtraInfo = table.Column<string>(type: "text", nullable: true),
NameColumn = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_LeaderboardDefinitions", x => x.Name);
});

migrationBuilder.CreateTable(
name: "Leaderboards",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Servers = table.Column<List<string>>(type: "text[]", nullable: false),
Count = table.Column<int>(type: "integer", nullable: false),
Position = table.Column<int>(type: "integer", nullable: false),
PlayerGuid = table.Column<Guid>(type: "uuid", nullable: true),
Username = table.Column<string>(type: "text", nullable: false),
LeaderboardDefinitionName = table.Column<string>(type: "text", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Leaderboards", x => x.Id);
table.ForeignKey(
name: "FK_Leaderboards_LeaderboardDefinitions_LeaderboardDefinitionNa~",
column: x => x.LeaderboardDefinitionName,
principalTable: "LeaderboardDefinitions",
principalColumn: "Name",
onDelete: ReferentialAction.Cascade);
});

migrationBuilder.CreateIndex(
name: "IX_Leaderboards_LeaderboardDefinitionName",
table: "Leaderboards",
column: "LeaderboardDefinitionName");
}

/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Leaderboards");

migrationBuilder.DropTable(
name: "LeaderboardDefinitions");
}
}
}
68 changes: 68 additions & 0 deletions ReplayBrowser/Data/Migrations/ReplayDbContextModelSnapshot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,63 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.ToTable("JobDepartments");
});

modelBuilder.Entity("ReplayBrowser.Data.Models.LeaderboardDefinition", b =>
{
b.Property<string>("Name")
.HasColumnType("text");

b.Property<string>("ExtraInfo")
.HasColumnType("text");

b.Property<string>("NameColumn")
.IsRequired()
.HasColumnType("text");

b.Property<string>("TrackedData")
.IsRequired()
.HasColumnType("text");

b.HasKey("Name");

b.ToTable("LeaderboardDefinitions");
});

modelBuilder.Entity("ReplayBrowser.Data.Models.LeaderboardPosition", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");

NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));

b.Property<int>("Count")
.HasColumnType("integer");

b.Property<string>("LeaderboardDefinitionName")
.IsRequired()
.HasColumnType("text");

b.Property<Guid?>("PlayerGuid")
.HasColumnType("uuid");

b.Property<int>("Position")
.HasColumnType("integer");

b.Property<List<string>>("Servers")
.IsRequired()
.HasColumnType("text[]");

b.Property<string>("Username")
.IsRequired()
.HasColumnType("text");

b.HasKey("Id");

b.HasIndex("LeaderboardDefinitionName");

b.ToTable("Leaderboards");
});

modelBuilder.Entity("ReplayBrowser.Data.Models.Notice", b =>
{
b.Property<int?>("Id")
Expand Down Expand Up @@ -585,6 +642,17 @@ protected override void BuildModel(ModelBuilder modelBuilder)
.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")
Expand Down
27 changes: 27 additions & 0 deletions ReplayBrowser/Data/Models/LeaderboardDefinition.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace ReplayBrowser.Data.Models;

public class LeaderboardDefinition : IEntityTypeConfiguration<LeaderboardDefinition>
{
public required string Name { get; set; }

/// <summary>
/// The text that will appear for the "Count" column.
/// </summary>
public required string TrackedData { get; set; }

/// <summary>
/// Will be displayed in a small font below the name.
/// </summary>
public string? ExtraInfo { get; set; }
public string NameColumn { get; set; } = "Player Name";

public void Configure(EntityTypeBuilder<LeaderboardDefinition> builder)
{
builder.HasKey(x => x.Name);
builder.Property(x => x.TrackedData).IsRequired();
builder.Property(x => x.NameColumn).IsRequired();
}
}
54 changes: 54 additions & 0 deletions ReplayBrowser/Data/Models/LeaderboardPosition.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace ReplayBrowser.Data.Models;

public class LeaderboardPosition : IEntityTypeConfiguration<LeaderboardPosition>
{
public int Id { get; set; }

/// <summary>
/// The servers that this position is for.
/// </summary>
public required List<string> Servers { get; set; } = null!;

/// <summary>
/// The number next to the position. For example "most times played" would be a count of how many times the player has played.
/// </summary>
public required int Count { get; set; }

/// <summary>
/// The position of the player in the leaderboard.
/// </summary>
public int Position { get; set; }

/// <summary>
/// The GUID of the player. If null, position is not for a player, but rather a general statistic.
/// </summary>
public Guid? PlayerGuid { get; set; }

/// <summary>
/// The display value of the player or statistic.
/// </summary>
public string Username { get; set; } = null!;


public string LeaderboardDefinitionName { get; set; } = null!;
public LeaderboardDefinition LeaderboardDefinition { get; set; } = null!;



public void Configure(EntityTypeBuilder<LeaderboardPosition> builder)
{
builder.HasOne(lp => lp.LeaderboardDefinition)
.WithMany()
.HasForeignKey(lp => lp.LeaderboardDefinitionName);

builder.HasKey(x => x.Id);
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();
}
}
3 changes: 3 additions & 0 deletions ReplayBrowser/Data/ReplayDbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
public DbSet<ReplayParticipant> ReplayParticipants { get; set; }

public DbSet<ServerToken> ServerTokens { get; set; }

public DbSet<LeaderboardPosition> Leaderboards { get; set; }
public DbSet<LeaderboardDefinition> LeaderboardDefinitions { get; set; }
}
7 changes: 0 additions & 7 deletions ReplayBrowser/Models/LeaderboardData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,6 @@

namespace ReplayBrowser.Models;

public class LeaderboardData
{
public bool IsCache { get; set; } = false;

public List<Leaderboard> Leaderboards { get; set; } = null!;
}

public class PlayerCount
{
public PlayerData? Player { get; set; }
Expand Down
24 changes: 20 additions & 4 deletions ReplayBrowser/Pages/Leaderboard.razor
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@page "/leaderboard"
@using Humanizer
@using Microsoft.AspNetCore.Components.Authorization
@using ReplayBrowser.Models
@using ReplayBrowser.Services
Expand All @@ -20,6 +21,14 @@

<PageTitle>Leaderboard</PageTitle>
<h4>Leaderboards</h4>
<em>Leaderboards update every 24 hours.</em>
@if(LeaderboardService.IsUpdating) {
<div class="alert alert-warning" role="alert">
<p>The leaderboards are currently updating. This may take a while. Please be patient.</p>
<em>Update started: @LeaderboardService.UpdateStarted.Humanize(utcDate: true). Current progress: @LeaderboardService.UpdateProgress / @LeaderboardService.UpdateTotal</em>
</div>
}

@if(RequestedPrivate)
{
<div class="alert alert-danger" role="alert">
Expand Down Expand Up @@ -105,7 +114,14 @@ else

<hr/>

@foreach (var leaderboard in LeaderboardData.Leaderboards)
@if(LeaderboardData.Length == 0)
{
<div class="alert alert-warning" role="alert">
<p>No data was found for the selected servers and time range. Data is probably still collected and calculated. Please try again later. This will take a long time.</p>
</div>
}

@foreach (var leaderboard in LeaderboardData)
{
<h4>@leaderboard.Name</h4>
if (leaderboard.ExtraInfo != null)
Expand Down Expand Up @@ -233,7 +249,7 @@ else

@code{
private bool IsLoading { get; set; } = true;
private LeaderboardData? LeaderboardData { get; set; } = null;
private Models.Leaderboard[]? LeaderboardData { get; set; } = null;
private bool RequestedPrivate { get; set; } = false;

protected override async Task OnInitializedAsync()
Expand Down Expand Up @@ -267,7 +283,7 @@ else
}
}

LeaderboardData? leaderboard = null;
Models.Leaderboard[]? leaderboard = null;
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
try
{
Expand All @@ -279,7 +295,7 @@ else
}

var selectedServersArray = selectedServers.Split(',');
leaderboard = await LeaderboardService.GetLeaderboard(timeRangeEnum, username, selectedServersArray, authState, entries);
leaderboard = await LeaderboardService.GetLeaderboards(timeRangeEnum, username, selectedServersArray, authState, entries);
}
catch (UnauthorizedAccessException)
{
Expand Down
Loading

0 comments on commit a965fbf

Please sign in to comment.