diff --git a/Plugins/Stats/Helpers/StatManager.cs b/Plugins/Stats/Helpers/StatManager.cs index 564fd5322..05c046488 100644 --- a/Plugins/Stats/Helpers/StatManager.cs +++ b/Plugins/Stats/Helpers/StatManager.cs @@ -51,83 +51,78 @@ namespace IW4MAdmin.Plugins.Stats.Helpers context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; var thirtyDaysAgo = DateTime.UtcNow.AddMonths(-1); - var iqClientIds = (from stat in context.Set() + var iqClientRatings = (from rating in context.Set() #if !DEBUG - .Where(s => s.TimePlayed > 3600) - .Where(s => s.EloRating > 60.0) + where rating.RatingHistory.Client.TotalConnectionTime > 3600 #endif - where stat.Client.Level != Player.Permission.Banned - where stat.Client.LastConnection >= thirtyDaysAgo - - group stat by stat.ClientId into sj - let performance = sj.Sum(s => (s.EloRating + s.Skill) * s.TimePlayed) / sj.Sum(st => st.TimePlayed) - orderby performance - select new - { - // sj.First().Client.CurrentAlias.Name, - sj.First().Client.ClientId, - Skill = sj.Select(s => s.Skill) - }) - /* - join averageStats in context.Set().Include(c => c.Ratings) - on stat.ClientId equals averageStats.ClientId - where averageStats.Ratings.Count > 0 - group new { stat, averageStats } by averageStats.ClientId into avg - orderby avg.Select(c => c.averageStats.Ratings.OrderByDescending(r => r.RatingId).First().Performance).First() - select new - { - avg.First().stat.Client.CurrentAlias.Name,//sj.Select(c => c.Client.CurrentAlias.Name), - avg.First().stat.ClientId,//sj.First().ClientId, - avg.First().stat.Kills,//Kills = sj.Select(s => s.Kills), - avg.First().stat.Deaths,//Deaths = sj.Select(s => s.Deaths), - avg.First().stat.Performance,//Performance = sj.Select(c => new { c.Performance, c.TimePlayed }), - // KDR = stat.Kills / stat.Deaths,//KDR = sj.Select(c => new { KDR = c.Kills / (double)c.Deaths, c.TimePlayed }), - //TotalPlayTime = sj.Select(c => c.TimePlayed), - avg.First().stat.Client.LastConnection,//sj.First().Client.LastConnection, - avg.First().stat.Client.TotalConnectionTime,//sj.First().Client.TotalConnectionTime, - avg.First().stat.TimePlayed, - RatingId = 0 - // todo: eventually replace this in favor of joining - //AverageHistory = context.Set().SingleOrDefault(r => r.ClientId == stat.ClientId) - })*/ + where rating.RatingHistory.Client.Level != Player.Permission.Banned + where rating.RatingHistory.Client.LastConnection > thirtyDaysAgo + where rating.Newest + where rating.ServerId == null + orderby rating.Performance descending + select new + { + Ratings = rating.RatingHistory.Ratings.Where(r => r.ServerId == null), + rating.RatingHistory.ClientId, + rating.RatingHistory.Client.CurrentAlias.Name, + rating.RatingHistory.Client.LastConnection, + rating.RatingHistory.Client.TotalConnectionTime, + rating.Performance, + }) .Skip(start) .Take(count); - var stats = await iqClientIds.ToListAsync(); + var clientRatings = await iqClientRatings.ToListAsync(); - var groupedSelection = stats.GroupBy(c => c.ClientId).Select(s => - new TopStatsInfo() + var clientIds = clientRatings.GroupBy(r => r.ClientId).Select(r => r.First().ClientId).ToList(); + + var iqStatsInfo = (from stat in context.Set() + where clientIds.Contains(stat.ClientId) + select new + { + stat.ClientId, + stat.Kills, + stat.Deaths, + stat.TimePlayed, + }); + + var statList = await iqStatsInfo.ToListAsync(); + var topPlayers = statList.GroupBy(s => s.ClientId) + .Select(s => new { - /* Name = s.First().Name, - // weighted based on time played - Performance = s.OrderByDescending(r => r.RatingId).First().Performance, - // ditto - KDR = s.First().Deaths == 0 ? s.First().Kills : (double)s.First().Kills / s.First().Deaths, - ClientId = s.First().ClientId, - Deaths = s.First().Deaths, - Kills = s.First().Kills, - LastSeen = Utilities.GetTimePassed(s.First().LastConnection, false), - TimePlayed = Math.Round(s.First().TotalConnectionTime / 3600.0, 1).ToString("#,##0"), - / PerformanceHistory = s.AverageHistory == null || s.AverageHistory?.Ratings.Count < 2 ? - new List() - { - s.Performance, - s.Performance - } : - s.AverageHistory.Ratings.Select(r => Math.Round(r.Performance, 1)).ToList()*/ + s.First().ClientId, + Kills = s.Sum(c => c.Kills), + Deaths = s.Sum(c => c.Deaths), + KDR = s.Sum(c => (c.Kills / (double)(c.Deaths == 0 ? 1 : c.Deaths)) * c.TimePlayed) / s.Sum(c => c.TimePlayed) }); - var statList = groupedSelection.OrderByDescending(s => s.Performance).ToList(); + var clientRatingsDict = clientRatings.ToDictionary(r => r.ClientId); + var finished = topPlayers.Select(s => new TopStatsInfo() + { + ClientId = s.ClientId, + Deaths = s.Deaths, + Kills = s.Kills, + KDR = Math.Round(s.KDR, 2), + LastSeen = Utilities.GetTimePassed(clientRatingsDict[s.ClientId].LastConnection, false), + Name = clientRatingsDict[s.ClientId].Name, + Performance = Math.Round(clientRatingsDict[s.ClientId].Performance, 2), + PerformanceHistory = clientRatingsDict[s.ClientId].Ratings.Count() > 1 ? + clientRatingsDict[s.ClientId].Ratings.Select(r => r.Performance).ToList() : + new List() { clientRatingsDict[s.ClientId].Performance, clientRatingsDict[s.ClientId].Performance }, + TimePlayed = Math.Round(clientRatingsDict[s.ClientId].TotalConnectionTime / 3600.0, 1).ToString("#,##0"), + }) + .OrderByDescending(r => r.Performance) + .ToList(); // set the ranking numerically int i = start + 1; - foreach (var stat in statList) + foreach (var stat in finished) { stat.Ranking = i; i++; } - return statList; + return finished; } } @@ -590,18 +585,13 @@ namespace IW4MAdmin.Plugins.Stats.Helpers using (var ctx = new DatabaseContext()) { - // select the individual history for current server - var iqIndividualStatHistory = from statHistory in ctx.Set() - where statHistory.ClientId == client.ClientId - where statHistory.ServerId == clientStats.ServerId - select statHistory; + // select the rating history for client + var iqClientHistory = from history in ctx.Set() + .Include(h => h.Ratings) + where history.ClientId == client.ClientId + select history; - // select the average history for current client - var iqAverageHistory = from stat in ctx.Set() - where stat.ClientId == client.ClientId - select stat; - - // select all stats for current client + // select all performance & time played for current client var iqClientStats = from stats in ctx.Set() where stats.ClientId == client.ClientId where stats.ServerId != clientStats.ServerId @@ -611,93 +601,107 @@ namespace IW4MAdmin.Plugins.Stats.Helpers stats.TimePlayed }; + // get the client ratings + var clientHistory = await iqClientHistory + .FirstOrDefaultAsync() ?? new EFClientRatingHistory() + { + Active = true, + ClientId = client.ClientId, + Ratings = new List() + }; + + if (clientHistory.RatingHistoryId == 0) + { + ctx.Add(clientHistory); + } + + else + { + ctx.Update(clientHistory); + } + // get the client ranking for the current server - int individualClientRanking = await ctx.Set() - .Where(c => c.ClientId != client.ClientId) + int individualClientRanking = await ctx.Set() .Where(c => c.ServerId == clientStats.ServerId) - .Where(c => c.Ratings.OrderByDescending(r => r.RatingId).FirstOrDefault().Performance > clientStats.Performance) + .Where(c => c.RatingHistory.ClientId != client.ClientId) + .Where(r => r.Newest) + .Where(c => c.Performance > clientStats.Performance) .CountAsync() + 1; - var currentServerHistory = await iqIndividualStatHistory - .Include(r => r.Ratings) - .FirstOrDefaultAsync() ?? new EFClientStatHistory() - { - Active = true, - ClientId = client.ClientId, - Ratings = new List(), - ServerId = clientStats.ServerId - }; - - var averageHistory = await iqAverageHistory - .Include(r => r.Ratings) - .FirstOrDefaultAsync() ?? new EFClientAverageStatHistory() - { - ClientId = client.ClientId, - Ratings = new List(), - Active = true, - }; - - if (currentServerHistory.StatHistoryId == 0) + // limit max history per server to 30 + if (clientHistory.Ratings.Count(r => r.ServerId == clientStats.ServerId) >= 30) { - ctx.Add(currentServerHistory); + var ratingToRemove = clientHistory.Ratings.First(r => r.ServerId == clientStats.ServerId); + ctx.Entry(ratingToRemove).State = EntityState.Deleted; + clientHistory.Ratings.Remove(ratingToRemove); } - else + // set the previous newest to false + var ratingToUnsetNewest = clientHistory.Ratings.LastOrDefault(r => r.ServerId == clientStats.ServerId); + if (ratingToUnsetNewest != null) { - ctx.Update(currentServerHistory); + ctx.Entry(ratingToUnsetNewest).State = EntityState.Modified; + ratingToUnsetNewest.Newest = false; } - if (averageHistory.Ratings.Count == 0) - { - ctx.Add(averageHistory); - } - - else - { - ctx.Update(averageHistory); - } - - if (currentServerHistory.Ratings.Count > 30) - { - ctx.Entry(currentServerHistory.Ratings.First()).State = EntityState.Deleted; - currentServerHistory.Ratings.Remove(currentServerHistory.Ratings.First()); - } - - currentServerHistory.Ratings.Add(new EFRating() + // add new rating for current server + clientHistory.Ratings.Add(new EFRating() { Performance = clientStats.Performance, Ranking = individualClientRanking, Active = true, - ClientId = client.ClientId, + Newest = true, + ServerId = clientStats.ServerId, + RatingHistoryId = clientHistory.RatingHistoryId, }); + // get other server stats var clientStatsList = await iqClientStats.ToListAsync(); + clientStatsList.Add(new { clientStats.Performance, TimePlayed = currentServerTotalPlaytime }); - // weight the performance based on play time + // weight the overall performance based on play time var performanceAverage = clientStatsList.Sum(p => (p.Performance * p.TimePlayed)) / clientStatsList.Sum(p => p.TimePlayed); - int overallClientRanking = await ctx.Set() - .Where(c => c.ClientId != client.ClientId) - .Where(c => c.Ratings.OrderByDescending(r => r.RatingId).FirstOrDefault().Performance > performanceAverage) + var thirtyDaysAgo = DateTime.UtcNow.AddMonths(-1); + int overallClientRanking = await ctx.Set() + .Where(r => r.RatingHistory.Client.Level != Player.Permission.Banned) + .Where(r => r.RatingHistory.Client.TotalConnectionTime > 3600) + .Where(r => r.RatingHistory.Client.LastConnection > thirtyDaysAgo) + .Where(r => r.RatingHistory.ClientId != client.ClientId) + .Where(r => r.ServerId == null) + .Where(r => r.Newest) .CountAsync() + 1; - if (averageHistory.Ratings.Count > 30) + // limit max average history to 30 + if (clientHistory.Ratings.Count(r => r.ServerId == null) >= 30) { - ctx.Entry(averageHistory.Ratings.First()).State = EntityState.Deleted; - averageHistory.Ratings.Remove(averageHistory.Ratings.First()); + var ratingToRemove = clientHistory.Ratings.First(r => r.ServerId == null); + ctx.Entry(ratingToRemove).State = EntityState.Deleted; + clientHistory.Ratings.Remove(ratingToRemove); } - averageHistory.Ratings.Add(new EFRating() + // set the previous average newest to false + ratingToUnsetNewest = clientHistory.Ratings.LastOrDefault(r => r.ServerId == null); + if (ratingToUnsetNewest != null) { + ctx.Entry(ratingToUnsetNewest).State = EntityState.Modified; + ratingToUnsetNewest.Newest = false; + } + + // add new average rating + clientHistory.Ratings.Add(new EFRating() + { + Active = true, + Newest = true, Performance = performanceAverage, Ranking = overallClientRanking, - Active = true, - ClientId = client.ClientId, + ServerId = null, + RatingHistoryId = clientHistory.RatingHistoryId }); await ctx.SaveChangesAsync(); diff --git a/Plugins/Stats/Models/EFClientAverageStatHistory.cs b/Plugins/Stats/Models/EFClientAverageStatHistory.cs deleted file mode 100644 index dd2f41a71..000000000 --- a/Plugins/Stats/Models/EFClientAverageStatHistory.cs +++ /dev/null @@ -1,22 +0,0 @@ -using SharedLibraryCore.Database.Models; -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using System.Text; - -namespace IW4MAdmin.Plugins.Stats.Models -{ - public class EFClientAverageStatHistory : SharedEntity - { - [Key] - public int ClientId { get; set; } - [ForeignKey("ClientId")] - public virtual EFClient Client { get; set; } - public virtual ICollection Ratings { get; set; } - [Required] - public int LastRatingId { get; set; } - [ForeignKey("LastRatingId")] - public virtual EFRating LastRating { get; set; } - } -} diff --git a/Plugins/Stats/Models/EFClientStatHistory.cs b/Plugins/Stats/Models/EFClientRatingHistory.cs similarity index 69% rename from Plugins/Stats/Models/EFClientStatHistory.cs rename to Plugins/Stats/Models/EFClientRatingHistory.cs index c8e5308a0..51d04d0e0 100644 --- a/Plugins/Stats/Models/EFClientStatHistory.cs +++ b/Plugins/Stats/Models/EFClientRatingHistory.cs @@ -8,16 +8,13 @@ using System.Text; namespace IW4MAdmin.Plugins.Stats.Models { - public class EFClientStatHistory : SharedEntity + public class EFClientRatingHistory : SharedEntity { [Key] - public int StatHistoryId { get; set; } + public int RatingHistoryId { get; set; } public int ClientId { get; set; } [ForeignKey("ClientId")] public virtual EFClient Client { get; set; } - public int ServerId { get; set; } - [ForeignKey("ServerId")] - public virtual EFServer Server { get; set; } public virtual ICollection Ratings { get; set; } } } diff --git a/Plugins/Stats/Models/EFRating.cs b/Plugins/Stats/Models/EFRating.cs index be0a4a1ff..96efb9dc1 100644 --- a/Plugins/Stats/Models/EFRating.cs +++ b/Plugins/Stats/Models/EFRating.cs @@ -11,12 +11,19 @@ namespace IW4MAdmin.Plugins.Stats.Models { [Key] public int RatingId { get; set; } - public int ClientId { get; set; } - [ForeignKey("ClientId")] - public EFClient Client { get; set; } + public int RatingHistoryId { get; set; } + [ForeignKey("RatingHistoryId")] + public virtual EFClientRatingHistory RatingHistory { get; set; } + // if null, indicates that the rating is an average rating + public int? ServerId { get; set; } + // [ForeignKey("ServerId")] can't make this nullable if this annotation is set + public virtual EFServer Server { get; set; } [Required] public double Performance { get; set; } [Required] public int Ranking { get; set; } + [Required] + // indicates if the rating is the latest + public bool Newest { get; set; } } } diff --git a/SharedLibraryCore/Migrations/20180529233328_AddAutomatedOffenseAndRatingHistory.cs b/SharedLibraryCore/Migrations/20180529233328_AddAutomatedOffenseAndRatingHistory.cs deleted file mode 100644 index 62b85bd9f..000000000 --- a/SharedLibraryCore/Migrations/20180529233328_AddAutomatedOffenseAndRatingHistory.cs +++ /dev/null @@ -1,139 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; -using System; -using System.Collections.Generic; - -namespace SharedLibraryCore.Migrations -{ - public partial class AddAutomatedOffenseAndRatingHistory : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "AutomatedOffense", - table: "EFPenalties", - nullable: true); - - migrationBuilder.CreateTable( - name: "EFClientAverageStatHistory", - columns: table => new - { - ClientId = table.Column(nullable: false), - Active = table.Column(nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_EFClientAverageStatHistory", x => x.ClientId); - table.ForeignKey( - name: "FK_EFClientAverageStatHistory_EFClients_ClientId", - column: x => x.ClientId, - principalTable: "EFClients", - principalColumn: "ClientId", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "EFClientStatHistory", - columns: table => new - { - StatHistoryId = table.Column(nullable: false) - .Annotation("Sqlite:Autoincrement", true), - Active = table.Column(nullable: false), - ClientId = table.Column(nullable: false), - ServerId = table.Column(nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_EFClientStatHistory", x => x.StatHistoryId); - table.ForeignKey( - name: "FK_EFClientStatHistory_EFClients_ClientId", - column: x => x.ClientId, - principalTable: "EFClients", - principalColumn: "ClientId", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_EFClientStatHistory_EFServers_ServerId", - column: x => x.ServerId, - principalTable: "EFServers", - principalColumn: "ServerId", - onDelete: ReferentialAction.Cascade); - }); - - migrationBuilder.CreateTable( - name: "EFRating", - columns: table => new - { - RatingId = table.Column(nullable: false) - .Annotation("Sqlite:Autoincrement", true), - Active = table.Column(nullable: false), - ClientId = table.Column(nullable: false), - EFClientAverageStatHistoryClientId = table.Column(nullable: true), - EFClientStatHistoryStatHistoryId = table.Column(nullable: true), - Performance = table.Column(nullable: false), - Ranking = table.Column(nullable: false) - }, - constraints: table => - { - table.PrimaryKey("PK_EFRating", x => x.RatingId); - table.ForeignKey( - name: "FK_EFRating_EFClients_ClientId", - column: x => x.ClientId, - principalTable: "EFClients", - principalColumn: "ClientId", - onDelete: ReferentialAction.Cascade); - table.ForeignKey( - name: "FK_EFRating_EFClientAverageStatHistory_EFClientAverageStatHistoryClientId", - column: x => x.EFClientAverageStatHistoryClientId, - principalTable: "EFClientAverageStatHistory", - principalColumn: "ClientId", - onDelete: ReferentialAction.Restrict); - table.ForeignKey( - name: "FK_EFRating_EFClientStatHistory_EFClientStatHistoryStatHistoryId", - column: x => x.EFClientStatHistoryStatHistoryId, - principalTable: "EFClientStatHistory", - principalColumn: "StatHistoryId", - onDelete: ReferentialAction.Restrict); - }); - - migrationBuilder.CreateIndex( - name: "IX_EFClientStatHistory_ClientId", - table: "EFClientStatHistory", - column: "ClientId"); - - migrationBuilder.CreateIndex( - name: "IX_EFClientStatHistory_ServerId", - table: "EFClientStatHistory", - column: "ServerId"); - - migrationBuilder.CreateIndex( - name: "IX_EFRating_ClientId", - table: "EFRating", - column: "ClientId"); - - migrationBuilder.CreateIndex( - name: "IX_EFRating_EFClientAverageStatHistoryClientId", - table: "EFRating", - column: "EFClientAverageStatHistoryClientId"); - - migrationBuilder.CreateIndex( - name: "IX_EFRating_EFClientStatHistoryStatHistoryId", - table: "EFRating", - column: "EFClientStatHistoryStatHistoryId"); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "EFRating"); - - migrationBuilder.DropTable( - name: "EFClientAverageStatHistory"); - - migrationBuilder.DropTable( - name: "EFClientStatHistory"); - - migrationBuilder.DropColumn( - name: "AutomatedOffense", - table: "EFPenalties"); - } - } -} diff --git a/SharedLibraryCore/Migrations/20180529233328_AddAutomatedOffenseAndRatingHistory.Designer.cs b/SharedLibraryCore/Migrations/20180531212903_AddAutomatedOffenseAndRatingHistory.Designer.cs similarity index 88% rename from SharedLibraryCore/Migrations/20180529233328_AddAutomatedOffenseAndRatingHistory.Designer.cs rename to SharedLibraryCore/Migrations/20180531212903_AddAutomatedOffenseAndRatingHistory.Designer.cs index 0f2b874e6..96cd81d1c 100644 --- a/SharedLibraryCore/Migrations/20180529233328_AddAutomatedOffenseAndRatingHistory.Designer.cs +++ b/SharedLibraryCore/Migrations/20180531212903_AddAutomatedOffenseAndRatingHistory.Designer.cs @@ -12,7 +12,7 @@ using System; namespace SharedLibraryCore.Migrations { [DbContext(typeof(DatabaseContext))] - [Migration("20180529233328_AddAutomatedOffenseAndRatingHistory")] + [Migration("20180531212903_AddAutomatedOffenseAndRatingHistory")] partial class AddAutomatedOffenseAndRatingHistory { protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -21,17 +21,6 @@ namespace SharedLibraryCore.Migrations modelBuilder .HasAnnotation("ProductVersion", "2.0.2-rtm-10011"); - modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientAverageStatHistory", b => - { - b.Property("ClientId"); - - b.Property("Active"); - - b.HasKey("ClientId"); - - b.ToTable("EFClientAverageStatHistory"); - }); - modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b => { b.Property("KillId") @@ -104,24 +93,20 @@ namespace SharedLibraryCore.Migrations b.ToTable("EFClientMessages"); }); - modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatHistory", b => + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", b => { - b.Property("StatHistoryId") + b.Property("RatingHistoryId") .ValueGeneratedOnAdd(); b.Property("Active"); b.Property("ClientId"); - b.Property("ServerId"); - - b.HasKey("StatHistoryId"); + b.HasKey("RatingHistoryId"); b.HasIndex("ClientId"); - b.HasIndex("ServerId"); - - b.ToTable("EFClientStatHistory"); + b.ToTable("EFClientRatingHistory"); }); modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b => @@ -192,23 +177,21 @@ namespace SharedLibraryCore.Migrations b.Property("Active"); - b.Property("ClientId"); - - b.Property("EFClientAverageStatHistoryClientId"); - - b.Property("EFClientStatHistoryStatHistoryId"); + b.Property("Newest"); b.Property("Performance"); b.Property("Ranking"); + b.Property("RatingHistoryId"); + + b.Property("ServerId"); + b.HasKey("RatingId"); - b.HasIndex("ClientId"); + b.HasIndex("RatingHistoryId"); - b.HasIndex("EFClientAverageStatHistoryClientId"); - - b.HasIndex("EFClientStatHistoryStatHistoryId"); + b.HasIndex("ServerId"); b.ToTable("EFRating"); }); @@ -373,14 +356,6 @@ namespace SharedLibraryCore.Migrations b.ToTable("Vector3"); }); - modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientAverageStatHistory", b => - { - b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client") - .WithMany() - .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade); - }); - modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b => { b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Attacker") @@ -424,17 +399,12 @@ namespace SharedLibraryCore.Migrations .OnDelete(DeleteBehavior.Cascade); }); - modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatHistory", b => + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", b => { b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client") .WithMany() .HasForeignKey("ClientId") .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server") - .WithMany() - .HasForeignKey("ServerId") - .OnDelete(DeleteBehavior.Cascade); }); modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b => @@ -470,18 +440,14 @@ namespace SharedLibraryCore.Migrations modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b => { - b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client") - .WithMany() - .HasForeignKey("ClientId") + b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", "RatingHistory") + .WithMany("Ratings") + .HasForeignKey("RatingHistoryId") .OnDelete(DeleteBehavior.Cascade); - b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientAverageStatHistory") - .WithMany("Ratings") - .HasForeignKey("EFClientAverageStatHistoryClientId"); - - b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientStatHistory") - .WithMany("Ratings") - .HasForeignKey("EFClientStatHistoryStatHistoryId"); + b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server") + .WithMany() + .HasForeignKey("ServerId"); }); modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b => diff --git a/SharedLibraryCore/Migrations/20180531212903_AddAutomatedOffenseAndRatingHistory.cs b/SharedLibraryCore/Migrations/20180531212903_AddAutomatedOffenseAndRatingHistory.cs new file mode 100644 index 000000000..79f1f6204 --- /dev/null +++ b/SharedLibraryCore/Migrations/20180531212903_AddAutomatedOffenseAndRatingHistory.cs @@ -0,0 +1,95 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using System; +using System.Collections.Generic; + +namespace SharedLibraryCore.Migrations +{ + public partial class AddAutomatedOffenseAndRatingHistory : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "AutomatedOffense", + table: "EFPenalties", + nullable: true); + + migrationBuilder.CreateTable( + name: "EFClientRatingHistory", + columns: table => new + { + RatingHistoryId = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Active = table.Column(nullable: false), + ClientId = table.Column(nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_EFClientRatingHistory", x => x.RatingHistoryId); + table.ForeignKey( + name: "FK_EFClientRatingHistory_EFClients_ClientId", + column: x => x.ClientId, + principalTable: "EFClients", + principalColumn: "ClientId", + onDelete: ReferentialAction.Cascade); + }); + + migrationBuilder.CreateTable( + name: "EFRating", + columns: table => new + { + RatingId = table.Column(nullable: false) + .Annotation("Sqlite:Autoincrement", true), + Active = table.Column(nullable: false), + Newest = table.Column(nullable: false), + Performance = table.Column(nullable: false), + Ranking = table.Column(nullable: false), + RatingHistoryId = table.Column(nullable: false), + ServerId = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_EFRating", x => x.RatingId); + table.ForeignKey( + name: "FK_EFRating_EFClientRatingHistory_RatingHistoryId", + column: x => x.RatingHistoryId, + principalTable: "EFClientRatingHistory", + principalColumn: "RatingHistoryId", + onDelete: ReferentialAction.Cascade); + table.ForeignKey( + name: "FK_EFRating_EFServers_ServerId", + column: x => x.ServerId, + principalTable: "EFServers", + principalColumn: "ServerId", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_EFClientRatingHistory_ClientId", + table: "EFClientRatingHistory", + column: "ClientId"); + + migrationBuilder.CreateIndex( + name: "IX_EFRating_RatingHistoryId", + table: "EFRating", + column: "RatingHistoryId"); + + migrationBuilder.CreateIndex( + name: "IX_EFRating_ServerId", + table: "EFRating", + column: "ServerId"); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "EFRating"); + + migrationBuilder.DropTable( + name: "EFClientRatingHistory"); + + migrationBuilder.DropColumn( + name: "AutomatedOffense", + table: "EFPenalties"); + } + } +} diff --git a/SharedLibraryCore/Migrations/DatabaseContextModelSnapshot.cs b/SharedLibraryCore/Migrations/DatabaseContextModelSnapshot.cs index 9300a7543..54323dc99 100644 --- a/SharedLibraryCore/Migrations/DatabaseContextModelSnapshot.cs +++ b/SharedLibraryCore/Migrations/DatabaseContextModelSnapshot.cs @@ -20,17 +20,6 @@ namespace SharedLibraryCore.Migrations modelBuilder .HasAnnotation("ProductVersion", "2.0.2-rtm-10011"); - modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientAverageStatHistory", b => - { - b.Property("ClientId"); - - b.Property("Active"); - - b.HasKey("ClientId"); - - b.ToTable("EFClientAverageStatHistory"); - }); - modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b => { b.Property("KillId") @@ -103,24 +92,20 @@ namespace SharedLibraryCore.Migrations b.ToTable("EFClientMessages"); }); - modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatHistory", b => + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", b => { - b.Property("StatHistoryId") + b.Property("RatingHistoryId") .ValueGeneratedOnAdd(); b.Property("Active"); b.Property("ClientId"); - b.Property("ServerId"); - - b.HasKey("StatHistoryId"); + b.HasKey("RatingHistoryId"); b.HasIndex("ClientId"); - b.HasIndex("ServerId"); - - b.ToTable("EFClientStatHistory"); + b.ToTable("EFClientRatingHistory"); }); modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b => @@ -191,23 +176,21 @@ namespace SharedLibraryCore.Migrations b.Property("Active"); - b.Property("ClientId"); - - b.Property("EFClientAverageStatHistoryClientId"); - - b.Property("EFClientStatHistoryStatHistoryId"); + b.Property("Newest"); b.Property("Performance"); b.Property("Ranking"); + b.Property("RatingHistoryId"); + + b.Property("ServerId"); + b.HasKey("RatingId"); - b.HasIndex("ClientId"); + b.HasIndex("RatingHistoryId"); - b.HasIndex("EFClientAverageStatHistoryClientId"); - - b.HasIndex("EFClientStatHistoryStatHistoryId"); + b.HasIndex("ServerId"); b.ToTable("EFRating"); }); @@ -372,14 +355,6 @@ namespace SharedLibraryCore.Migrations b.ToTable("Vector3"); }); - modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientAverageStatHistory", b => - { - b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client") - .WithMany() - .HasForeignKey("ClientId") - .OnDelete(DeleteBehavior.Cascade); - }); - modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b => { b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Attacker") @@ -423,17 +398,12 @@ namespace SharedLibraryCore.Migrations .OnDelete(DeleteBehavior.Cascade); }); - modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatHistory", b => + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", b => { b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client") .WithMany() .HasForeignKey("ClientId") .OnDelete(DeleteBehavior.Cascade); - - b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server") - .WithMany() - .HasForeignKey("ServerId") - .OnDelete(DeleteBehavior.Cascade); }); modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b => @@ -469,18 +439,14 @@ namespace SharedLibraryCore.Migrations modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b => { - b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client") - .WithMany() - .HasForeignKey("ClientId") + b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", "RatingHistory") + .WithMany("Ratings") + .HasForeignKey("RatingHistoryId") .OnDelete(DeleteBehavior.Cascade); - b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientAverageStatHistory") - .WithMany("Ratings") - .HasForeignKey("EFClientAverageStatHistoryClientId"); - - b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientStatHistory") - .WithMany("Ratings") - .HasForeignKey("EFClientStatHistoryStatHistoryId"); + b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server") + .WithMany() + .HasForeignKey("ServerId"); }); modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b => diff --git a/WebfrontCore/wwwroot/js/loader.js b/WebfrontCore/wwwroot/js/loader.js index 8d3e26663..b7f2df254 100644 --- a/WebfrontCore/wwwroot/js/loader.js +++ b/WebfrontCore/wwwroot/js/loader.js @@ -23,6 +23,7 @@ function loadMoreItems() { if (response.trim().length === 0) { staleLoader(); } + $(document).trigger("loaderFinished", response); hideLoader(); isLoaderLoading = false; }) diff --git a/WebfrontCore/wwwroot/js/stats.js b/WebfrontCore/wwwroot/js/stats.js index 2a5d7fe7d..e5433e334 100644 --- a/WebfrontCore/wwwroot/js/stats.js +++ b/WebfrontCore/wwwroot/js/stats.js @@ -27,8 +27,8 @@ gridThickness: 0, lineThickness: 0, tickThickness: 0, - minimum: Math.min(...data) - 15, - maximum: Math.max(...data) + 15, + minimum: Math.min(...data) - Math.min(...data) * 0.075, + maximum: Math.max(...data) + Math.max(...data) * 0.075, margin: 0, valueFormatString: " ", labelMaxWidth: 0 @@ -59,3 +59,10 @@ $(document).ready(function () { }); }); }); + +$(document).on("loaderFinished", function (event, response) { + const ids = $.map($(response).find('.client-rating-graph'), function (elem) { return $(elem).attr('id'); }); + ids.forEach(function (item, index) { + getStatsChart(item, $(item).width(), $(item).height()).render(); + }); +});