continue rework of profile

start moving profile info out of javascript into componentview
rework meta data to include count and offset
This commit is contained in:
RaidMax 2019-03-27 19:40:26 -05:00
parent 1e2e2218e3
commit 7b8126d57e
17 changed files with 277 additions and 250 deletions

View File

@ -388,42 +388,80 @@ namespace IW4MAdmin.Application
#endregion
#region META
async Task<List<ProfileMeta>> getLastMap(int clientId)
async Task<List<ProfileMeta>> getProfileMeta(int clientId, int offset, int count)
{
var meta = await _metaService.GetPersistentMeta("LastMapPlayed", new EFClient() { ClientId = clientId });
var metaList = new List<ProfileMeta>();
return meta == null ? new List<ProfileMeta>() : new List<ProfileMeta>()
// we don't want to return anything because it means we're trying to retrieve paged meta data
if (count > 1)
{
new ProfileMeta()
{
Id = meta.MetaId,
Key = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_LAST_MAP"],
Value = meta.Value,
Show = true
}
return metaList;
}
};
}
var lastMapMeta = await _metaService.GetPersistentMeta("LastMapPlayed", new EFClient() { ClientId = clientId });
async Task<List<ProfileMeta>> getLastServer(int clientId)
{
var meta = await _metaService.GetPersistentMeta("LastServerPlayed", new EFClient() { ClientId = clientId });
return meta == null ? new List<ProfileMeta>() : new List<ProfileMeta>()
metaList.Add(new ProfileMeta()
{
new ProfileMeta()
{
Id = meta.MetaId,
Key = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_LAST_SERVER"],
Value = meta.Value,
Show = true
}
Id = lastMapMeta.MetaId,
Key = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_LAST_MAP"],
Value = lastMapMeta.Value,
Show = true,
Type = ProfileMeta.MetaType.Information
});
};
}
var lastServerMeta = await _metaService.GetPersistentMeta("LastServerPlayed", new EFClient() { ClientId = clientId });
MetaService.AddRuntimeMeta(getLastMap);
MetaService.AddRuntimeMeta(getLastServer);
metaList.Add(new ProfileMeta()
{
Id = lastServerMeta.MetaId,
Key = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_LAST_SERVER"],
Value = lastServerMeta.Value,
Show = true,
Type = ProfileMeta.MetaType.Information
});
var client = await GetClientService().Get(clientId);
metaList.Add(new ProfileMeta()
{
Id = client.ClientId,
Key = $"{Utilities.CurrentLocalization.LocalizationIndex["GLOBAL_TIME_HOURS"]} {Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_PROFILE_PLAYER"]}",
Value = Math.Round(client.TotalConnectionTime / 3600.0, 1).ToString("#,##0"),
Show = true,
Type = ProfileMeta.MetaType.Information
});
metaList.Add(new ProfileMeta()
{
Id = client.ClientId,
Key = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_PROFILE_FSEEN"],
Value = Utilities.GetTimePassed(client.FirstConnection, false),
Show = true,
Type = ProfileMeta.MetaType.Information
});
metaList.Add(new ProfileMeta()
{
Id = client.ClientId,
Key = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_PROFILE_LSEEN"],
Value = Utilities.GetTimePassed(client.LastConnection, false),
Show = true,
Type = ProfileMeta.MetaType.Information
});
metaList.Add(new ProfileMeta()
{
Id = client.ClientId,
Key = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_CONNECTIONS"],
Value = client.Connections,
Show = true,
Type = ProfileMeta.MetaType.Information
});
return metaList;
};
MetaService.AddRuntimeMeta(getProfileMeta);
#endregion
#region INIT

View File

@ -124,8 +124,13 @@ namespace IW4MAdmin.Plugins.Stats
"/Stats/TopPlayersAsync");
// meta data info
async Task<List<ProfileMeta>> getStats(int clientId)
async Task<List<ProfileMeta>> getStats(int clientId, int offset, int count)
{
if (count > 1)
{
return new List<ProfileMeta>();
}
IList<EFClientStatistics> clientStats;
using (var ctx = new DatabaseContext(disableTracking: true))
{
@ -146,38 +151,50 @@ namespace IW4MAdmin.Plugins.Stats
{
Key = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_RANKING"],
Value = "#" + await StatManager.GetClientOverallRanking(clientId),
Type = ProfileMeta.MetaType.Information
},
new ProfileMeta()
{
Key = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_TEXT_KILLS"],
Value = kills
Value = kills,
Type = ProfileMeta.MetaType.Information
},
new ProfileMeta()
{
Key = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_TEXT_DEATHS"],
Value = deaths
Value = deaths,
Type = ProfileMeta.MetaType.Information
},
new ProfileMeta()
{
Key = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_TEXT_KDR"],
Value = kdr
Value = kdr,
Type = ProfileMeta.MetaType.Information
},
new ProfileMeta()
{
Key = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_COMMANDS_PERFORMANCE"],
Value = performance
Value = performance,
Type = ProfileMeta.MetaType.Information
},
new ProfileMeta()
{
Key = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_META_SPM"],
Value = spm
Value = spm,
Type = ProfileMeta.MetaType.Information
}
};
}
async Task<List<ProfileMeta>> getAnticheatInfo(int clientId)
async Task<List<ProfileMeta>> getAnticheatInfo(int clientId, int offset, int count)
{
if (count > 1)
{
return new List<ProfileMeta>();
}
IList<EFClientStatistics> clientStats;
using (var ctx = new DatabaseContext(disableTracking: true))
{
clientStats = await ctx.Set<EFClientStatistics>()
@ -221,24 +238,28 @@ namespace IW4MAdmin.Plugins.Stats
{
Key = "Chest Ratio",
Value = chestRatio,
Type = ProfileMeta.MetaType.Information,
Sensitive = true
},
new ProfileMeta()
{
Key = "Abdomen Ratio",
Value = abdomenRatio,
Type = ProfileMeta.MetaType.Information,
Sensitive = true
},
new ProfileMeta()
{
Key = "Chest To Abdomen Ratio",
Value = chestAbdomenRatio,
Type = ProfileMeta.MetaType.Information,
Sensitive = true
},
new ProfileMeta()
{
Key = "Headshot Ratio",
Value = headRatio,
Type = ProfileMeta.MetaType.Information,
Sensitive = true
},
new ProfileMeta()
@ -246,49 +267,64 @@ namespace IW4MAdmin.Plugins.Stats
Key = "Hit Offset Average",
// todo: make sure this is wrapped somewhere else
Value = $"{Math.Round(((float)hitOffsetAverage), 4).ToString(new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName))}°",
Type = ProfileMeta.MetaType.Information,
Sensitive = true
},
new ProfileMeta()
{
Key = "Max Strain",
Value = Math.Round(maxStrain, 3),
Type = ProfileMeta.MetaType.Information,
Sensitive = true
},
};
}
async Task<List<ProfileMeta>> getMessages(int clientId)
async Task<List<ProfileMeta>> getMessages(int clientId, int offset, int count)
{
if (count <= 1)
{
using (var ctx = new DatabaseContext(true))
{
return new List<ProfileMeta>
{
new ProfileMeta()
{
Key = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_PROFILE_MESSAGES"],
Value = await ctx.Set<EFClientMessage>().CountAsync(),
Type = ProfileMeta.MetaType.Information
}
};
}
}
List<ProfileMeta> messageMeta;
using (var ctx = new DatabaseContext(disableTracking: true))
{
var messages = ctx.Set<EFClientMessage>().Where(m => m.ClientId == clientId);
var messages = ctx.Set<EFClientMessage>().Where(m => m.ClientId == clientId)
.OrderByDescending(_message => _message.TimeSent)
.Skip(offset)
.Take(count);
messageMeta = await messages.Select(m => new ProfileMeta()
{
Key = "EventMessage",
Key = null,
Value = m.Message,
When = m.TimeSent,
Extra = m.ServerId.ToString()
Extra = m.ServerId.ToString(),
Type = ProfileMeta.MetaType.ChatMessage
}).ToListAsync();
}
messageMeta.Add(new ProfileMeta()
{
Key = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_PROFILE_MESSAGES"],
Value = messageMeta.Count
});
return messageMeta;
}
MetaService.AddRuntimeMeta(getStats);
if (Config.Configuration().EnableAntiCheat)
{
MetaService.AddRuntimeMeta(getAnticheatInfo);
}
MetaService.AddRuntimeMeta(getStats);
MetaService.AddRuntimeMeta(getMessages);
async Task<string> totalKills(Server server)

View File

@ -10,17 +10,19 @@ namespace SharedLibraryCore.Dtos
{
public string OffenderName { get; set; }
public int OffenderId { get; set; }
public ulong OffenderNetworkId { get; set; }
public string OffenderIPAddress { get; set; }
public string PunisherName { get; set; }
public int PunisherId { get; set; }
public ulong PunisherNetworkId { get; set; }
public string PunisherIPAddress { get; set; }
public string PunisherLevel { get; set; }
public int PunisherLevelId { get; set; }
public string Offense { get; set; }
public string AutomatedOffense { get; set; }
public string Type { get; set; }
public string PenaltyType { get; set; }
public string TimePunished { get; set; }
public string TimeRemaining { get; set; }
public bool Expired { get; set; }
public string IPAddress { get; set; }
public ulong NetworkId { get; set; }
}
}

View File

@ -18,10 +18,10 @@ namespace SharedLibraryCore.Dtos
public List<string> IPs { get; set; }
public bool HasActivePenalty { get; set; }
public string ActivePenaltyType { get; set; }
public int ConnectionCount { get; set; }
public string LastSeen { get; set; }
public string FirstSeen { get; set; }
public string TimePlayed { get; set; }
//public int ConnectionCount { get; set; }
//public string LastSeen { get; set; }
//public string FirstSeen { get; set; }
//public string TimePlayed { get; set; }
public bool Authenticated { get; set; }
public List<ProfileMeta> Meta { get; set; }
public bool Online { get; set; }

View File

@ -8,11 +8,22 @@ namespace SharedLibraryCore.Dtos
{
public class ProfileMeta : SharedInfo
{
public enum MetaType
{
Other,
Information,
AliasUpdate,
ChatMessage
}
public DateTime When { get; set; }
public string WhenString => Utilities.GetTimePassed(When, false);
public string Key { get; set; }
public dynamic Value { get; set; }
public string Extra { get; set; }
public virtual string Class => Value.GetType().ToString();
public MetaType Type { get; set; }
public int? Column { get; set; }
public int? Order { get; set; }
}
}

View File

@ -11,7 +11,7 @@ namespace SharedLibraryCore.Services
{
public class MetaService
{
private static List<Func<int, Task<List<ProfileMeta>>>> _metaActions = new List<Func<int, Task<List<ProfileMeta>>>>();
private static List<Func<int, int, int, Task<List<ProfileMeta>>>> _metaActions = new List<Func<int, int, int, Task<List<ProfileMeta>>>>();
/// <summary>
/// adds or updates meta key and value to the database
@ -71,7 +71,7 @@ namespace SharedLibraryCore.Services
/// aads a meta task to the runtime meta list
/// </summary>
/// <param name="metaAction"></param>
public static void AddRuntimeMeta(Func<int, Task<List<ProfileMeta>>> metaAction)
public static void AddRuntimeMeta(Func<int, int, int, Task<List<ProfileMeta>>> metaAction)
{
_metaActions.Add(metaAction);
}
@ -80,14 +80,16 @@ namespace SharedLibraryCore.Services
/// retrieves all the runtime meta information for given client idea
/// </summary>
/// <param name="clientId">id of the client</param>
/// <param name="count">number of meta items to retrieve</param>
/// <param name="offset">offset from the first item</param>
/// <returns></returns>
public static async Task<List<ProfileMeta>> GetRuntimeMeta(int clientId)
public static async Task<List<ProfileMeta>> GetRuntimeMeta(int clientId, int offset = 0, int count = int.MaxValue)
{
var meta = new List<ProfileMeta>();
foreach (var action in _metaActions)
{
meta.AddRange(await action(clientId));
meta.AddRange(await action(clientId, offset, count));
}
return meta;

View File

@ -195,7 +195,7 @@ namespace SharedLibraryCore.Services
PunisherName = punisherAlias.Name,
PunisherId = penalty.PunisherId,
Offense = penalty.Offense,
Type = penalty.Type.ToString(),
PenaltyType = penalty.Type.ToString(),
TimeRemaining = penalty.Expires.HasValue ? (now > penalty.Expires ? "" : penalty.Expires.ToString()) : DateTime.MaxValue.ToString(),
AutomatedOffense = penalty.AutomatedOffense,
Expired = penalty.Expires.HasValue && penalty.Expires <= DateTime.UtcNow
@ -208,9 +208,9 @@ namespace SharedLibraryCore.Services
list.ForEach(p =>
{
// todo: why does this have to be done?
if (((PenaltyInfo)p.Value).Type.Length < 2)
if (((PenaltyInfo)p.Value).PenaltyType.Length < 2)
{
((PenaltyInfo)p.Value).Type = ((Penalty.PenaltyType)Convert.ToInt32(((PenaltyInfo)p.Value).Type)).ToString();
((PenaltyInfo)p.Value).PenaltyType = ((Penalty.PenaltyType)Convert.ToInt32(((PenaltyInfo)p.Value).PenaltyType)).ToString();
}
var pi = ((PenaltyInfo)p.Value);
@ -251,7 +251,7 @@ namespace SharedLibraryCore.Services
PunisherName = punisherAlias.Name,
PunisherId = penalty.PunisherId,
Offense = penalty.Offense,
Type = penalty.Type.ToString(),
PenaltyType = penalty.Type.ToString(),
AutomatedOffense = penalty.AutomatedOffense
},
When = penalty.When,
@ -263,9 +263,9 @@ namespace SharedLibraryCore.Services
list.ForEach(p =>
{
// todo: why does this have to be done?
if (((PenaltyInfo)p.Value).Type.Length < 2)
if (((PenaltyInfo)p.Value).PenaltyType.Length < 2)
{
((PenaltyInfo)p.Value).Type = ((Penalty.PenaltyType)Convert.ToInt32(((PenaltyInfo)p.Value).Type)).ToString();
((PenaltyInfo)p.Value).PenaltyType = ((Penalty.PenaltyType)Convert.ToInt32(((PenaltyInfo)p.Value).PenaltyType)).ToString();
}
});

View File

@ -34,10 +34,6 @@ namespace WebfrontCore.Controllers
ClientId = client.ClientId,
IPAddress = client.IPAddressString,
NetworkId = client.NetworkId,
ConnectionCount = client.Connections,
FirstSeen = Utilities.GetTimePassed(client.FirstConnection, false),
LastSeen = Utilities.GetTimePassed(client.LastConnection, false),
TimePlayed = Math.Round(client.TotalConnectionTime / 3600.0, 1).ToString("#,##0"),
Meta = new List<ProfileMeta>(),
Aliases = client.AliasLink.Children
.Where(a => a.Name != client.Name)
@ -59,7 +55,7 @@ namespace WebfrontCore.Controllers
LinkedAccounts = client.LinkedAccounts
};
var meta = await MetaService.GetRuntimeMeta(client.ClientId);
var meta = await MetaService.GetRuntimeMeta(client.ClientId, 0, 1);
var penaltyMeta = await Manager.GetPenaltyService()
.ReadGetClientPenaltiesAsync(client.ClientId);
var administeredPenaltiesMeta = await Manager.GetPenaltyService()
@ -76,19 +72,19 @@ namespace WebfrontCore.Controllers
});
}
if (Authorized)
{
clientDto.Meta.AddRange(client.AliasLink.Children
.GroupBy(a => a.Name)
.Select(a => a.First())
.Select(a => new ProfileMeta()
{
Key = "AliasEvent",
Value = $"{Localization["WEBFRONT_CLIENT_META_JOINED"]} {a.Name}",
Sensitive = true,
When = a.DateAdded
}));
}
//if (Authorized)
//{
// clientDto.Meta.AddRange(client.AliasLink.Children
// .GroupBy(a => a.Name)
// .Select(a => a.First())
// .Select(a => new ProfileMeta()
// {
// Value = $"{Localization["WEBFRONT_CLIENT_META_JOINED"]} {a.Name}",
// Sensitive = true,
// When = a.DateAdded,
// Type = ProfileMeta.MetaType.AliasUpdate
// }));
//}
if (Authorized)
{
@ -118,6 +114,7 @@ namespace WebfrontCore.Controllers
Value = m.Value,
Show = false,
}));
clientDto.Meta = clientDto.Meta
.OrderByDescending(m => m.When)
.ToList();
@ -173,13 +170,25 @@ namespace WebfrontCore.Controllers
Name = c.Name,
Level = c.Level.ToLocalizedLevelName(),
LevelInt = (int)c.Level,
ClientId = c.ClientId,
LastSeen = Utilities.GetTimePassed(c.LastConnection, false)
// todo: add back last seen for search
ClientId = c.ClientId
})
.ToList();
ViewBag.Title = $"{clientsDto.Count} {Localization["WEBFRONT_CLIENT_SEARCH_MATCHING"]} \"{clientName}\"";
return View("Find/Index", clientsDto);
}
public async Task<IActionResult> Meta(int id, int count, int offset)
{
var meta = await MetaService.GetRuntimeMeta(id, offset, count);
if (meta.Count == 0)
{
return Ok();
}
return View("Components/ProfileMetaList/_List", meta);
}
}
}

View File

@ -46,20 +46,25 @@ namespace WebfrontCore.Controllers
{
// todo: this seems like it's pulling unnecessary info from LINQ to entities.
var iqPenalties = ctx.Penalties
.AsNoTracking()
.Where(p => p.Type == SharedLibraryCore.Objects.Penalty.PenaltyType.Ban && p.Active)
.OrderByDescending(_penalty => _penalty.When)
.Select(p => new PenaltyInfo()
{
Id = p.PenaltyId,
OffenderId = p.OffenderId,
OffenderName = p.Offender.CurrentAlias.Name,
OffenderNetworkId = (ulong)p.Offender.NetworkId,
OffenderIPAddress = Authorized ? p.Offender.CurrentAlias.IPAddress.ConvertIPtoString() : null,
Offense = p.Offense,
PunisherId = p.PunisherId,
Type = p.Type.ToString(),
PunisherNetworkId = (ulong)p.Punisher.NetworkId,
PunisherName = p.Punisher.CurrentAlias.Name,
PunisherIPAddress = Authorized ? p.Punisher.CurrentAlias.IPAddress.ConvertIPtoString() : null,
PenaltyType = p.Type.ToString(),
TimePunished = p.When.ToString(),
TimeRemaining = "",
AutomatedOffense = Authorized ? p.AutomatedOffense : "",
NetworkId = (ulong)p.Offender.NetworkId,
IPAddress = Authorized ? p.Offender.IPAddressString : ""
TimeRemaining = null,
AutomatedOffense = Authorized ? p.AutomatedOffense : null,
});
#if DEBUG == true
var querySql = iqPenalties.ToSql();

View File

@ -29,6 +29,19 @@ namespace WebfrontCore
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// allow CORS
services.AddCors(_options =>
{
_options.AddPolicy("AllowAll",
_builder =>
{
_builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials();
});
});
// Add framework services.
var mvcBuilder = services.AddMvc()
.ConfigureApplicationPartManager(_ =>
@ -98,6 +111,7 @@ namespace WebfrontCore
app.UseStaticFiles();
app.UseAuthentication();
app.UseCors("AllowAll");
app.UseMvc(routes =>
{

View File

@ -33,7 +33,7 @@ namespace WebfrontCore.ViewComponents
$"{showEvadeString(p)}{p.AutomatedOffense}" :
$"{showEvadeString(p)}{p.Offense}",
#endif
Type = p.Type.ToString(),
PenaltyType = p.Type.ToString(),
TimePunished = Utilities.GetTimePassed(p.When, false),
// show time passed if ban
TimeRemaining = DateTime.UtcNow > p.Expires ? "" : $"{((p.Expires ?? DateTime.MaxValue).Year == DateTime.MaxValue.Year ? Utilities.GetTimePassed(p.When, true) : Utilities.TimeSpanText((p.Expires ?? DateTime.MaxValue) - DateTime.UtcNow))}",

View File

@ -0,0 +1,15 @@
using Microsoft.AspNetCore.Mvc;
using SharedLibraryCore.Services;
using System.Threading.Tasks;
namespace WebfrontCore.ViewComponents
{
public class ProfileMetaListViewComponent : ViewComponent
{
public async Task<IViewComponentResult> InvokeAsync(int clientId, int count, int offset)
{
var meta = await MetaService.GetRuntimeMeta(clientId, offset, count);
return View("_List", meta);
}
}
}

View File

@ -17,7 +17,7 @@
<div class="row pt-2 pb-2 bg-dark">
<div class="col-5">@Html.ActionLink(client.Name, "ProfileAsync", "Client", new { id = client.ClientId })</div>
<div class="col-4 level-color-@client.LevelInt">@client.Level</div>
<div class="col-3 text-right">@client.LastSeen @loc["WEBFRONT_PENALTY_TEMPLATE_AGO"]</div>
@*<div class="col-3 text-right">@client.LastSeen @loc["WEBFRONT_PENALTY_TEMPLATE_AGO"]</div>*@
</div>
}
}

View File

@ -5,6 +5,9 @@
var loc = SharedLibraryCore.Utilities.CurrentLocalization.LocalizationIndex;
string gravatarUrl = Model.Meta.FirstOrDefault(m => m.Key == "GravatarEmail")?.Value;
bool isTempBanned = Model.ActivePenaltyType == "TempBan";
var informationMeta = Model.Meta
.Where(_meta => _meta.Type == SharedLibraryCore.Dtos.ProfileMeta.MetaType.Information)
.ToList();
}
<div id="profile_wrapper" class="pb-3 row d-flex flex-column flex-lg-row">
@ -76,27 +79,41 @@
</div>
<div id="profile_info" class="row d-block d-lg-flex flex-row border-bottom border-top pt-2 pb-2">
<div id="profile_meta_0" class="text-center text-lg-left mr-0 mr-lg-4">
<div id="profile_time_played" class="text-muted">
@loc["WEBFRONT_PROFILE_PLAYER"] <span class="text-primary">@Model.TimePlayed</span> @loc["GLOBAL_TIME_HOURS"]
</div>
<div id="profile_first_seen" class="text-muted">
@loc["WEBFRONT_PROFILE_FSEEN"] <span class="text-primary">@Model.FirstSeen</span> @loc["WEBFRONT_PENALTY_TEMPLATE_AGO"]
</div>
<div id="profile_last_seen" class="text-muted">
@loc["WEBFRONT_PROFILE_LSEEN"] <span class="text-primary">@Model.LastSeen</span> @loc["WEBFRONT_PENALTY_TEMPLATE_AGO"]
</div>
@for (int i = 0; i < informationMeta.Count; i += 3)
{
<div class="profile-meta-entry">
<span class="profile-meta-value text-primary">@informationMeta[i].Value</span>
<span class="profile-meta-title text-muted"> @informationMeta[i].Key</span>
</div>
}
</div>
<div class="text-center text-lg-left mr-0 mr-lg-4" id="profile_meta_1">
@for (int i = 1; i < informationMeta.Count; i += 3)
{
<div class="profile-meta-entry">
<span class="profile-meta-value text-primary">@informationMeta[i].Value</span>
<span class="profile-meta-title text-muted"> @informationMeta[i].Key</span>
</div>
}
</div>
<div class="text-center text-lg-left" id="profile_meta_2">
@for (int i = 2; i < informationMeta.Count; i += 3)
{
<div class="profile-meta-entry">
<span class="profile-meta-value text-primary">@informationMeta[i].Value</span>
<span class="profile-meta-title text-muted"> @informationMeta[i].Key</span>
</div>
}
</div>
</div>
<div class="row d-md-flex pt-2">
<div id="profile_events" class="text-muted text-left ml-sm-0">
@await Component.InvokeAsync("ProfileMetaList", new { clientId = Model.ClientId, count = 30, offset = 0 })
</div>
</div>
@ -105,12 +122,9 @@
}
@section scripts {
<script>
const clientInfo = {};
clientInfo.clientId = @Model.ClientId;
clientInfo.Meta = @Html.Raw(Json.Serialize(@Model.Meta.Where(m => m.Show)));
</script>
<environment include="Development">
<script type="text/javascript" src="~/js/loader.js"></script>
<script type="text/javascript" src="~/js/profile.js"></script>
</environment>
<script>initLoader('/Client/Meta/@Model.ClientId', '#profile_events', 30);</script>
}

View File

@ -13,9 +13,9 @@
</tr>
<tr class="d-table-row d-md-none bg-dark">
<th scope="row" class="bg-primary">@loc["WEBFRONT_PENALTY_TEMPLATE_TYPE"]</th>
<td class="penalties-color-@Model.Type.ToLower()">
@Model.Type
<th scope="row" class="bg-primary">@loc["WEBFRONT_PENALTY_TEMPLATE_PenaltyType"]</th>
<td class="penalties-color-@Model.PenaltyType.ToLower()">
@Model.PenaltyType
</td>
</tr>
@ -53,8 +53,8 @@
<td>
@Html.ActionLink(Model.OffenderName, "ProfileAsync", "Client", new { id = Model.OffenderId }, new { @class = "link-inverse" })
</td>
<td class="penalties-color-@Model.Type.ToLower()">
@Model.Type
<td class="penalties-color-@Model.PenaltyType.ToLower()">
@Model.PenaltyType
</td>
<td class="text-light w-50">
@Model.Offense

View File

@ -0,0 +1,20 @@
@model List<SharedLibraryCore.Dtos.ProfileMeta>
@{Layout = null;}
<div class="p2 text-white profile-event-timestep">
<span class="text-primary">&mdash;</span>
<span>@SharedLibraryCore.Utilities.GetTimePassed(Model.FirstOrDefault()?.When ?? DateTime.Now, true)</span>
</div>
@foreach (var meta in Model)
{
@switch (meta.Type)
{
case SharedLibraryCore.Dtos.ProfileMeta.MetaType.ChatMessage:
<div>
<span style="color:white;">></span>
<span class="client-message text-muted" data-serverid="@meta.Extra" data-when="@meta.When"> @meta.Value</span>
</div>
break;
}
}

View File

@ -1,13 +1,4 @@
// keeps track of how many events have been displayed
let count = 1;
let metaIndex = 0;
$(document).ready(function () {
if (typeof clientInfo === 'undefined') {
return false;
}
$(document).ready(function () {
/*
Expand alias tab if they have any
*/
@ -19,51 +10,6 @@ $(document).ready(function () {
}
});
/*
load the initial 40 events
*/
$.each(clientInfo.Meta, function (index, meta) {
if (meta.key.includes("Event")) {
loadMeta(meta);
if (count % 40 === 0) {
count++;
return false;
}
count++;
}
});
/*
load additional events on scroll
*/
$(window).scroll(function () {
if ($(window).scrollTop() === $(document).height() - $(window).height() || $(document).height() === $(window).height()) {
while (count % 40 !== 0 && count < clientInfo.Meta.length) {
loadMeta(clientInfo.Meta[count - 1]);
count++;
}
count++;
}
});
/*
load meta thats not an event
*/
$.each(clientInfo.Meta, function (index, meta) {
if (!meta.key.includes("Event")) {
let metaString = `<div class="profile-meta-entry"><span class="profile-meta-value text-primary">${meta.value}</span><span class="profile-meta-title text-muted"> ${meta.key}</span></div>`;
// todo: fix the view so we don't have the 3 hardcoded meta
if (metaIndex % 3 == 0 && metaIndex < 7) {
metaIndex++;
}
let selector = '#profile_meta_' + (metaIndex % 3);
$(selector).append(metaString);
metaIndex++;
}
});
/*
* load context of chat
*/
@ -150,88 +96,3 @@ $(document).ready(function () {
});
});
});
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";
case "Unban":
return "Unbanned";
}
}
function shouldIncludePlural(num) {
return num > 1 ? 's' : '';
}
let mostRecentDate = 0;
let currentStepAmount = 0;
let lastStep = '';
// todo: fix
function timeStep(stepDifference) {
let hours = stepDifference / (1000 * 60 * 60);
let days = stepDifference / (1000 * 60 * 60 * 24);
let weeks = stepDifference / (1000 * 60 * 60 * 24 * 7);
if (Math.round(weeks) > Math.round(currentStepAmount / 24 * 7)) {
currentStepAmount = Math.round(weeks);
return `${currentStepAmount} week${shouldIncludePlural(currentStepAmount)} ago`;
}
if (Math.round(days) > Math.round(currentStepAmount / 24)) {
currentStepAmount = Math.round(days);
return `${currentStepAmount} day${shouldIncludePlural(currentStepAmount)} ago`;
}
if (Math.round(hours) > currentStepAmount) {
currentStepAmount = Math.round(hours);
return `${currentStepAmount} hour${shouldIncludePlural(currentStepAmount)} ago`;
}
}
function loadMeta(meta) {
let eventString = '';
const metaDate = moment.utc(meta.when).valueOf();
if (mostRecentDate === 0) {
mostRecentDate = metaDate;
}
const step = timeStep(moment.utc().valueOf() - metaDate);
if (step !== lastStep && step !== undefined && metaDate > 0) {
$('#profile_events').append('<span class="p2 text-white profile-event-timestep"><span class="text-primary">&mdash;</span> ' + step + '</span>');
lastStep = step;
}
// it's a penalty
if (meta.class.includes("Penalty")) {
if (meta.value.punisherId !== clientInfo.clientId) {
const timeRemaining = meta.value.type === 'TempBan' && meta.value.timeRemaining.length > 0 ?
`(${meta.value.timeRemaining})` :
'';
eventString = `<div><span class="penalties-color-${meta.value.type.toLowerCase()}">${penaltyToName(meta.value.type)}</span> by <span class="text-highlight"> <a class="link-inverse" href="${meta.value.punisherId}">${meta.value.punisherName}</a></span > for <span style="color: white; " class="automated-penalty-info-detailed" data-clientid="${meta.value.offenderId}">${meta.value.offense}</span><span class="text-muted"> ${timeRemaining}</span></div>`;
}
else {
eventString = `<div><span class="penalties-color-${meta.value.type.toLowerCase()}">${penaltyToName(meta.value.type)} </span> <span class="text-highlight"><a class="link-inverse" href="${meta.value.offenderId}"> ${meta.value.offenderName}</a></span > for <span style="color: white;" class="automated-penalty-info-detailed" data-clientid="${meta.value.offenderId}">${meta.value.offense}</span></div>`;
}
}
else if (meta.key.includes("Alias")) {
eventString = `<div><span class="text-success">${meta.value}</span></div>`;
}
// it's a message
else if (meta.key.includes("Event")) {
eventString = `<div><span style="color:white;">></span><span class="client-message text-muted" data-serverid="${meta.extra}" data-when="${meta.when}"> ${meta.value}</span></div>`;
}
$('#profile_events').append(eventString);
}