Add automated ban offense for anti-cheat
add EFClientStatHistory and EFClientAverageStatHistory for tracking change of stats over time
This commit is contained in:
parent
2204686b08
commit
bf68e5672f
@ -1024,7 +1024,8 @@ namespace IW4MAdmin
|
|||||||
Punisher = Origin,
|
Punisher = Origin,
|
||||||
Active = true,
|
Active = true,
|
||||||
When = DateTime.UtcNow,
|
When = DateTime.UtcNow,
|
||||||
Link = Target.AliasLink
|
Link = Target.AliasLink,
|
||||||
|
AutomatedOffense = Origin.AdministeredPenalties.FirstOrDefault()?.AutomatedOffense
|
||||||
};
|
};
|
||||||
|
|
||||||
await Manager.GetPenaltyService().Create(newPenalty);
|
await Manager.GetPenaltyService().Create(newPenalty);
|
||||||
|
@ -14,6 +14,8 @@ using System.Text.RegularExpressions;
|
|||||||
using IW4MAdmin.Plugins.Stats.Web.Dtos;
|
using IW4MAdmin.Plugins.Stats.Web.Dtos;
|
||||||
using SharedLibraryCore.Database;
|
using SharedLibraryCore.Database;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using SharedLibraryCore.Database.Models;
|
||||||
|
using SharedLibraryCore.Services;
|
||||||
|
|
||||||
namespace IW4MAdmin.Plugins.Stats.Helpers
|
namespace IW4MAdmin.Plugins.Stats.Helpers
|
||||||
{
|
{
|
||||||
@ -50,64 +52,70 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
|
|
||||||
var thirtyDaysAgo = DateTime.UtcNow.AddMonths(-1);
|
var thirtyDaysAgo = DateTime.UtcNow.AddMonths(-1);
|
||||||
var iqClientIds = (from stat in context.Set<EFClientStatistics>()
|
var iqClientIds = (from stat in context.Set<EFClientStatistics>()
|
||||||
join client in context.Clients
|
|
||||||
on stat.ClientId equals client.ClientId
|
|
||||||
#if !DEBUG
|
#if !DEBUG
|
||||||
where stat.TimePlayed >= 3600
|
.Where(s => s.TimePlayed > 3600)
|
||||||
where client.Level != Player.Permission.Banned
|
.Where(s => s.EloRating > 60.0)
|
||||||
where client.LastConnection >= thirtyDaysAgo
|
|
||||||
where stat.Performance > 60
|
|
||||||
#endif
|
#endif
|
||||||
group stat by stat.ClientId into s
|
where stat.Client.Level != Player.Permission.Banned
|
||||||
orderby s.Average(cs => cs.Performance) descending
|
where stat.Client.LastConnection >= thirtyDaysAgo
|
||||||
select s.First().ClientId)
|
|
||||||
|
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<EFClientAverageStatHistory>().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<EFClientAverageStatHistory>().SingleOrDefault(r => r.ClientId == stat.ClientId)
|
||||||
|
})*/
|
||||||
.Skip(start)
|
.Skip(start)
|
||||||
.Take(count);
|
.Take(count);
|
||||||
|
|
||||||
var clientIds = await iqClientIds.ToListAsync();
|
var stats = await iqClientIds.ToListAsync();
|
||||||
|
|
||||||
var iqStats = (from stat in context.Set<EFClientStatistics>()
|
var groupedSelection = stats.GroupBy(c => c.ClientId).Select(s =>
|
||||||
join client in context.Clients
|
new TopStatsInfo()
|
||||||
on stat.ClientId equals client.ClientId
|
{
|
||||||
where clientIds.Contains(client.ClientId)
|
/* Name = s.First().Name,
|
||||||
select new
|
// 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<double>()
|
||||||
{
|
{
|
||||||
client.CurrentAlias.Name,
|
s.Performance,
|
||||||
client.ClientId,
|
s.Performance
|
||||||
stat.Kills,
|
} :
|
||||||
stat.Deaths,
|
s.AverageHistory.Ratings.Select(r => Math.Round(r.Performance, 1)).ToList()*/
|
||||||
stat.EloRating,
|
});
|
||||||
stat.Skill,
|
|
||||||
stat.TimePlayed,
|
|
||||||
client.LastConnection,
|
|
||||||
client.TotalConnectionTime
|
|
||||||
});
|
|
||||||
|
|
||||||
var stats = await iqStats.ToListAsync();
|
|
||||||
|
|
||||||
var groupedSelection = stats.GroupBy(s => s.ClientId).Select(s =>
|
|
||||||
new TopStatsInfo()
|
|
||||||
{
|
|
||||||
Name = s.Select(c => c.Name).FirstOrDefault(),
|
|
||||||
// weighted based on time played
|
|
||||||
Performance = Math.Round
|
|
||||||
(s
|
|
||||||
.Where(c => (c.Skill + c.EloRating) / 2.0 > 0)
|
|
||||||
.Sum(c => (c.Skill + c.EloRating) / 2.0 * c.TimePlayed) /
|
|
||||||
s.Where(c => (c.Skill + c.EloRating) / 2.0 > 0)
|
|
||||||
.Sum(c => c.TimePlayed), 2),
|
|
||||||
// ditto
|
|
||||||
KDR = Math.Round(s
|
|
||||||
.Where(c => c.Deaths > 0)
|
|
||||||
.Sum(c => ((c.Kills / (double)c.Deaths) * c.TimePlayed) /
|
|
||||||
s.Where(d => d.Deaths > 0)
|
|
||||||
.Sum(d => d.TimePlayed)), 2),
|
|
||||||
ClientId = s.Select(c => c.ClientId).FirstOrDefault(),
|
|
||||||
Deaths = s.Sum(cs => cs.Deaths),
|
|
||||||
Kills = s.Sum(cs => cs.Kills),
|
|
||||||
LastSeen = Utilities.GetTimePassed(s.First().LastConnection, false),
|
|
||||||
TimePlayed = Math.Round(s.First().TotalConnectionTime / 3600.0, 1).ToString("#,##0"),
|
|
||||||
});
|
|
||||||
|
|
||||||
var statList = groupedSelection.OrderByDescending(s => s.Performance).ToList();
|
var statList = groupedSelection.OrderByDescending(s => s.Performance).ToList();
|
||||||
|
|
||||||
@ -215,8 +223,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
Active = true,
|
Active = true,
|
||||||
HitCount = 0,
|
HitCount = 0,
|
||||||
Location = hl
|
Location = hl
|
||||||
})
|
}).ToList()
|
||||||
.ToList()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// insert if they've not been added
|
// insert if they've not been added
|
||||||
@ -437,7 +444,16 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
case Penalty.PenaltyType.Ban:
|
case Penalty.PenaltyType.Ban:
|
||||||
await attacker.Ban(Utilities.CurrentLocalization.LocalizationIndex["PLUGIN_STATS_CHEAT_DETECTED"], new Player()
|
await attacker.Ban(Utilities.CurrentLocalization.LocalizationIndex["PLUGIN_STATS_CHEAT_DETECTED"], new Player()
|
||||||
{
|
{
|
||||||
ClientId = 1
|
ClientId = 1,
|
||||||
|
AdministeredPenalties = new List<EFPenalty>()
|
||||||
|
{
|
||||||
|
new EFPenalty()
|
||||||
|
{
|
||||||
|
AutomatedOffense = penalty.Type == Cheat.Detection.DetectionType.Bone ?
|
||||||
|
$"{penalty.Type}-{(int)penalty.Location}-{Math.Round(penalty.Value, 2)}@{penalty.HitCount}" :
|
||||||
|
$"{penalty.Type}-{Math.Round(penalty.Value, 2)}@{penalty.HitCount}",
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case Penalty.PenaltyType.Flag:
|
case Penalty.PenaltyType.Flag:
|
||||||
@ -546,6 +562,15 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
attackerStats.Skill = 0.0;
|
attackerStats.Skill = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update their performance
|
||||||
|
#if !DEBUG
|
||||||
|
if ((DateTime.UtcNow - attackerStats.LastStatHistoryUpdate).TotalMinutes >= 10)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
await UpdateStatHistory(attacker, attackerStats);
|
||||||
|
attackerStats.LastStatHistoryUpdate = DateTime.UtcNow;
|
||||||
|
}
|
||||||
|
|
||||||
// todo: do we want to save this immediately?
|
// todo: do we want to save this immediately?
|
||||||
var clientStatsSvc = ContextThreads[serverId].ClientStatSvc;
|
var clientStatsSvc = ContextThreads[serverId].ClientStatSvc;
|
||||||
clientStatsSvc.Update(attackerStats);
|
clientStatsSvc.Update(attackerStats);
|
||||||
@ -553,6 +578,132 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
await clientStatsSvc.SaveChangesAsync();
|
await clientStatsSvc.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update the invidual and average stat history for a client
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">client to update</param>
|
||||||
|
/// <param name="clientStats">stats of client that is being updated</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private async Task UpdateStatHistory(Player client, EFClientStatistics clientStats)
|
||||||
|
{
|
||||||
|
int currentServerTotalPlaytime = clientStats.TimePlayed + (int)(DateTime.UtcNow - client.LastConnection).TotalSeconds;
|
||||||
|
|
||||||
|
using (var ctx = new DatabaseContext())
|
||||||
|
{
|
||||||
|
// select the individual history for current server
|
||||||
|
var iqIndividualStatHistory = from statHistory in ctx.Set<EFClientStatHistory>()
|
||||||
|
where statHistory.ClientId == client.ClientId
|
||||||
|
where statHistory.ServerId == clientStats.ServerId
|
||||||
|
select statHistory;
|
||||||
|
|
||||||
|
// select the average history for current client
|
||||||
|
var iqAverageHistory = from stat in ctx.Set<EFClientAverageStatHistory>()
|
||||||
|
where stat.ClientId == client.ClientId
|
||||||
|
select stat;
|
||||||
|
|
||||||
|
// select all stats for current client
|
||||||
|
var iqClientStats = from stats in ctx.Set<EFClientStatistics>()
|
||||||
|
where stats.ClientId == client.ClientId
|
||||||
|
where stats.ServerId != clientStats.ServerId
|
||||||
|
select new
|
||||||
|
{
|
||||||
|
stats.Performance,
|
||||||
|
stats.TimePlayed
|
||||||
|
};
|
||||||
|
|
||||||
|
// get the client ranking for the current server
|
||||||
|
int individualClientRanking = await ctx.Set<EFClientStatHistory>()
|
||||||
|
.Where(c => c.ClientId != client.ClientId)
|
||||||
|
.Where(c => c.ServerId == clientStats.ServerId)
|
||||||
|
.Where(c => c.Ratings.OrderByDescending(r => r.RatingId).FirstOrDefault().Performance > clientStats.Performance)
|
||||||
|
.CountAsync() + 1;
|
||||||
|
|
||||||
|
var currentServerHistory = await iqIndividualStatHistory
|
||||||
|
.Include(r => r.Ratings)
|
||||||
|
.FirstOrDefaultAsync() ?? new EFClientStatHistory()
|
||||||
|
{
|
||||||
|
Active = true,
|
||||||
|
ClientId = client.ClientId,
|
||||||
|
Ratings = new List<EFRating>(),
|
||||||
|
ServerId = clientStats.ServerId
|
||||||
|
};
|
||||||
|
|
||||||
|
var averageHistory = await iqAverageHistory
|
||||||
|
.Include(r => r.Ratings)
|
||||||
|
.FirstOrDefaultAsync() ?? new EFClientAverageStatHistory()
|
||||||
|
{
|
||||||
|
ClientId = client.ClientId,
|
||||||
|
Ratings = new List<EFRating>(),
|
||||||
|
Active = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (currentServerHistory.StatHistoryId == 0)
|
||||||
|
{
|
||||||
|
ctx.Add(currentServerHistory);
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ctx.Update(currentServerHistory);
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
Performance = clientStats.Performance,
|
||||||
|
Ranking = individualClientRanking,
|
||||||
|
Active = true,
|
||||||
|
ClientId = client.ClientId,
|
||||||
|
});
|
||||||
|
|
||||||
|
var clientStatsList = await iqClientStats.ToListAsync();
|
||||||
|
clientStatsList.Add(new
|
||||||
|
{
|
||||||
|
clientStats.Performance,
|
||||||
|
TimePlayed = currentServerTotalPlaytime
|
||||||
|
});
|
||||||
|
|
||||||
|
// weight the performance based on play time
|
||||||
|
var performanceAverage = clientStatsList.Sum(p => (p.Performance * p.TimePlayed)) / clientStatsList.Sum(p => p.TimePlayed);
|
||||||
|
|
||||||
|
int overallClientRanking = await ctx.Set<EFClientAverageStatHistory>()
|
||||||
|
.Where(c => c.ClientId != client.ClientId)
|
||||||
|
.Where(c => c.Ratings.OrderByDescending(r => r.RatingId).FirstOrDefault().Performance > performanceAverage)
|
||||||
|
.CountAsync() + 1;
|
||||||
|
|
||||||
|
if (averageHistory.Ratings.Count > 30)
|
||||||
|
{
|
||||||
|
ctx.Entry(averageHistory.Ratings.First()).State = EntityState.Deleted;
|
||||||
|
averageHistory.Ratings.Remove(averageHistory.Ratings.First());
|
||||||
|
}
|
||||||
|
|
||||||
|
averageHistory.Ratings.Add(new EFRating()
|
||||||
|
{
|
||||||
|
Performance = performanceAverage,
|
||||||
|
Ranking = overallClientRanking,
|
||||||
|
Active = true,
|
||||||
|
ClientId = client.ClientId,
|
||||||
|
});
|
||||||
|
|
||||||
|
await ctx.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Performs the incrementation of kills and deaths for client statistics
|
/// Performs the incrementation of kills and deaths for client statistics
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
22
Plugins/Stats/Models/EFClientAverageStatHistory.cs
Normal file
22
Plugins/Stats/Models/EFClientAverageStatHistory.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
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<EFRating> Ratings { get; set; }
|
||||||
|
[Required]
|
||||||
|
public int LastRatingId { get; set; }
|
||||||
|
[ForeignKey("LastRatingId")]
|
||||||
|
public virtual EFRating LastRating { get; set; }
|
||||||
|
}
|
||||||
|
}
|
23
Plugins/Stats/Models/EFClientStatHistory.cs
Normal file
23
Plugins/Stats/Models/EFClientStatHistory.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
using IW4MAdmin.Plugins.Stats.Models;
|
||||||
|
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 EFClientStatHistory : SharedEntity
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
public int StatHistoryId { 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<EFRating> Ratings { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -96,5 +96,7 @@ namespace IW4MAdmin.Plugins.Stats.Models
|
|||||||
private List<int> SessionScores = new List<int>() { 0 };
|
private List<int> SessionScores = new List<int>() { 0 };
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public IW4Info.Team Team { get; set; }
|
public IW4Info.Team Team { get; set; }
|
||||||
|
[NotMapped]
|
||||||
|
public DateTime LastStatHistoryUpdate { get; set; } = DateTime.UtcNow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
22
Plugins/Stats/Models/EFRating.cs
Normal file
22
Plugins/Stats/Models/EFRating.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
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 EFRating : SharedEntity
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
public int RatingId { get; set; }
|
||||||
|
public int ClientId { get; set; }
|
||||||
|
[ForeignKey("ClientId")]
|
||||||
|
public EFClient Client { get; set; }
|
||||||
|
[Required]
|
||||||
|
public double Performance { get; set; }
|
||||||
|
[Required]
|
||||||
|
public int Ranking { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -16,7 +16,7 @@ namespace IW4MAdmin.Plugins.Stats.Web.Controllers
|
|||||||
ViewBag.Title = Utilities.CurrentLocalization.LocalizationIndex.Set["WEBFRONT_STATS_INDEX_TITLE"];
|
ViewBag.Title = Utilities.CurrentLocalization.LocalizationIndex.Set["WEBFRONT_STATS_INDEX_TITLE"];
|
||||||
ViewBag.Description = Utilities.CurrentLocalization.LocalizationIndex.Set["WEBFRONT_STATS_INDEX_DESC"];
|
ViewBag.Description = Utilities.CurrentLocalization.LocalizationIndex.Set["WEBFRONT_STATS_INDEX_DESC"];
|
||||||
|
|
||||||
return View("Index", await Plugin.Manager.GetTopStats(0, 15));
|
return View("Index", await Plugin.Manager.GetTopStats(0, 25));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
|
@ -16,5 +16,6 @@ namespace IW4MAdmin.Plugins.Stats.Web.Dtos
|
|||||||
public string LastSeen { get; set; }
|
public string LastSeen { get; set; }
|
||||||
public int Kills { get; set; }
|
public int Kills { get; set; }
|
||||||
public int Deaths { get; set; }
|
public int Deaths { get; set; }
|
||||||
|
public List<double> PerformanceHistory { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
@model List<IW4MAdmin.Plugins.Stats.Web.Dtos.TopStatsInfo>
|
@model List<IW4MAdmin.Plugins.Stats.Web.Dtos.TopStatsInfo>
|
||||||
<h4 class="pb-2 text-center ">@ViewBag.Title</h4>
|
<h4 class="pb-2 text-center ">@ViewBag.Title</h4>
|
||||||
|
|
||||||
<div id="stats_top_players" class="row border-top border-bottom">
|
<div id="stats_top_players" class="striped border-top border-bottom">
|
||||||
@await Html.PartialAsync("_List", Model)
|
@await Html.PartialAsync("_List", Model)
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@section scripts {
|
@section scripts {
|
||||||
<environment include="Development">
|
<environment include="Development">
|
||||||
<script type="text/javascript" src="~/js/loader.js"></script>
|
<script type="text/javascript" src="~/js/loader.js"></script>
|
||||||
</environment>
|
<script type="text/javascript" src="~/js/stats.js"></script>
|
||||||
<script>initLoader('/Stats/GetTopPlayersAsync', '#stats_top_players');</script>
|
</environment>
|
||||||
}
|
<script>initLoader('/Stats/GetTopPlayersAsync', '#stats_top_players');</script>
|
||||||
|
}
|
||||||
|
@ -25,26 +25,25 @@
|
|||||||
return "0_no-place/menu_div_no_place.png";
|
return "0_no-place/menu_div_no_place.png";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
<table class="table table-striped mb-0" style="background-color:rgba(0, 0, 0, 0.1)">
|
@foreach (var stat in Model)
|
||||||
@foreach (var stat in Model)
|
{
|
||||||
{
|
<div class="row ml-0 mr-0 pt-2 pb-2">
|
||||||
<tr>
|
<div class="col-md-4 text-md-left text-center">
|
||||||
<td style="vertical-align: middle">
|
<h2 class="text-muted">#@stat.Ranking — @Html.ActionLink(stat.Name, "ProfileAsync", "Client", new { id = stat.ClientId })</h2>
|
||||||
<div class="">
|
<span class="text-primary">@stat.Performance</span><span class="text-muted"> @loc["PLUGINS_STATS_COMMANDS_PERFORMANCE"]</span><br />
|
||||||
<h2 class="text-muted">#@stat.Ranking — @Html.ActionLink(stat.Name, "ProfileAsync", "Client", new { id = stat.ClientId })</h2>
|
<span class="text-primary">@stat.KDR</span><span class="text-muted"> @loc["PLUGINS_STATS_TEXT_KDR"]</span>
|
||||||
<span class="text-primary">@stat.Performance</span><span class="text-muted"> @loc["PLUGINS_STATS_COMMANDS_PERFORMANCE"]</span><br />
|
<span class="text-primary">@stat.Kills</span><span class="text-muted"> @loc["PLUGINS_STATS_TEXT_KILLS"]</span>
|
||||||
<span class="text-primary">@stat.KDR</span><span class="text-muted"> @loc["PLUGINS_STATS_TEXT_KDR"]</span>
|
<span class="text-primary">@stat.Deaths</span><span class="text-muted"> @loc["PLUGINS_STATS_TEXT_DEATHS"]</span><br />
|
||||||
<span class="text-primary">@stat.Kills</span><span class="text-muted"> @loc["PLUGINS_STATS_TEXT_KILLS"]</span>
|
<span class="text-muted">@loc["WEBFRONT_PROFILE_PLAYER"]</span> <span class="text-primary"> @stat.TimePlayed </span><span class="text-muted">@loc["GLOBAL_HOURS"]</span><br />
|
||||||
<span class="text-primary">@stat.Deaths</span><span class="text-muted"> @loc["PLUGINS_STATS_TEXT_DEATHS"]</span><br />
|
<span class="text-muted">@loc["WEBFRONT_PROFILE_LSEEN"]</span><span class="text-primary"> @stat.LastSeen </span><span class="text-muted">@loc["WEBFRONT_PENALTY_TEMPLATE_AGO"]</span>
|
||||||
<span class="text-muted">@loc["WEBFRONT_PROFILE_PLAYER"]</span> <span class="text-primary"> @stat.TimePlayed </span><span class="text-muted">@loc["GLOBAL_HOURS"]</span><br />
|
</div>
|
||||||
<span class="text-muted">@loc["WEBFRONT_PROFILE_LSEEN"]</span><span class="text-primary"> @stat.LastSeen </span><span class="text-muted">@loc["WEBFRONT_PENALTY_TEMPLATE_AGO"]</span>
|
|
||||||
</div>
|
<div class="col-md-6 client-rating-graph" id="rating_history_@stat.ClientId" data-history="@Html.Raw(Json.Serialize(stat.PerformanceHistory))">
|
||||||
</td>
|
|
||||||
<td class="text-right ml-0 pl-0" style="vertical-align: middle">
|
</div>
|
||||||
<div>
|
|
||||||
<img src="/images/icons/@rankIcon(stat.Performance)" />
|
<div class="col-md-2 client-rating-icon text-md-right text-center align-items-center d-flex justify-content-center">
|
||||||
</div>
|
<img src="/images/icons/@rankIcon(stat.Performance)" />
|
||||||
</td>
|
</div>
|
||||||
</tr>
|
</div>
|
||||||
}
|
}
|
||||||
</table>
|
|
@ -30,6 +30,7 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
public DateTime Expires { get; set; }
|
public DateTime Expires { get; set; }
|
||||||
[Required]
|
[Required]
|
||||||
public string Offense { get; set; }
|
public string Offense { get; set; }
|
||||||
|
public string AutomatedOffense { get; set; }
|
||||||
public Objects.Penalty.PenaltyType Type { get; set; }
|
public Objects.Penalty.PenaltyType Type { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ namespace SharedLibraryCore.Dtos
|
|||||||
public int PunisherId { get; set; }
|
public int PunisherId { get; set; }
|
||||||
public string PunisherLevel { get; set; }
|
public string PunisherLevel { get; set; }
|
||||||
public string Offense { get; set; }
|
public string Offense { get; set; }
|
||||||
|
public string AutomatedOffense { get; set; }
|
||||||
public string Type { get; set; }
|
public string Type { get; set; }
|
||||||
public string TimePunished { get; set; }
|
public string TimePunished { get; set; }
|
||||||
public string TimeRemaining { get; set; }
|
public string TimeRemaining { get; set; }
|
||||||
|
536
SharedLibraryCore/Migrations/20180529233328_AddAutomatedOffenseAndRatingHistory.Designer.cs
generated
Normal file
536
SharedLibraryCore/Migrations/20180529233328_AddAutomatedOffenseAndRatingHistory.Designer.cs
generated
Normal file
@ -0,0 +1,536 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.Internal;
|
||||||
|
using SharedLibraryCore.Database;
|
||||||
|
using SharedLibraryCore.Objects;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace SharedLibraryCore.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(DatabaseContext))]
|
||||||
|
[Migration("20180529233328_AddAutomatedOffenseAndRatingHistory")]
|
||||||
|
partial class AddAutomatedOffenseAndRatingHistory
|
||||||
|
{
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.HasAnnotation("ProductVersion", "2.0.2-rtm-10011");
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientAverageStatHistory", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ClientId");
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.HasKey("ClientId");
|
||||||
|
|
||||||
|
b.ToTable("EFClientAverageStatHistory");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("KillId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("AttackerId");
|
||||||
|
|
||||||
|
b.Property<int>("Damage");
|
||||||
|
|
||||||
|
b.Property<int?>("DeathOriginVector3Id");
|
||||||
|
|
||||||
|
b.Property<int>("DeathType");
|
||||||
|
|
||||||
|
b.Property<int>("HitLoc");
|
||||||
|
|
||||||
|
b.Property<int?>("KillOriginVector3Id");
|
||||||
|
|
||||||
|
b.Property<int>("Map");
|
||||||
|
|
||||||
|
b.Property<int>("ServerId");
|
||||||
|
|
||||||
|
b.Property<int>("VictimId");
|
||||||
|
|
||||||
|
b.Property<int?>("ViewAnglesVector3Id");
|
||||||
|
|
||||||
|
b.Property<int>("Weapon");
|
||||||
|
|
||||||
|
b.Property<DateTime>("When");
|
||||||
|
|
||||||
|
b.HasKey("KillId");
|
||||||
|
|
||||||
|
b.HasIndex("AttackerId");
|
||||||
|
|
||||||
|
b.HasIndex("DeathOriginVector3Id");
|
||||||
|
|
||||||
|
b.HasIndex("KillOriginVector3Id");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.HasIndex("VictimId");
|
||||||
|
|
||||||
|
b.HasIndex("ViewAnglesVector3Id");
|
||||||
|
|
||||||
|
b.ToTable("EFClientKills");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientMessage", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("MessageId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ClientId");
|
||||||
|
|
||||||
|
b.Property<string>("Message");
|
||||||
|
|
||||||
|
b.Property<int>("ServerId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("TimeSent");
|
||||||
|
|
||||||
|
b.HasKey("MessageId");
|
||||||
|
|
||||||
|
b.HasIndex("ClientId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("EFClientMessages");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatHistory", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("StatHistoryId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ClientId");
|
||||||
|
|
||||||
|
b.Property<int>("ServerId");
|
||||||
|
|
||||||
|
b.HasKey("StatHistoryId");
|
||||||
|
|
||||||
|
b.HasIndex("ClientId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("EFClientStatHistory");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ClientId");
|
||||||
|
|
||||||
|
b.Property<int>("ServerId");
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("Deaths");
|
||||||
|
|
||||||
|
b.Property<double>("EloRating");
|
||||||
|
|
||||||
|
b.Property<int>("Kills");
|
||||||
|
|
||||||
|
b.Property<double>("MaxStrain");
|
||||||
|
|
||||||
|
b.Property<double>("RollingWeightedKDR");
|
||||||
|
|
||||||
|
b.Property<double>("SPM");
|
||||||
|
|
||||||
|
b.Property<double>("Skill");
|
||||||
|
|
||||||
|
b.Property<int>("TimePlayed");
|
||||||
|
|
||||||
|
b.HasKey("ClientId", "ServerId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("EFClientStatistics");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFHitLocationCount", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("HitLocationCountId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ClientId")
|
||||||
|
.HasColumnName("EFClientStatistics_ClientId");
|
||||||
|
|
||||||
|
b.Property<int>("HitCount");
|
||||||
|
|
||||||
|
b.Property<float>("HitOffsetAverage");
|
||||||
|
|
||||||
|
b.Property<int>("Location");
|
||||||
|
|
||||||
|
b.Property<float>("MaxAngleDistance");
|
||||||
|
|
||||||
|
b.Property<int>("ServerId")
|
||||||
|
.HasColumnName("EFClientStatistics_ServerId");
|
||||||
|
|
||||||
|
b.HasKey("HitLocationCountId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.HasIndex("ClientId", "ServerId");
|
||||||
|
|
||||||
|
b.ToTable("EFHitLocationCounts");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("RatingId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ClientId");
|
||||||
|
|
||||||
|
b.Property<int?>("EFClientAverageStatHistoryClientId");
|
||||||
|
|
||||||
|
b.Property<int?>("EFClientStatHistoryStatHistoryId");
|
||||||
|
|
||||||
|
b.Property<double>("Performance");
|
||||||
|
|
||||||
|
b.Property<int>("Ranking");
|
||||||
|
|
||||||
|
b.HasKey("RatingId");
|
||||||
|
|
||||||
|
b.HasIndex("ClientId");
|
||||||
|
|
||||||
|
b.HasIndex("EFClientAverageStatHistoryClientId");
|
||||||
|
|
||||||
|
b.HasIndex("EFClientStatHistoryStatHistoryId");
|
||||||
|
|
||||||
|
b.ToTable("EFRating");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServer", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ServerId");
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("Port");
|
||||||
|
|
||||||
|
b.HasKey("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("EFServers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("StatisticId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ServerId");
|
||||||
|
|
||||||
|
b.Property<long>("TotalKills");
|
||||||
|
|
||||||
|
b.Property<long>("TotalPlayTime");
|
||||||
|
|
||||||
|
b.HasKey("StatisticId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("EFServerStatistics");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAlias", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("AliasId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<DateTime>("DateAdded");
|
||||||
|
|
||||||
|
b.Property<int>("IPAddress");
|
||||||
|
|
||||||
|
b.Property<int>("LinkId");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasKey("AliasId");
|
||||||
|
|
||||||
|
b.HasIndex("LinkId");
|
||||||
|
|
||||||
|
b.ToTable("EFAlias");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAliasLink", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("AliasLinkId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.HasKey("AliasLinkId");
|
||||||
|
|
||||||
|
b.ToTable("EFAliasLinks");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFClient", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ClientId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("AliasLinkId");
|
||||||
|
|
||||||
|
b.Property<int>("Connections");
|
||||||
|
|
||||||
|
b.Property<int>("CurrentAliasId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("FirstConnection");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastConnection");
|
||||||
|
|
||||||
|
b.Property<int>("Level");
|
||||||
|
|
||||||
|
b.Property<bool>("Masked");
|
||||||
|
|
||||||
|
b.Property<long>("NetworkId");
|
||||||
|
|
||||||
|
b.Property<string>("Password");
|
||||||
|
|
||||||
|
b.Property<string>("PasswordSalt");
|
||||||
|
|
||||||
|
b.Property<int>("TotalConnectionTime");
|
||||||
|
|
||||||
|
b.HasKey("ClientId");
|
||||||
|
|
||||||
|
b.HasIndex("AliasLinkId");
|
||||||
|
|
||||||
|
b.HasIndex("CurrentAliasId");
|
||||||
|
|
||||||
|
b.HasIndex("NetworkId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("EFClients");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFPenalty", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("PenaltyId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<string>("AutomatedOffense");
|
||||||
|
|
||||||
|
b.Property<DateTime>("Expires");
|
||||||
|
|
||||||
|
b.Property<int>("LinkId");
|
||||||
|
|
||||||
|
b.Property<int>("OffenderId");
|
||||||
|
|
||||||
|
b.Property<string>("Offense")
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Property<int>("PunisherId");
|
||||||
|
|
||||||
|
b.Property<int>("Type");
|
||||||
|
|
||||||
|
b.Property<DateTime>("When");
|
||||||
|
|
||||||
|
b.HasKey("PenaltyId");
|
||||||
|
|
||||||
|
b.HasIndex("LinkId");
|
||||||
|
|
||||||
|
b.HasIndex("OffenderId");
|
||||||
|
|
||||||
|
b.HasIndex("PunisherId");
|
||||||
|
|
||||||
|
b.ToTable("EFPenalties");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Helpers.Vector3", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Vector3Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<float>("X");
|
||||||
|
|
||||||
|
b.Property<float>("Y");
|
||||||
|
|
||||||
|
b.Property<float>("Z");
|
||||||
|
|
||||||
|
b.HasKey("Vector3Id");
|
||||||
|
|
||||||
|
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")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AttackerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "DeathOrigin")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("DeathOriginVector3Id");
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "KillOrigin")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("KillOriginVector3Id");
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Victim")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("VictimId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Helpers.Vector3", "ViewAngles")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ViewAnglesVector3Id");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientMessage", 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.EFClientStatHistory", 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 =>
|
||||||
|
{
|
||||||
|
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.EFHitLocationCount", 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);
|
||||||
|
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics")
|
||||||
|
.WithMany("HitLocations")
|
||||||
|
.HasForeignKey("ClientId", "ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ClientId")
|
||||||
|
.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");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ServerId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAlias", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "Link")
|
||||||
|
.WithMany("Children")
|
||||||
|
.HasForeignKey("LinkId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFClient", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "AliasLink")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AliasLinkId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFAlias", "CurrentAlias")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CurrentAliasId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFPenalty", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "Link")
|
||||||
|
.WithMany("ReceivedPenalties")
|
||||||
|
.HasForeignKey("LinkId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Offender")
|
||||||
|
.WithMany("ReceivedPenalties")
|
||||||
|
.HasForeignKey("OffenderId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Punisher")
|
||||||
|
.WithMany("AdministeredPenalties")
|
||||||
|
.HasForeignKey("PunisherId")
|
||||||
|
.OnDelete(DeleteBehavior.Restrict);
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,139 @@
|
|||||||
|
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<string>(
|
||||||
|
name: "AutomatedOffense",
|
||||||
|
table: "EFPenalties",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "EFClientAverageStatHistory",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
ClientId = table.Column<int>(nullable: false),
|
||||||
|
Active = table.Column<bool>(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<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
Active = table.Column<bool>(nullable: false),
|
||||||
|
ClientId = table.Column<int>(nullable: false),
|
||||||
|
ServerId = table.Column<int>(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<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
Active = table.Column<bool>(nullable: false),
|
||||||
|
ClientId = table.Column<int>(nullable: false),
|
||||||
|
EFClientAverageStatHistoryClientId = table.Column<int>(nullable: true),
|
||||||
|
EFClientStatHistoryStatHistoryId = table.Column<int>(nullable: true),
|
||||||
|
Performance = table.Column<double>(nullable: false),
|
||||||
|
Ranking = table.Column<int>(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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -20,6 +20,17 @@ namespace SharedLibraryCore.Migrations
|
|||||||
modelBuilder
|
modelBuilder
|
||||||
.HasAnnotation("ProductVersion", "2.0.2-rtm-10011");
|
.HasAnnotation("ProductVersion", "2.0.2-rtm-10011");
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientAverageStatHistory", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("ClientId");
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.HasKey("ClientId");
|
||||||
|
|
||||||
|
b.ToTable("EFClientAverageStatHistory");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b =>
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b =>
|
||||||
{
|
{
|
||||||
b.Property<long>("KillId")
|
b.Property<long>("KillId")
|
||||||
@ -92,6 +103,26 @@ namespace SharedLibraryCore.Migrations
|
|||||||
b.ToTable("EFClientMessages");
|
b.ToTable("EFClientMessages");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatHistory", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("StatHistoryId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ClientId");
|
||||||
|
|
||||||
|
b.Property<int>("ServerId");
|
||||||
|
|
||||||
|
b.HasKey("StatHistoryId");
|
||||||
|
|
||||||
|
b.HasIndex("ClientId");
|
||||||
|
|
||||||
|
b.HasIndex("ServerId");
|
||||||
|
|
||||||
|
b.ToTable("EFClientStatHistory");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b =>
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("ClientId");
|
b.Property<int>("ClientId");
|
||||||
@ -153,6 +184,34 @@ namespace SharedLibraryCore.Migrations
|
|||||||
b.ToTable("EFHitLocationCounts");
|
b.ToTable("EFHitLocationCounts");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("RatingId")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<int>("ClientId");
|
||||||
|
|
||||||
|
b.Property<int?>("EFClientAverageStatHistoryClientId");
|
||||||
|
|
||||||
|
b.Property<int?>("EFClientStatHistoryStatHistoryId");
|
||||||
|
|
||||||
|
b.Property<double>("Performance");
|
||||||
|
|
||||||
|
b.Property<int>("Ranking");
|
||||||
|
|
||||||
|
b.HasKey("RatingId");
|
||||||
|
|
||||||
|
b.HasIndex("ClientId");
|
||||||
|
|
||||||
|
b.HasIndex("EFClientAverageStatHistoryClientId");
|
||||||
|
|
||||||
|
b.HasIndex("EFClientStatHistoryStatHistoryId");
|
||||||
|
|
||||||
|
b.ToTable("EFRating");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServer", b =>
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServer", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("ServerId");
|
b.Property<int>("ServerId");
|
||||||
@ -269,6 +328,8 @@ namespace SharedLibraryCore.Migrations
|
|||||||
|
|
||||||
b.Property<bool>("Active");
|
b.Property<bool>("Active");
|
||||||
|
|
||||||
|
b.Property<string>("AutomatedOffense");
|
||||||
|
|
||||||
b.Property<DateTime>("Expires");
|
b.Property<DateTime>("Expires");
|
||||||
|
|
||||||
b.Property<int>("LinkId");
|
b.Property<int>("LinkId");
|
||||||
@ -311,6 +372,14 @@ namespace SharedLibraryCore.Migrations
|
|||||||
b.ToTable("Vector3");
|
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 =>
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Attacker")
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Attacker")
|
||||||
@ -354,6 +423,19 @@ namespace SharedLibraryCore.Migrations
|
|||||||
.OnDelete(DeleteBehavior.Cascade);
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatHistory", 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 =>
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
@ -385,6 +467,22 @@ namespace SharedLibraryCore.Migrations
|
|||||||
.OnDelete(DeleteBehavior.Cascade);
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("ClientId")
|
||||||
|
.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");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b =>
|
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
|
||||||
|
@ -28,6 +28,7 @@ namespace SharedLibraryCore.Services
|
|||||||
Expires = newEntity.Expires,
|
Expires = newEntity.Expires,
|
||||||
Offense = newEntity.Offense,
|
Offense = newEntity.Offense,
|
||||||
When = newEntity.When,
|
When = newEntity.When,
|
||||||
|
AutomatedOffense = newEntity.AutomatedOffense
|
||||||
};
|
};
|
||||||
|
|
||||||
if (addedEntity.Expires == DateTime.MaxValue)
|
if (addedEntity.Expires == DateTime.MaxValue)
|
||||||
@ -162,7 +163,8 @@ namespace SharedLibraryCore.Services
|
|||||||
PunisherId = penalty.PunisherId,
|
PunisherId = penalty.PunisherId,
|
||||||
Offense = penalty.Offense,
|
Offense = penalty.Offense,
|
||||||
Type = penalty.Type.ToString(),
|
Type = penalty.Type.ToString(),
|
||||||
TimeRemaining = now > penalty.Expires ? "" : penalty.Expires.ToString()
|
TimeRemaining = now > penalty.Expires ? "" : penalty.Expires.ToString(),
|
||||||
|
AutomatedOffense = penalty.AutomatedOffense
|
||||||
},
|
},
|
||||||
When = penalty.When,
|
When = penalty.When,
|
||||||
Sensitive = penalty.Type == Penalty.PenaltyType.Flag
|
Sensitive = penalty.Type == Penalty.PenaltyType.Flag
|
||||||
@ -206,7 +208,8 @@ namespace SharedLibraryCore.Services
|
|||||||
PunisherName = punisherAlias.Name,
|
PunisherName = punisherAlias.Name,
|
||||||
PunisherId = penalty.PunisherId,
|
PunisherId = penalty.PunisherId,
|
||||||
Offense = penalty.Offense,
|
Offense = penalty.Offense,
|
||||||
Type = penalty.Type.ToString()
|
Type = penalty.Type.ToString(),
|
||||||
|
AutomatedOffense = penalty.AutomatedOffense
|
||||||
},
|
},
|
||||||
When = penalty.When,
|
When = penalty.When,
|
||||||
Sensitive = penalty.Type == Penalty.PenaltyType.Flag
|
Sensitive = penalty.Type == Penalty.PenaltyType.Flag
|
||||||
|
@ -43,7 +43,8 @@ namespace WebfrontCore.Controllers
|
|||||||
PunisherId = p.PunisherId,
|
PunisherId = p.PunisherId,
|
||||||
Type = p.Type.ToString(),
|
Type = p.Type.ToString(),
|
||||||
TimePunished = p.When.ToString(),
|
TimePunished = p.When.ToString(),
|
||||||
TimeRemaining = p.Expires.ToString()
|
TimeRemaining = p.Expires.ToString(),
|
||||||
|
AutomatedOffense = p.AutomatedOffense
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
return Json(penaltiesDto);
|
return Json(penaltiesDto);
|
||||||
|
@ -20,11 +20,12 @@ namespace WebfrontCore.ViewComponents
|
|||||||
PunisherId = p.PunisherId,
|
PunisherId = p.PunisherId,
|
||||||
PunisherName = p.Punisher.Name,
|
PunisherName = p.Punisher.Name,
|
||||||
PunisherLevel = p.Punisher.Level.ToString(),
|
PunisherLevel = p.Punisher.Level.ToString(),
|
||||||
Offense = p.Offense,
|
Offense = User.Identity.IsAuthenticated && !string.IsNullOrEmpty(p.AutomatedOffense) ? p.AutomatedOffense : p.Offense,
|
||||||
Type = p.Type.ToString(),
|
Type = p.Type.ToString(),
|
||||||
TimePunished = Utilities.GetTimePassed(p.When, false),
|
TimePunished = Utilities.GetTimePassed(p.When, false),
|
||||||
TimeRemaining = DateTime.UtcNow > p.Expires ? "" : Utilities.TimeSpanText(p.Expires - DateTime.UtcNow),
|
TimeRemaining = DateTime.UtcNow > p.Expires ? "" : Utilities.TimeSpanText(p.Expires - DateTime.UtcNow),
|
||||||
Sensitive = p.Type == Penalty.PenaltyType.Flag
|
Sensitive = p.Type == Penalty.PenaltyType.Flag,
|
||||||
|
AutomatedOffense = p.AutomatedOffense
|
||||||
});
|
});
|
||||||
|
|
||||||
penaltiesDto = User.Identity.IsAuthenticated ? penaltiesDto.ToList() : penaltiesDto.Where(p => !p.Sensitive).ToList();
|
penaltiesDto = User.Identity.IsAuthenticated ? penaltiesDto.ToList() : penaltiesDto.Where(p => !p.Sensitive).ToList();
|
||||||
|
@ -23,7 +23,8 @@
|
|||||||
"wwwroot/js/profile.js",
|
"wwwroot/js/profile.js",
|
||||||
"wwwroot/js/server.js",
|
"wwwroot/js/server.js",
|
||||||
"wwwroot/js/search.js",
|
"wwwroot/js/search.js",
|
||||||
"wwwroot/js/loader.js"
|
"wwwroot/js/loader.js",
|
||||||
|
"wwwroot/js/stats.js"
|
||||||
],
|
],
|
||||||
// Optionally specify minification options
|
// Optionally specify minification options
|
||||||
"minify": {
|
"minify": {
|
||||||
|
17
WebfrontCore/wwwroot/css/bootstrap-custom.scss
vendored
17
WebfrontCore/wwwroot/css/bootstrap-custom.scss
vendored
@ -179,7 +179,18 @@ select {
|
|||||||
margin-top: -3px;
|
margin-top: -3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.stats-ranking-icon {
|
.striped > div:nth-child(even) {
|
||||||
width: 32px;
|
background-color: rgba(0, 0, 0, 0.125);
|
||||||
height: 32px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.striped > div:nth-child(odd) {
|
||||||
|
background-color: rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.client-rating-graph {
|
||||||
|
min-height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.client-rating-icon {
|
||||||
|
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
let offset = 15;
|
let loaderOffset = 25;
|
||||||
let loadCount = 15;
|
let loadCount = 25;
|
||||||
let isLoading = false;
|
let isLoaderLoading = false;
|
||||||
let loadUri = '';
|
let loadUri = '';
|
||||||
let loaderResponseId = '';
|
let loaderResponseId = '';
|
||||||
|
|
||||||
@ -11,26 +11,26 @@ function initLoader(location, loaderId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function loadMoreItems() {
|
function loadMoreItems() {
|
||||||
if (isLoading) {
|
if (isLoaderLoading) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
showLoader();
|
showLoader();
|
||||||
isLoading = true;
|
isLoaderLoading = true;
|
||||||
$.get(loadUri, { offset: offset, count : loadCount })
|
$.get(loadUri, { offset: loaderOffset, count : loadCount })
|
||||||
.done(function (response) {
|
.done(function (response) {
|
||||||
$(loaderResponseId).append(response);
|
$(loaderResponseId).append(response);
|
||||||
if (response.trim().length === 0) {
|
if (response.trim().length === 0) {
|
||||||
staleLoader();
|
staleLoader();
|
||||||
}
|
}
|
||||||
hideLoader();
|
hideLoader();
|
||||||
isLoading = false;
|
isLoaderLoading = false;
|
||||||
})
|
})
|
||||||
.fail(function (jqxhr, statis, error) {
|
.fail(function (jqxhr, statis, error) {
|
||||||
errorLoader();
|
errorLoader();
|
||||||
isLoading = false;
|
isLoaderLoading = false;
|
||||||
});
|
});
|
||||||
offset += loadCount;
|
loaderOffset += loadCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupListeners() {
|
function setupListeners() {
|
||||||
|
61
WebfrontCore/wwwroot/js/stats.js
Normal file
61
WebfrontCore/wwwroot/js/stats.js
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
function getStatsChart(id, width, height) {
|
||||||
|
const data = $('#' + id).data('history');
|
||||||
|
let fixedData = [];
|
||||||
|
data.forEach(function (item, i) {
|
||||||
|
fixedData[i] = { x: i, y: item };
|
||||||
|
});
|
||||||
|
|
||||||
|
return new CanvasJS.Chart(id, {
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
height: height,
|
||||||
|
width: width,
|
||||||
|
animationEnabled: false,
|
||||||
|
toolTip: {
|
||||||
|
contentFormatter: function (e) {
|
||||||
|
return e.entries[0].dataPoint.y;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisX: {
|
||||||
|
interval: 1,
|
||||||
|
gridThickness: 0,
|
||||||
|
lineThickness: 0,
|
||||||
|
tickThickness: 0,
|
||||||
|
margin: 0,
|
||||||
|
valueFormatString: " "
|
||||||
|
},
|
||||||
|
axisY: {
|
||||||
|
gridThickness: 0,
|
||||||
|
lineThickness: 0,
|
||||||
|
tickThickness: 0,
|
||||||
|
minimum: Math.min(...data) - 15,
|
||||||
|
maximum: Math.max(...data) + 15,
|
||||||
|
margin: 0,
|
||||||
|
valueFormatString: " ",
|
||||||
|
labelMaxWidth: 0
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
maxWidth: 0,
|
||||||
|
maxHeight: 0,
|
||||||
|
dockInsidePlotArea: true
|
||||||
|
},
|
||||||
|
data: [{
|
||||||
|
showInLegend: false,
|
||||||
|
type: "splineArea",
|
||||||
|
color: 'rgba(0, 122, 204, 0.25)',
|
||||||
|
markerSize: 0,
|
||||||
|
dataPoints: fixedData
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
|
$('.client-rating-graph').each(function (i, element) {
|
||||||
|
getStatsChart($(element).attr('id'), $(element).width(), $(element).height()).render();
|
||||||
|
});
|
||||||
|
|
||||||
|
$(window).resize(function () {
|
||||||
|
$('.client-rating-graph').each(function (index, element) {
|
||||||
|
getStatsChart($(element).attr('id'), $(element).width(), $(element).height()).render();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user