added meta property and service for clients
started workign on a new profile page for clients
This commit is contained in:
parent
d2ead61061
commit
c599d8ef20
@ -127,6 +127,7 @@
|
||||
<HintPath>lib\Kayak.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
@ -164,6 +165,9 @@
|
||||
<Content Include="Webfront\images\minimap_mp_terminal.png">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Webfront\profile.html">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
<Content Include="Webfront\scripts\wordcloud2.js">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
|
@ -58,7 +58,11 @@ namespace IW4MAdmin
|
||||
|
||||
bool binaryContent = requestedPage.BinaryContent != null;
|
||||
if (requestedPage.content != null && requestedPage.content.GetType() != typeof(string))
|
||||
#if !DEBUG
|
||||
requestedPage.content = Newtonsoft.Json.JsonConvert.SerializeObject(requestedPage.content);
|
||||
#else
|
||||
requestedPage.content = Newtonsoft.Json.JsonConvert.SerializeObject(requestedPage.content, Newtonsoft.Json.Formatting.Indented);
|
||||
#endif
|
||||
|
||||
string maxAge = requestedPage.contentType == "application/json" ? "0" : "31536000";
|
||||
var headers = new HttpResponseHead()
|
||||
|
@ -23,6 +23,7 @@ namespace IW4MAdmin
|
||||
{
|
||||
return Math.Abs($"{IP}:{Port.ToString()}".GetHashCode());
|
||||
}
|
||||
|
||||
override public async Task<bool> AddPlayer(Player polledPlayer)
|
||||
{
|
||||
if (polledPlayer.Ping == 999 || polledPlayer.Ping < 1 || polledPlayer.ClientNumber > (MaxClients) || polledPlayer.ClientNumber < 0)
|
||||
|
@ -14,6 +14,8 @@ using System.Threading.Tasks;
|
||||
using SharedLibrary.Services;
|
||||
using System.Linq.Expressions;
|
||||
using SharedLibrary.Database.Models;
|
||||
using System.Collections.Specialized;
|
||||
using SharedLibrary.Dtos;
|
||||
|
||||
namespace IW4MAdmin
|
||||
{
|
||||
@ -41,8 +43,10 @@ namespace IW4MAdmin
|
||||
SharedLibrary.WebService.PageList.Add(new PubbansJSON());
|
||||
SharedLibrary.WebService.PageList.Add(new AdminsJSON());
|
||||
SharedLibrary.WebService.PageList.Add(new Admins());
|
||||
SharedLibrary.WebService.PageList.Add(new Profile());
|
||||
|
||||
SchedulerThread = new Thread(() => {
|
||||
SchedulerThread = new Thread(() =>
|
||||
{
|
||||
ScheduleThreadStart(WebScheduler, WebServer);
|
||||
})
|
||||
{
|
||||
@ -389,7 +393,7 @@ namespace IW4MAdmin
|
||||
admin = admins.First(a => a.IPAddress == 0).AsPlayer();
|
||||
|
||||
if (admin == null)
|
||||
admin = new Player() { Name = "RestUser"};
|
||||
admin = new Player() { Name = "RestUser" };
|
||||
|
||||
Event remoteEvent = new Event(Event.GType.Say, querySet["command"], admin, null, S)
|
||||
{
|
||||
@ -414,7 +418,7 @@ namespace IW4MAdmin
|
||||
|
||||
else
|
||||
{
|
||||
cmd.Add(new SharedLibrary.Helpers.CommandResult() { Clientd = 0, Message = "No command entered" });
|
||||
cmd.Add(new SharedLibrary.Helpers.CommandResult() { Clientd = 0, Message = "No command entered" });
|
||||
}
|
||||
|
||||
HttpResponse resp = new HttpResponse()
|
||||
@ -627,10 +631,10 @@ namespace IW4MAdmin
|
||||
contentType = GetContentType(),
|
||||
content = Admins.Select(a => new
|
||||
{
|
||||
a.ClientId,
|
||||
a.Level,
|
||||
a.Name,
|
||||
playerID = a.ClientId
|
||||
a.ClientId,
|
||||
a.Level,
|
||||
a.Name,
|
||||
playerID = a.ClientId
|
||||
}),
|
||||
additionalHeaders = new Dictionary<string, string>()
|
||||
};
|
||||
@ -698,9 +702,8 @@ namespace IW4MAdmin
|
||||
return "/pages";
|
||||
}
|
||||
|
||||
public async Task<HttpResponse> GetPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary<string, string> headers)
|
||||
public async Task<HttpResponse> GetPage(NameValueCollection querySet, IDictionary<string, string> headers)
|
||||
{
|
||||
|
||||
var pages = SharedLibrary.WebService.PageList.Select(p => new
|
||||
{
|
||||
pagePath = p.GetPath(),
|
||||
@ -745,7 +748,7 @@ namespace IW4MAdmin
|
||||
return "GetPlayer";
|
||||
}
|
||||
|
||||
public async Task<HttpResponse> GetPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary<string, string> headers)
|
||||
public async Task<HttpResponse> GetPage(NameValueCollection querySet, IDictionary<string, string> headers)
|
||||
{
|
||||
List<PlayerInfo> pInfo = new List<PlayerInfo>();
|
||||
IList<EFClient> matchedPlayers = new List<EFClient>();
|
||||
@ -788,12 +791,22 @@ namespace IW4MAdmin
|
||||
recent = true;
|
||||
}
|
||||
|
||||
bool isProfile = querySet["profile"] != null;
|
||||
|
||||
if (matchedPlayers != null && matchedPlayers.Count > 0)
|
||||
{
|
||||
foreach (var pp in matchedPlayers)
|
||||
{
|
||||
if (pp == null) continue;
|
||||
|
||||
List<ProfileMeta> meta = new List<ProfileMeta>();
|
||||
if (isProfile)
|
||||
{
|
||||
meta.AddRange(await ApplicationManager.GetInstance().GetPenaltyService().ReadGetClientPenaltiesAsync(pp.ClientId));
|
||||
meta.AddRange(await ApplicationManager.GetInstance().GetPenaltyService().ReadGetClientPenaltiesAsync(pp.ClientId, false));
|
||||
meta.AddRange(await MetaService.GetMeta(pp.ClientId));
|
||||
}
|
||||
|
||||
PlayerInfo eachPlayer = new PlayerInfo()
|
||||
{
|
||||
playerIP = pp.IPAddressString,
|
||||
@ -801,16 +814,19 @@ namespace IW4MAdmin
|
||||
playerLevel = pp.Level.ToString(),
|
||||
playerName = pp.Name,
|
||||
playernpID = pp.NetworkId.ToString(),
|
||||
forumID = -1,
|
||||
authed = authed,
|
||||
showV2Features = false,
|
||||
playerAliases = new List<string>(),
|
||||
playerIPs = new List<string>()
|
||||
playerIPs = new List<string>(),
|
||||
Meta = meta.OrderByDescending(m => m.When).ToList(),
|
||||
FirstSeen = Utilities.GetTimePassed(pp.FirstConnection, false),
|
||||
TimePlayed = Math.Round(pp.TotalConnectionTime / 3600.0, 1).ToString("#,##0"),
|
||||
LastSeen = Utilities.GetTimePassed(pp.LastConnection, false)
|
||||
};
|
||||
|
||||
if (!recent)
|
||||
{
|
||||
eachPlayer.playerAliases = pp.AliasLink.Children
|
||||
.Where(a => a.Name != eachPlayer.playerName)
|
||||
.OrderBy(a => a.Name)
|
||||
.Select(a => a.Name)
|
||||
.Distinct()
|
||||
@ -824,15 +840,14 @@ namespace IW4MAdmin
|
||||
}
|
||||
|
||||
//eachPlayer.playerAliases = eachPlayer.playerAliases.Distinct().ToList();
|
||||
// eachPlayer.playerIPs = eachPlayer.playerIPs.Distinct().ToList();
|
||||
// eachPlayer.playerIPs = eachPlayer.playerIPs.Distinct().ToList();
|
||||
|
||||
eachPlayer.playerConnections = pp.Connections;
|
||||
eachPlayer.lastSeen = Utilities.GetTimePassed(pp.LastConnection);
|
||||
pInfo.Add(eachPlayer);
|
||||
|
||||
}
|
||||
|
||||
resp.content = Newtonsoft.Json.JsonConvert.SerializeObject(pInfo);
|
||||
resp.content = pInfo;
|
||||
return resp;
|
||||
}
|
||||
|
||||
@ -846,6 +861,21 @@ namespace IW4MAdmin
|
||||
}
|
||||
}
|
||||
|
||||
class Profile : HTMLPage
|
||||
{
|
||||
public override string GetPath() => "/profile";
|
||||
public override string GetContent(NameValueCollection querySet, IDictionary<string, string> headers)
|
||||
{
|
||||
IFile admins = new IFile("webfront\\profile.html");
|
||||
string content = admins.GetText();
|
||||
admins.Close();
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
public override string GetName() => "Client Profile";
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
struct ServerInfo
|
||||
{
|
||||
@ -876,13 +906,14 @@ namespace IW4MAdmin
|
||||
public string playerLevel;
|
||||
public string playerIP;
|
||||
public string playernpID;
|
||||
public Int64 forumID;
|
||||
public List<string> playerAliases;
|
||||
public List<string> playerIPs;
|
||||
public int playerConnections;
|
||||
public string lastSeen;
|
||||
public bool showV2Features;
|
||||
public string LastSeen;
|
||||
public string FirstSeen;
|
||||
public string TimePlayed;
|
||||
public bool authed;
|
||||
public List<ProfileMeta> Meta;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
|
322
Admin/Webfront/profile.html
Normal file
322
Admin/Webfront/profile.html
Normal file
@ -0,0 +1,322 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
|
||||
<title>IW4MAdmin by RaidMax</title>
|
||||
<meta name="description" content="Administration tool for IW4M servers. IW4MAdmin Created by RaidMax">
|
||||
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/open-iconic/1.1.1/font/css/open-iconic-bootstrap.min.css" />
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
|
||||
<script src="http://code.jquery.com/jquery-3.3.1.min.js"
|
||||
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
|
||||
crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
|
||||
<style>
|
||||
#profile_avatar {
|
||||
height: 200px;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.profile-shortcode {
|
||||
font-size: 150pt;
|
||||
line-height: 175px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.text-highlight {
|
||||
color: rgb(0, 122, 204) !important;
|
||||
}
|
||||
|
||||
#profile_info {
|
||||
color: white;
|
||||
}
|
||||
|
||||
#profile_name {
|
||||
font-size: 4em;
|
||||
line-height: 1em;
|
||||
}
|
||||
|
||||
#profile_info > .text-muted {
|
||||
font-size: 1.5em;
|
||||
line-height: 1.25em;
|
||||
}
|
||||
|
||||
#content,
|
||||
.container-fluid, #profile_aliases {
|
||||
background-color: rgb(34, 34, 34);
|
||||
}
|
||||
|
||||
#profile_level > span.level {
|
||||
color: rgba(236, 130, 222, 0.69);
|
||||
font-weight: bold;
|
||||
font-size: 1.5em;
|
||||
line-height: 1.4em;
|
||||
}
|
||||
|
||||
#profile_wrapper {
|
||||
border-bottom: 2px rgb(0, 122, 204) solid;
|
||||
}
|
||||
|
||||
.level-color-user, .level-color-guest {
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
}
|
||||
|
||||
.level-bgcolor-user, .level-bgcolor-guest {
|
||||
background-color: rgba(255, 255, 255, 0.85);
|
||||
}
|
||||
|
||||
.level-color-trusted, .level-color-user {
|
||||
color: rgba(116,147,99,1);
|
||||
}
|
||||
|
||||
.level-bgcolor-trusted, .level-bgcolor-user {
|
||||
background-color: rgba(116,147,99,1);
|
||||
}
|
||||
|
||||
.level-color-flagged {
|
||||
color: rgba(253, 139, 22, 0.85);
|
||||
}
|
||||
|
||||
.level-bgcolor-flagged {
|
||||
background-color: rgba(253, 139, 22, 0.85);
|
||||
}
|
||||
|
||||
.level-color-banned {
|
||||
color: rgba(255, 69, 69, 0.85);
|
||||
}
|
||||
|
||||
.level-bgcolor-banned {
|
||||
background-color: rgba(255, 69, 69, 0.85);
|
||||
}
|
||||
|
||||
.level-color-moderator {
|
||||
color: rgba(235, 211, 101, 0.75);
|
||||
}
|
||||
|
||||
.level-bgcolor-moderator {
|
||||
background-color: rgba(235, 211, 101, 0.75);
|
||||
}
|
||||
|
||||
.level-color-administrator {
|
||||
color: rgba(236, 130, 222, 0.69);
|
||||
}
|
||||
|
||||
.level-bgcolor-administrator {
|
||||
background-color: rgba(236, 130, 222, 0.69);
|
||||
}
|
||||
|
||||
.level-color-senioradmin {
|
||||
color: rgba(50, 177, 185, 0.85);
|
||||
}
|
||||
|
||||
.level-bgcolor-senioradmin {
|
||||
background-color: rgba(50, 177, 185, 0.85);
|
||||
}
|
||||
|
||||
.level-color-owner {
|
||||
color: rgb(0, 122, 204);
|
||||
}
|
||||
|
||||
.level-bgcolor-owner {
|
||||
background-color: rgb(0, 122, 204);
|
||||
}
|
||||
|
||||
.profile-meta-title {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.profile-meta-entry {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
.penalties-color-kick {
|
||||
color: rgba(116, 147, 99, 1);
|
||||
}
|
||||
|
||||
.penalties-color-report {
|
||||
color: rgba(116, 147, 99, 1);
|
||||
}
|
||||
|
||||
.penalties-color-warning {
|
||||
color: rgba(235, 211, 101, 0.75);
|
||||
}
|
||||
|
||||
.penalties-color-tempban {
|
||||
color: rgba(253, 139, 22, 0.85);
|
||||
}
|
||||
|
||||
.penalties-color-flag {
|
||||
color: rgba(253, 139, 22, 0.85);
|
||||
}
|
||||
|
||||
.penalties-color-ban {
|
||||
color: rgba(255, 69, 69, 0.85);
|
||||
}
|
||||
|
||||
#profile_aliases_btn {
|
||||
font-size: 0.5em;
|
||||
color: rgb(0, 122, 204);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#profile_aliases_btn:hover {
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#profile_aliases {
|
||||
position: relative;
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<script>
|
||||
function parseGet(val) {
|
||||
var result = "undefined",
|
||||
tmp = [];
|
||||
location.search
|
||||
.substr(1)
|
||||
.split("&")
|
||||
.forEach(function (item) {
|
||||
tmp = item.split("=");
|
||||
if (tmp[0] === val) result = decodeURIComponent(tmp[1]);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
function penaltyToName(penaltyName) {
|
||||
switch (penaltyName) {
|
||||
case "Flag":
|
||||
return "Flagged"
|
||||
case "Warning":
|
||||
return "Warned";
|
||||
case "Report":
|
||||
return "Reported";
|
||||
case "Ban":
|
||||
return "Banned";
|
||||
case "Kick":
|
||||
return "Kicked";
|
||||
case "TempBan":
|
||||
return "Temp Banned";
|
||||
}
|
||||
}
|
||||
|
||||
let playerInfo = undefined;
|
||||
|
||||
function loadMeta(meta) {
|
||||
let eventString = '';
|
||||
// it's a penalty
|
||||
if (meta.Class.includes("Penalty")) {
|
||||
if (meta.Value.PunisherId != playerInfo.playerID) {
|
||||
eventString = `<div><span class="penalties-color-${meta.Value.Type.toLowerCase()}">${penaltyToName(meta.Value.Type)}</span> by <span class="text-highlight"> <a href="/profile?id=${meta.Value.PunisherId}">${meta.Value.PunisherName}</a></span > for <span style="color: white; ">${meta.Value.Offense}</span> ${meta.WhenString} ago </div>`;
|
||||
}
|
||||
else {
|
||||
eventString = `<div><span class="penalties-color-${meta.Value.Type.toLowerCase()}">${penaltyToName(meta.Value.Type)} </span> <span class="text-highlight"><a href="/profile?id=${meta.Value.OffenderId}"> ${meta.Value.OffenderName}</a></span > for <span style="color: white; ">${meta.Value.Offense}</span> ${meta.WhenString} ago </div>`;
|
||||
}
|
||||
}
|
||||
// it's a message
|
||||
else if (meta.Key.includes("Event")) {
|
||||
eventString = `<div><span style="color:white;">></span><span class="text-muted"> ${meta.Value}</span></div>`;
|
||||
}
|
||||
$('#profile_events').append(eventString);
|
||||
}
|
||||
|
||||
let count = 1;
|
||||
$(window).scroll(function () {
|
||||
if ($(window).scrollTop() == $(document).height() - $(window).height() || $(document).height() == $(window).height()) {
|
||||
while (count % 40 != 0 && count < playerInfo.Meta.length) {
|
||||
loadMeta(playerInfo.Meta[count - 1]);
|
||||
count++;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
});
|
||||
|
||||
$(document).ready(function () {
|
||||
$("#profile_aliases_btn").click(function (e) {
|
||||
if ($("#profile_aliases").text() != '') {
|
||||
$("#profile_aliases").slideToggle(50);
|
||||
}
|
||||
});
|
||||
|
||||
jQuery.getJSON("/getplayer?profile=1&id=" + parseGet("id"), function (result) {
|
||||
playerInfo = result[0];
|
||||
|
||||
let firstLetter = playerInfo.playerName.match(/[a-zA-Z]/);
|
||||
if (firstLetter == undefined)
|
||||
firstLetter = '?';
|
||||
else
|
||||
firstLetter = firstLetter.pop().toUpperCase();
|
||||
|
||||
$('#profile_avatar').addClass('level-bgcolor-' + playerInfo.playerLevel.toLowerCase());
|
||||
$('#profile_avatar > .profile-shortcode').text(firstLetter);
|
||||
$('#profile_name > .client-name').prepend(playerInfo.playerName);
|
||||
$.each(playerInfo.playerAliases, function (index, alias) {
|
||||
$("#profile_aliases").append(alias + "<br/>");
|
||||
});
|
||||
$('#profile_time_played > .text-highlight').text(playerInfo.TimePlayed);
|
||||
$('#profile_level > span').text(playerInfo.playerLevel).addClass('level-color-' + playerInfo.playerLevel.toLowerCase());
|
||||
$('#profile_first_seen > .text-highlight').text(playerInfo.FirstSeen);
|
||||
$('#profile_last_seen > .text-highlight').text(playerInfo.LastSeen);
|
||||
|
||||
$.each(playerInfo.Meta, function (index, meta) {
|
||||
if (!meta.Key.includes("Event")) {
|
||||
let metaString = `<div class="profile-meta-entry"><span class="profile-meta-value text-highlight">${meta.Value}</span><span class="profile-meta-title"> ${meta.Key}</span></div>`;
|
||||
$("#profile_meta").append(metaString);
|
||||
}
|
||||
});
|
||||
|
||||
$.each(playerInfo.Meta, function (index, meta) {
|
||||
loadMeta(meta);
|
||||
|
||||
if (count % 40 == 0) {
|
||||
count++;
|
||||
return false;
|
||||
}
|
||||
count++
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container-fluid">
|
||||
<div id="content" class="p-4">
|
||||
<div id="profile_wrapper" class="row d-flex d-sm-inline-flex justify-content-center justify-content-left pb-4">
|
||||
<div class="mr-auto ml-auto ml-sm-0 mr-sm-0">
|
||||
<div id="profile_avatar" class="text-center">
|
||||
<span class="profile-shortcode">_</span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="profile_info" class="text-center text-sm-left pr-4 pl-4">
|
||||
<div id="profile_name">
|
||||
<span class="client-name"><span id="profile_aliases_btn" class="oi oi-caret-bottom pl-2"></span></span>
|
||||
<div id="profile_aliases" class="pr-4 pb-2 pt-2 text-muted"></div>
|
||||
</div>
|
||||
<div id="profile_level" class="text-muted">
|
||||
<span>_</span>
|
||||
</div>
|
||||
<div id="profile_time_played" class="text-muted">
|
||||
Played <span class="text-highlight">_</span> hours
|
||||
</div>
|
||||
<div id="profile_first_seen" class="text-muted">
|
||||
First seen <span class="text-highlight">_</span> ago
|
||||
</div>
|
||||
<div id="profile_last_seen" class="text-muted">
|
||||
Last seen <span class="text-highlight">_</span> ago
|
||||
</div>
|
||||
</div>
|
||||
<div id="profile_meta" class="text-center text-sm-right pt-2">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row d-md-flex pt-4">
|
||||
<div id="profile_events" class="text-muted text-left ml-sm-0">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Binary file not shown.
@ -50,7 +50,7 @@
|
||||
var p = "";
|
||||
p +=
|
||||
"<div class=\"playerInfo table alternate_" + i % 2 + "\"> \
|
||||
<div class=\"tableCell\"><a href=\"/players?id=" + player['playerID'] + "\">" + escapeHtml(player['playerName']) + "</a></div> \
|
||||
<div class=\"tableCell\"><a href=\"/profile?id=" + player['playerID'] + "\">" + escapeHtml(player['playerName']) + "</a></div> \
|
||||
<div class=\"tableCell\">" + formatHidden(player['playerAliases'], player.authed) + "</div> \
|
||||
<div class=\"tableCell\">" + formatHidden(player['playerIPs'], player.authed) + "</div> \
|
||||
<div class=\"tableCell\">" + getColorForLevel(player['playerLevel'], player['playerLevel']) + "</div> \
|
||||
@ -61,7 +61,7 @@
|
||||
"<div class=\"tableCell\" style='width: 2em;'><a href=\"/chat?clientid=" + player.playerID + "\"><i class=\"fa fa-comments\" aria-hidden=\"true\"></i></a></div>"
|
||||
|
||||
p +=
|
||||
"<div class=\"tableCell alignRight\">" + checkJustNow(player['lastSeen']) + "</div> \
|
||||
"<div class=\"tableCell alignRight\">" + checkJustNow(player['LastSeen']) + "</div> \
|
||||
</div>";
|
||||
|
||||
$("#playersTable").append(p);
|
||||
|
@ -5,6 +5,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using SharedLibrary;
|
||||
using SharedLibrary.Dtos;
|
||||
using SharedLibrary.Helpers;
|
||||
using SharedLibrary.Interfaces;
|
||||
using SharedLibrary.Services;
|
||||
@ -81,7 +82,65 @@ namespace StatsPlugin
|
||||
|
||||
public Task OnLoadAsync(IManager manager)
|
||||
{
|
||||
// todo: is this fast?
|
||||
// meta data info
|
||||
async Task<List<ProfileMeta>> getStats(int clientId)
|
||||
{
|
||||
var statsSvc = new GenericRepository<EFClientStatistics>();
|
||||
var clientStats = await statsSvc.FindAsync(c => c.ClientId == clientId);
|
||||
|
||||
int kills = clientStats.Sum(c => c.Kills);
|
||||
int deaths = clientStats.Sum(c => c.Deaths);
|
||||
double kdr = Math.Round(clientStats.Sum(c => c.KDR) / clientStats.Count, 2);
|
||||
double skill = Math.Round(clientStats.Sum(c => c.Skill) / clientStats.Count, 2);
|
||||
|
||||
return new List<ProfileMeta>()
|
||||
{
|
||||
new ProfileMeta()
|
||||
{
|
||||
Key = "Kills",
|
||||
Value = kills
|
||||
},
|
||||
new ProfileMeta()
|
||||
{
|
||||
Key = "Deaths",
|
||||
Value = deaths
|
||||
},
|
||||
new ProfileMeta()
|
||||
{
|
||||
Key = "KDR",
|
||||
Value = kdr
|
||||
},
|
||||
new ProfileMeta()
|
||||
{
|
||||
Key = "Skill",
|
||||
Value = skill
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async Task<List<ProfileMeta>> getMessages(int clientId)
|
||||
{
|
||||
var messageSvc = new GenericRepository<EFClientMessage>();
|
||||
var messages = await messageSvc.FindAsync(m => m.ClientId == clientId);
|
||||
var messageMeta = messages.Select(m => new ProfileMeta()
|
||||
{
|
||||
Key = "EventMessage",
|
||||
Value = m.Message,
|
||||
When = m.TimeSent
|
||||
}).ToList();
|
||||
messageMeta.Add(new ProfileMeta()
|
||||
{
|
||||
Key = "Messages",
|
||||
Value = messages.Count
|
||||
});
|
||||
|
||||
return messageMeta;
|
||||
}
|
||||
|
||||
MetaService.AddMeta(getStats);
|
||||
MetaService.AddMeta(getMessages);
|
||||
|
||||
// todo: is this fast? make async?
|
||||
string totalKills()
|
||||
{
|
||||
var serverStats = new GenericRepository<EFServerStatistics>();
|
||||
|
18
SharedLibrary/Dtos/ProfileMeta.cs
Normal file
18
SharedLibrary/Dtos/ProfileMeta.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharedLibrary.Dtos
|
||||
{
|
||||
public class ProfileMeta
|
||||
{
|
||||
public DateTime When { get; set; }
|
||||
public string WhenString => Utilities.GetTimePassed(When, false);
|
||||
public string Key { get; set; }
|
||||
public dynamic Value { get; set; }
|
||||
public virtual string Class => Value.GetType().ToString();
|
||||
}
|
||||
}
|
18
SharedLibrary/Dtos/ProfilePenalty.cs
Normal file
18
SharedLibrary/Dtos/ProfilePenalty.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharedLibrary.Dtos
|
||||
{
|
||||
public class ProfilePenalty
|
||||
{
|
||||
public string OffenderName { get; set; }
|
||||
public int OffenderId { get; set; }
|
||||
public string PunisherName { get; set; }
|
||||
public int PunisherId { get; set; }
|
||||
public string Offense { get; set; }
|
||||
public string Type { get; set; }
|
||||
}
|
||||
}
|
@ -75,6 +75,8 @@ namespace SharedLibrary.Objects
|
||||
public Server CurrentServer { get; set; }
|
||||
[NotMapped]
|
||||
public int Score { get; set; }
|
||||
[NotMapped]
|
||||
public IList<Dtos.ProfileMeta> Meta { get; set; }
|
||||
|
||||
private int _ipaddress;
|
||||
public override int IPAddress
|
||||
|
27
SharedLibrary/Services/MetaService.cs
Normal file
27
SharedLibrary/Services/MetaService.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using SharedLibrary.Dtos;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SharedLibrary.Services
|
||||
{
|
||||
public class MetaService
|
||||
{
|
||||
private static List<Func<int, Task<List<ProfileMeta>>>> MetaActions = new List<Func<int, Task<List<ProfileMeta>>>>();
|
||||
|
||||
public static void AddMeta(Func<int, Task<List<ProfileMeta>>> metaAction)
|
||||
{
|
||||
MetaActions.Add(metaAction);
|
||||
}
|
||||
|
||||
public static async Task<List<ProfileMeta>> GetMeta(int clientId)
|
||||
{
|
||||
var meta = new List<ProfileMeta>();
|
||||
foreach (var action in MetaActions)
|
||||
meta.AddRange(await action(clientId));
|
||||
return meta;
|
||||
}
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@ using System.Data.Entity;
|
||||
using SharedLibrary.Database;
|
||||
using SharedLibrary.Database.Models;
|
||||
using System.Linq.Expressions;
|
||||
using SharedLibrary.Dtos;
|
||||
|
||||
namespace SharedLibrary.Services
|
||||
{
|
||||
@ -56,6 +57,8 @@ namespace SharedLibrary.Services
|
||||
|
||||
public async Task<IList<EFPenalty>> Find(Func<EFPenalty, bool> expression)
|
||||
{
|
||||
return await Task.FromResult(new List<EFPenalty>());
|
||||
// fixme: this is so slow!
|
||||
return await Task.Run(() =>
|
||||
{
|
||||
using (var context = new DatabaseContext())
|
||||
@ -109,6 +112,86 @@ namespace SharedLibrary.Services
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a read-only copy of client penalties
|
||||
/// </summary>
|
||||
/// <param name="clientI"></param>
|
||||
/// <param name="victim">Retreive penalties for clients receiving penalties, other wise given</param>
|
||||
/// <returns></returns>
|
||||
public async Task<List<ProfileMeta>> ReadGetClientPenaltiesAsync(int clientId, bool victim = true)
|
||||
{
|
||||
using (var context = new DatabaseContext())
|
||||
{
|
||||
context.Configuration.LazyLoadingEnabled = false;
|
||||
context.Configuration.ProxyCreationEnabled = false;
|
||||
context.Configuration.AutoDetectChangesEnabled = false;
|
||||
|
||||
if (victim)
|
||||
{
|
||||
var iqPenalties = from penalty in context.Penalties.AsNoTracking()
|
||||
where penalty.OffenderId == clientId
|
||||
join victimClient in context.Clients.AsNoTracking()
|
||||
on penalty.OffenderId equals victimClient.ClientId
|
||||
join victimAlias in context.Aliases
|
||||
on victimClient.CurrentAliasId equals victimAlias.AliasId
|
||||
join punisherClient in context.Clients
|
||||
on penalty.PunisherId equals punisherClient.ClientId
|
||||
join punisherAlias in context.Aliases
|
||||
on punisherClient.CurrentAliasId equals punisherAlias.AliasId
|
||||
//orderby penalty.When descending
|
||||
select new ProfileMeta()
|
||||
{
|
||||
Key = "Event.Penalty",
|
||||
Value = new ProfilePenalty
|
||||
{
|
||||
OffenderName = victimAlias.Name,
|
||||
OffenderId = victimClient.ClientId,
|
||||
PunisherName = punisherAlias.Name,
|
||||
PunisherId = penalty.PunisherId,
|
||||
Offense = penalty.Offense,
|
||||
Type = penalty.Type.ToString()
|
||||
},
|
||||
When = penalty.When
|
||||
};
|
||||
// fixme: is this good and fast?
|
||||
return await iqPenalties.ToListAsync();
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
var iqPenalties = from penalty in context.Penalties.AsNoTracking()
|
||||
where penalty.PunisherId == clientId
|
||||
join victimClient in context.Clients.AsNoTracking()
|
||||
on penalty.OffenderId equals victimClient.ClientId
|
||||
join victimAlias in context.Aliases
|
||||
on victimClient.CurrentAliasId equals victimAlias.AliasId
|
||||
join punisherClient in context.Clients
|
||||
on penalty.PunisherId equals punisherClient.ClientId
|
||||
join punisherAlias in context.Aliases
|
||||
on punisherClient.CurrentAliasId equals punisherAlias.AliasId
|
||||
//orderby penalty.When descending
|
||||
select new ProfileMeta()
|
||||
{
|
||||
Key = "Event.Penalty",
|
||||
Value = new ProfilePenalty
|
||||
{
|
||||
OffenderName = victimAlias.Name,
|
||||
OffenderId = victimClient.ClientId,
|
||||
PunisherName = punisherAlias.Name,
|
||||
PunisherId = penalty.PunisherId,
|
||||
Offense = penalty.Offense,
|
||||
Type = penalty.Type.ToString()
|
||||
},
|
||||
When = penalty.When
|
||||
};
|
||||
// fixme: is this good and fast?
|
||||
return await iqPenalties.ToListAsync();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public async Task RemoveActivePenalties(int aliasLinkId)
|
||||
{
|
||||
using (var context = new DatabaseContext())
|
||||
|
@ -103,6 +103,8 @@
|
||||
<Compile Include="Database\Models\EFClient.cs" />
|
||||
<Compile Include="Database\Models\EFPenalty.cs" />
|
||||
<Compile Include="Database\Models\SharedEntity.cs" />
|
||||
<Compile Include="Dtos\ProfileMeta.cs" />
|
||||
<Compile Include="Dtos\ProfilePenalty.cs" />
|
||||
<Compile Include="Exceptions\DatabaseException.cs" />
|
||||
<Compile Include="Helpers\AsyncStatus.cs" />
|
||||
<Compile Include="Commands\NativeCommands.cs" />
|
||||
@ -139,6 +141,7 @@
|
||||
<Compile Include="Services\AliasService.cs" />
|
||||
<Compile Include="Services\ClientService.cs" />
|
||||
<Compile Include="Services\GenericRepository.cs" />
|
||||
<Compile Include="Services\MetaService.cs" />
|
||||
<Compile Include="Services\PenaltyService.cs" />
|
||||
<Compile Include="Utilities.cs" />
|
||||
<Compile Include="WebService.cs" />
|
||||
|
Loading…
Reference in New Issue
Block a user