fix bug with privileged users not always showing the most recent profile

temporary bans are now applied to all linked accounts instead of a per-guid basis
rework set level flow
add guid and ip address (if logged in) to public async endpoint
This commit is contained in:
RaidMax 2019-03-24 21:34:20 -05:00
parent 1056c7c335
commit cae6d8389e
15 changed files with 320 additions and 214 deletions

View File

@ -82,11 +82,7 @@ namespace IW4MAdmin
};
Manager.GetEventHandler().AddEvent(e);
if (client.IPAddress != null)
{
await client.OnJoin(client.IPAddress);
}
await client.OnJoin(client.IPAddress);
}
catch (Exception ex)
@ -186,6 +182,9 @@ namespace IW4MAdmin
{
if (E.Type == GameEvent.EventType.ChangePermission)
{
var newPermission = (EFClient.Permission)E.Extra;
E.Target.Level = newPermission;
if (!E.Target.IsPrivileged())
{
// remove banned or demoted privileged user
@ -196,6 +195,8 @@ namespace IW4MAdmin
{
Manager.GetPrivilegedClients()[E.Target.ClientId] = E.Target;
}
await Manager.GetClientService().Update(E.Target);
}
else if (E.Type == GameEvent.EventType.PreConnect)
@ -611,6 +612,17 @@ namespace IW4MAdmin
if (ConnectionErrors > 0)
{
Logger.WriteVerbose($"{loc["MANAGER_CONNECTION_REST"]} {IP}:{Port}");
var _event = new GameEvent()
{
Type = GameEvent.EventType.ConnectionRestored,
Owner = this,
Origin = Utilities.IW4MAdminClient(this),
Target = Utilities.IW4MAdminClient(this)
};
Manager.GetEventHandler().AddEvent(_event);
Throttled = false;
}
@ -625,6 +637,19 @@ namespace IW4MAdmin
{
Logger.WriteError($"{e.Message} {IP}:{Port}, {loc["SERVER_ERROR_POLLING"]}");
Logger.WriteDebug($"Internal Exception: {e.Data["internal_exception"]}");
var _event = new GameEvent()
{
Type = GameEvent.EventType.ConnectionLost,
Owner = this,
Origin = Utilities.IW4MAdminClient(this),
Target = Utilities.IW4MAdminClient(this),
Extra = e,
Data = ConnectionErrors.ToString()
};
Manager.GetEventHandler().AddEvent(_event);
Throttled = true;
}
return true;

View File

@ -16,8 +16,8 @@ namespace IW4MAdmin.Plugins.Stats.Web.Controllers
[HttpGet]
public IActionResult TopPlayersAsync()
{
ViewBag.Title = Utilities.CurrentLocalization.LocalizationIndex.Set["WEBFRONT_STATS_INDEX_TITLE"];
ViewBag.Description = Utilities.CurrentLocalization.LocalizationIndex.Set["WEBFRONT_STATS_INDEX_DESC"];
ViewBag.Title = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_STATS_INDEX_TITLE"];
ViewBag.Description = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_STATS_INDEX_DESC"];
ViewBag.Servers = Manager.GetServers().Select(_server => new ServerInfo() { Name = _server.Hostname, ID = _server.EndPoint });
return View("Index");

View File

@ -28,7 +28,7 @@
@if (Model.Count == 0)
{
<div class="p-2 text-center">@SharedLibraryCore.Utilities.CurrentLocalization.LocalizationIndex.Set["PLUGINS_STATS_TEXT_NOQUALIFY"]</div>
<div class="p-2 text-center">@SharedLibraryCore.Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_TEXT_NOQUALIFY"]</div>
}
@foreach (var stat in Model)
{

View File

@ -1,7 +1,6 @@
using Microsoft.EntityFrameworkCore;
using SharedLibraryCore.Database;
using SharedLibraryCore.Database.Models;
using SharedLibraryCore.Events;
using SharedLibraryCore.Objects;
using SharedLibraryCore.Services;
using System;
@ -18,7 +17,7 @@ namespace SharedLibraryCore.Commands
public class CQuit : Command
{
public CQuit() :
base("quit", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_QUIT_DESC"], "q", EFClient.Permission.Owner, false)
base("quit", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_QUIT_DESC"], "q", EFClient.Permission.Owner, false)
{ }
public override Task ExecuteAsync(GameEvent E)
@ -30,32 +29,15 @@ namespace SharedLibraryCore.Commands
public class COwner : Command
{
public COwner() :
base("owner", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_OWNER_DESC"], "iamgod", EFClient.Permission.User, false)
base("owner", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_OWNER_DESC"], "iamgod", EFClient.Permission.User, false)
{ }
public override async Task ExecuteAsync(GameEvent E)
{
if ((await (E.Owner.Manager.GetClientService() as ClientService).GetOwners()).Count == 0)
if (await (E.Owner.Manager.GetClientService() as ClientService).GetOwnerCount() == 0 &&
!E.Target.SetLevel(EFClient.Permission.Owner, Utilities.IW4MAdminClient(E.Owner)).Failed)
{
var oldPermission = E.Origin.Level;
E.Origin.Level = EFClient.Permission.Owner;
E.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_OWNER_SUCCESS"]);
await E.Owner.Manager.GetClientService().Update(E.Origin);
var e = new GameEvent()
{
Type = GameEvent.EventType.ChangePermission,
Origin = E.Origin,
Target = E.Origin,
Owner = E.Owner,
Extra = new Change()
{
PreviousValue = oldPermission.ToString(),
NewValue = E.Origin.Level.ToString()
}
};
E.Owner.Manager.GetEventHandler().AddEvent(e);
}
else
{
@ -67,7 +49,7 @@ namespace SharedLibraryCore.Commands
public class CWarn : Command
{
public CWarn() :
base("warn", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_WARN_DESC"], "w", EFClient.Permission.Trusted, true, new CommandArgument[]
base("warn", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_WARN_DESC"], "w", EFClient.Permission.Trusted, true, new CommandArgument[]
{
new CommandArgument()
{
@ -96,7 +78,7 @@ namespace SharedLibraryCore.Commands
public class CWarnClear : Command
{
public CWarnClear() :
base("warnclear", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_WARNCLEAR_DESC"], "wc", EFClient.Permission.Trusted, true, new CommandArgument[]
base("warnclear", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_WARNCLEAR_DESC"], "wc", EFClient.Permission.Trusted, true, new CommandArgument[]
{
new CommandArgument()
{
@ -120,7 +102,7 @@ namespace SharedLibraryCore.Commands
public class CKick : Command
{
public CKick() :
base("kick", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_KICK_DESC"], "k", EFClient.Permission.Moderator, true, new CommandArgument[]
base("kick", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_KICK_DESC"], "k", EFClient.Permission.Moderator, true, new CommandArgument[]
{
new CommandArgument()
{
@ -146,7 +128,7 @@ namespace SharedLibraryCore.Commands
public class CSay : Command
{
public CSay() :
base("say", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SAY_DESC"], "s", EFClient.Permission.Moderator, false, new CommandArgument[]
base("say", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SAY_DESC"], "s", EFClient.Permission.Moderator, false, new CommandArgument[]
{
new CommandArgument()
{
@ -166,7 +148,7 @@ namespace SharedLibraryCore.Commands
public class CTempBan : Command
{
public CTempBan() :
base("tempban", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_TEMPBAN_DESC"], "tb", EFClient.Permission.Administrator, true, new CommandArgument[]
base("tempban", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_TEMPBAN_DESC"], "tb", EFClient.Permission.Administrator, true, new CommandArgument[]
{
new CommandArgument()
{
@ -214,7 +196,7 @@ namespace SharedLibraryCore.Commands
public class CBan : Command
{
public CBan() :
base("ban", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_BAN_DESC"], "b", EFClient.Permission.SeniorAdmin, true, new CommandArgument[]
base("ban", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_BAN_DESC"], "b", EFClient.Permission.SeniorAdmin, true, new CommandArgument[]
{
new CommandArgument()
{
@ -240,7 +222,7 @@ namespace SharedLibraryCore.Commands
public class CUnban : Command
{
public CUnban() :
base("unban", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_UNBAN_DESC"], "ub", EFClient.Permission.SeniorAdmin, true, new CommandArgument[]
base("unban", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_UNBAN_DESC"], "ub", EFClient.Permission.SeniorAdmin, true, new CommandArgument[]
{
new CommandArgument()
{
@ -273,7 +255,7 @@ namespace SharedLibraryCore.Commands
public class CWhoAmI : Command
{
public CWhoAmI() :
base("whoami", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_WHO_DESC"], "who", EFClient.Permission.User, false)
base("whoami", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_WHO_DESC"], "who", EFClient.Permission.User, false)
{ }
public override Task ExecuteAsync(GameEvent E)
@ -288,7 +270,7 @@ namespace SharedLibraryCore.Commands
public class CList : Command
{
public CList() :
base("list", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_LIST_DESC"], "l", EFClient.Permission.Moderator, false)
base("list", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_LIST_DESC"], "l", EFClient.Permission.Moderator, false)
{ }
public override Task ExecuteAsync(GameEvent E)
@ -307,11 +289,11 @@ namespace SharedLibraryCore.Commands
// todo: make this better :)
if (P.Masked)
{
playerList.AppendFormat("[^3{0}^7]{3}[^3{1}^7] {2}", Utilities.ConvertLevelToColor( EFClient.Permission.User, P.ClientPermission.Name), P.ClientNumber, P.Name, Utilities.GetSpaces( EFClient.Permission.SeniorAdmin.ToString().Length - EFClient.Permission.User.ToString().Length));
playerList.AppendFormat("[^3{0}^7]{3}[^3{1}^7] {2}", Utilities.ConvertLevelToColor(EFClient.Permission.User, P.ClientPermission.Name), P.ClientNumber, P.Name, Utilities.GetSpaces(EFClient.Permission.SeniorAdmin.ToString().Length - EFClient.Permission.User.ToString().Length));
}
else
{
playerList.AppendFormat("[^3{0}^7]{3}[^3{1}^7] {2}", Utilities.ConvertLevelToColor(P.Level, P.ClientPermission.Name), P.ClientNumber, P.Name, Utilities.GetSpaces( EFClient.Permission.SeniorAdmin.ToString().Length - P.Level.ToString().Length));
playerList.AppendFormat("[^3{0}^7]{3}[^3{1}^7] {2}", Utilities.ConvertLevelToColor(P.Level, P.ClientPermission.Name), P.ClientNumber, P.Name, Utilities.GetSpaces(EFClient.Permission.SeniorAdmin.ToString().Length - P.Level.ToString().Length));
}
if (count == 2 || E.Owner.GetClientsAsList().Count == 1)
@ -339,7 +321,7 @@ namespace SharedLibraryCore.Commands
public class CHelp : Command
{
public CHelp() :
base("help", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_HELP_DESC"], "h", EFClient.Permission.User, false, new CommandArgument[]
base("help", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_HELP_DESC"], "h", EFClient.Permission.User, false, new CommandArgument[]
{
new CommandArgument()
{
@ -404,7 +386,7 @@ namespace SharedLibraryCore.Commands
public class CFastRestart : Command
{
public CFastRestart() :
base("fastrestart", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_FASTRESTART_DESC"], "fr", EFClient.Permission.Moderator, false)
base("fastrestart", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_FASTRESTART_DESC"], "fr", EFClient.Permission.Moderator, false)
{ }
public override async Task ExecuteAsync(GameEvent E)
@ -420,7 +402,7 @@ namespace SharedLibraryCore.Commands
public class CMapRotate : Command
{
public CMapRotate() :
base("maprotate", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_MAPROTATE_DESC"], "mr", EFClient.Permission.Administrator, false)
base("maprotate", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_MAPROTATE_DESC"], "mr", EFClient.Permission.Administrator, false)
{ }
public override async Task ExecuteAsync(GameEvent E)
@ -437,7 +419,7 @@ namespace SharedLibraryCore.Commands
public class CSetLevel : Command
{
public CSetLevel() :
base("setlevel", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SETLEVEL_DESC"], "sl", EFClient.Permission.Moderator, true, new CommandArgument[]
base("setlevel", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SETLEVEL_DESC"], "sl", EFClient.Permission.Moderator, true, new CommandArgument[]
{
new CommandArgument()
{
@ -452,50 +434,54 @@ namespace SharedLibraryCore.Commands
})
{ }
public override async Task ExecuteAsync(GameEvent E)
public override Task ExecuteAsync(GameEvent E)
{
EFClient.Permission oldPerm = E.Target.Level;
EFClient.Permission newPerm = Utilities.MatchPermission(E.Data);
if (E.Target == E.Origin)
{
E.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SETLEVEL_SELF"]);
return;
return Task.CompletedTask;
}
EFClient.Permission oldPerm = E.Target.Level;
EFClient.Permission newPerm = Utilities.MatchPermission(E.Data);
if (newPerm == EFClient.Permission.Owner &&
else if (newPerm == EFClient.Permission.Owner &&
!E.Owner.Manager.GetApplicationSettings().Configuration().EnableMultipleOwners)
{
// only one owner is allowed
E.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SETLEVEL_OWNER"]);
return;
return Task.CompletedTask;
}
if (E.Origin.Level < EFClient.Permission.Owner &&
else if (E.Origin.Level < EFClient.Permission.Owner &&
!E.Owner.Manager.GetApplicationSettings().Configuration().EnableSteppedHierarchy)
{
// only the owner is allowed to set levels
E.Origin.Tell($"{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SETLEVEL_STEPPEDDISABLED"]} ^5{E.Target.Name}");
return;
return Task.CompletedTask;
}
if (newPerm >= E.Origin.Level)
else if (E.Origin.Level <= newPerm &&
E.Origin.Level < EFClient.Permission.Owner)
{
if (E.Origin.Level < EFClient.Permission.Owner)
{
E.Origin.Tell(string.Format(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SETLEVEL_LEVELTOOHIGH"], E.Target.Name, (E.Origin.Level - 1).ToString()));
return;
}
// can't promote a client to higher than your current perms
E.Origin.Tell(string.Format(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SETLEVEL_LEVELTOOHIGH"], E.Target.Name, (E.Origin.Level - 1).ToString()));
return Task.CompletedTask;
}
else if (newPerm > EFClient.Permission.Banned)
else if (newPerm > EFClient.Permission.Banned)
{
var ActiveClient = E.Owner.Manager.GetActiveClients()
.FirstOrDefault(p => p.NetworkId == E.Target.NetworkId);
if (ActiveClient != null)
{
ActiveClient.Level = newPerm;
await E.Owner.Manager.GetClientService().Update(ActiveClient);
ActiveClient.SetLevel(newPerm, E.Origin);
// inform the client that they were promoted
// we don't really want to tell them if they're demoted haha
if (newPerm > oldPerm)
{
ActiveClient.Tell($"{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SETLEVEL_SUCCESS_TARGET"]} {newPerm}");
@ -504,26 +490,11 @@ namespace SharedLibraryCore.Commands
else
{
E.Target.Level = newPerm;
await E.Owner.Manager.GetClientService().Update(E.Target);
E.Target.SetLevel(newPerm, E.Origin);
}
var e = new GameEvent()
{
Origin = E.Origin,
Target = E.Target,
Owner = E.Owner,
Type = GameEvent.EventType.ChangePermission,
Extra = new Change()
{
PreviousValue = oldPerm.ToString(),
NewValue = newPerm.ToString()
}
};
E.Owner.Manager.GetEventHandler().AddEvent(e);
var _ = newPerm < oldPerm ?
// inform the origin that the client has been updated
_ = newPerm < oldPerm ?
E.Origin.Tell($"{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SETLEVEL_DEMOTE_SUCCESS"]} {E.Target.Name}") :
E.Origin.Tell($"{E.Target.Name} {Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SETLEVEL_SUCCESS"]}");
}
@ -532,13 +503,15 @@ namespace SharedLibraryCore.Commands
{
E.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SETLEVEL_FAIL"]);
}
return Task.CompletedTask;
}
}
public class CUsage : Command
{
public CUsage() :
base("usage", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_USAGE_DESC"], "us", EFClient.Permission.Moderator, false)
base("usage", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_USAGE_DESC"], "us", EFClient.Permission.Moderator, false)
{ }
public override Task ExecuteAsync(GameEvent E)
@ -551,7 +524,7 @@ namespace SharedLibraryCore.Commands
public class CUptime : Command
{
public CUptime() :
base("uptime", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_UPTIME_DESC"], "up", EFClient.Permission.Moderator, false)
base("uptime", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_UPTIME_DESC"], "up", EFClient.Permission.Moderator, false)
{ }
public override Task ExecuteAsync(GameEvent E)
@ -566,13 +539,13 @@ namespace SharedLibraryCore.Commands
public class CListAdmins : Command
{
public CListAdmins() :
base("admins", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_ADMINS_DESC"], "a", EFClient.Permission.User, false)
base("admins", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_ADMINS_DESC"], "a", EFClient.Permission.User, false)
{ }
public static string OnlineAdmins(Server S)
{
var onlineAdmins = S.GetClientsAsList()
.Where(p => p.Level > EFClient.Permission.Flagged)
.Where(p => p.Level > EFClient.Permission.Flagged)
.Where(p => !p.Masked)
.Select(p => $"[^3{Utilities.ConvertLevelToColor(p.Level, p.ClientPermission.Name)}^7] {p.Name}");
@ -595,7 +568,7 @@ namespace SharedLibraryCore.Commands
public class CLoadMap : Command
{
public CLoadMap() :
base("map", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_MAP_DESC"], "m", EFClient.Permission.Administrator, false, new CommandArgument[]
base("map", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_MAP_DESC"], "m", EFClient.Permission.Administrator, false, new CommandArgument[]
{
new CommandArgument()
{
@ -628,7 +601,7 @@ namespace SharedLibraryCore.Commands
public class CFindPlayer : Command
{
public CFindPlayer() :
base("find", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_FIND_DESC"], "f", EFClient.Permission.Administrator, false, new CommandArgument[]
base("find", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_FIND_DESC"], "f", EFClient.Permission.Administrator, false, new CommandArgument[]
{
new CommandArgument()
{
@ -672,7 +645,7 @@ namespace SharedLibraryCore.Commands
public class CListRules : Command
{
public CListRules() :
base("rules", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_RULES_DESC"], "r", EFClient.Permission.User, false)
base("rules", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_RULES_DESC"], "r", EFClient.Permission.User, false)
{ }
public override Task ExecuteAsync(GameEvent E)
@ -707,7 +680,7 @@ namespace SharedLibraryCore.Commands
public class CPrivateMessage : Command
{
public CPrivateMessage() :
base("privatemessage", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_PM_DESC"], "pm", EFClient.Permission.User, true, new CommandArgument[]
base("privatemessage", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_PM_DESC"], "pm", EFClient.Permission.User, true, new CommandArgument[]
{
new CommandArgument()
{
@ -734,7 +707,7 @@ namespace SharedLibraryCore.Commands
public class CFlag : Command
{
public CFlag() :
base("flag", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_FLAG_DESC"], "fp", EFClient.Permission.Moderator, true, new CommandArgument[]
base("flag", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_FLAG_DESC"], "fp", EFClient.Permission.Moderator, true, new CommandArgument[]
{
new CommandArgument()
{
@ -776,7 +749,7 @@ namespace SharedLibraryCore.Commands
public class CUnflag : Command
{
public CUnflag() :
base("unflag", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_UNFLAG_DESC"], "uf", EFClient.Permission.Moderator, true, new CommandArgument[]
base("unflag", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_UNFLAG_DESC"], "uf", EFClient.Permission.Moderator, true, new CommandArgument[]
{
new CommandArgument()
{
@ -814,7 +787,7 @@ namespace SharedLibraryCore.Commands
public class CReport : Command
{
public CReport() :
base("report", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_REPORT_DESC"], "rep", EFClient.Permission.User, true, new CommandArgument[]
base("report", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_REPORT_DESC"], "rep", EFClient.Permission.User, true, new CommandArgument[]
{
new CommandArgument()
{
@ -885,7 +858,7 @@ namespace SharedLibraryCore.Commands
public class CListReports : Command
{
public CListReports() :
base("reports", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_REPORTS_DESC"], "reps", EFClient.Permission.Moderator, false, new CommandArgument[]
base("reports", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_REPORTS_DESC"], "reps", EFClient.Permission.Moderator, false, new CommandArgument[]
{
new CommandArgument()
{
@ -922,7 +895,7 @@ namespace SharedLibraryCore.Commands
public class CMask : Command
{
public CMask() :
base("mask", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_MASK_DESC"], "hide", EFClient.Permission.Moderator, false)
base("mask", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_MASK_DESC"], "hide", EFClient.Permission.Moderator, false)
{ }
public override async Task ExecuteAsync(GameEvent E)
@ -945,7 +918,7 @@ namespace SharedLibraryCore.Commands
public class CListBanInfo : Command
{
public CListBanInfo() :
base("baninfo", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_BANINFO_DESC"], "bi", EFClient.Permission.Moderator, true, new CommandArgument[]
base("baninfo", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_BANINFO_DESC"], "bi", EFClient.Permission.Moderator, true, new CommandArgument[]
{
new CommandArgument()
{
@ -978,7 +951,7 @@ namespace SharedLibraryCore.Commands
public class CListAlias : Command
{
public CListAlias() :
base("alias", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_ALIAS_DESC"], "known", EFClient.Permission.Moderator, true, new CommandArgument[]
base("alias", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_ALIAS_DESC"], "known", EFClient.Permission.Moderator, true, new CommandArgument[]
{
new CommandArgument()
{
@ -1012,7 +985,7 @@ namespace SharedLibraryCore.Commands
public class CExecuteRCON : Command
{
public CExecuteRCON() :
base("rcon", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_RCON_DESC"], "rcon", EFClient.Permission.Owner, false, new CommandArgument[]
base("rcon", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_RCON_DESC"], "rcon", EFClient.Permission.Owner, false, new CommandArgument[]
{
new CommandArgument()
{
@ -1040,7 +1013,7 @@ namespace SharedLibraryCore.Commands
public class CPlugins : Command
{
public CPlugins() :
base("plugins", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_PLUGINS_DESC"], "p", EFClient.Permission.Administrator, false)
base("plugins", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_PLUGINS_DESC"], "p", EFClient.Permission.Administrator, false)
{ }
public override Task ExecuteAsync(GameEvent E)
@ -1057,7 +1030,7 @@ namespace SharedLibraryCore.Commands
public class CIP : Command
{
public CIP() :
base("getexternalip", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_IP_DESC"], "ip", EFClient.Permission.User, false)
base("getexternalip", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_IP_DESC"], "ip", EFClient.Permission.User, false)
{ }
public override Task ExecuteAsync(GameEvent E)
@ -1069,7 +1042,7 @@ namespace SharedLibraryCore.Commands
public class CPruneAdmins : Command
{
public CPruneAdmins() : base("prune", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_PRUNE_DESC"], "pa", EFClient.Permission.Owner, false, new CommandArgument[]
public CPruneAdmins() : base("prune", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_PRUNE_DESC"], "pa", EFClient.Permission.Owner, false, new CommandArgument[]
{
new CommandArgument()
{
@ -1108,10 +1081,10 @@ namespace SharedLibraryCore.Commands
{
var lastActive = DateTime.UtcNow.AddDays(-inactiveDays);
inactiveUsers = await context.Clients
.Where(c => c.Level > EFClient.Permission.Flagged && c.Level <= EFClient.Permission.Moderator)
.Where(c => c.Level > EFClient.Permission.Flagged && c.Level <= EFClient.Permission.Moderator)
.Where(c => c.LastConnection < lastActive)
.ToListAsync();
inactiveUsers.ForEach(c => c.Level = EFClient.Permission.User);
inactiveUsers.ForEach(c => c.Level = EFClient.Permission.User);
await context.SaveChangesAsync();
}
E.Origin.Tell($"^5{inactiveUsers.Count} ^7{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_PRUNE_SUCCESS"]}");
@ -1120,7 +1093,7 @@ namespace SharedLibraryCore.Commands
public class CSetPassword : Command
{
public CSetPassword() : base("setpassword", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SETPASSWORD_DESC"], "sp", EFClient.Permission.Moderator, false, new CommandArgument[]
public CSetPassword() : base("setpassword", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SETPASSWORD_DESC"], "sp", EFClient.Permission.Moderator, false, new CommandArgument[]
{
new CommandArgument()
{
@ -1154,7 +1127,7 @@ namespace SharedLibraryCore.Commands
public class CKillServer : Command
{
public CKillServer() : base("killserver", "kill the game server", "kill", EFClient.Permission.Administrator, false)
public CKillServer() : base("killserver", "kill the game server", "kill", EFClient.Permission.Administrator, false)
{
}
@ -1236,7 +1209,7 @@ namespace SharedLibraryCore.Commands
public class CPing : Command
{
public CPing() : base("ping", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_PING_DESC"], "pi", EFClient.Permission.User, false, new CommandArgument[]
public CPing() : base("ping", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_PING_DESC"], "pi", EFClient.Permission.User, false, new CommandArgument[]
{
new CommandArgument()
{
@ -1277,7 +1250,7 @@ namespace SharedLibraryCore.Commands
public class CSetGravatar : Command
{
public CSetGravatar() : base("setgravatar", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_GRAVATAR_DESC"], "sg", EFClient.Permission.User, false, new CommandArgument[]
public CSetGravatar() : base("setgravatar", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_GRAVATAR_DESC"], "sg", EFClient.Permission.User, false, new CommandArgument[]
{
new CommandArgument()
{
@ -1341,7 +1314,7 @@ namespace SharedLibraryCore.Commands
/// </summary>
public class CNextMap : Command
{
public CNextMap() : base("nextmap", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_NEXTMAP_DESC"], "nm", EFClient.Permission.User, false) { }
public CNextMap() : base("nextmap", Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_NEXTMAP_DESC"], "nm", EFClient.Permission.User, false) { }
public static async Task<string> GetNextMap(Server s)
{
string mapRotation = (await s.GetDvarAsync<string>("sv_mapRotation")).Value.ToLower();

View File

@ -33,6 +33,7 @@ namespace SharedLibraryCore.Configuration
public List<string> AutoMessages { get; set; }
public List<string> GlobalRules { get; set; }
public List<MapConfiguration> Maps { get; set; }
public List<string> DisallowedClientNames { get; set; }
public IBaseConfiguration Generate()
{
@ -61,6 +62,13 @@ namespace SharedLibraryCore.Configuration
}
RConPollRate = 5000;
DisallowedClientNames = new List<string>()
{
"Unknown Soldier",
"UnknownSoldier",
"CHEATER",
"VickNet"
};
return this;
}

View File

@ -20,5 +20,7 @@ namespace SharedLibraryCore.Dtos
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

@ -85,6 +85,14 @@ namespace SharedLibraryCore
/// a client's information was updated
/// </summary>
Update,
/// <summary>
/// connection was lost to a server (the server has not responded after a number of attempts)
/// </summary>
ConnectionLost,
/// <summary>
/// connection was restored to a server (the server began responding again)
/// </summary>
ConnectionRestored,
// events "generated" by clients
/// <summary>
@ -167,6 +175,10 @@ namespace SharedLibraryCore
/// team info printed out by game script
/// </summary>
JoinTeam = 304,
/// <summary>
/// used for community generated plugin events
/// </summary>
Other
}
static long NextEventId;

View File

@ -3,6 +3,7 @@ using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace SharedLibraryCore.Database.Models
@ -377,7 +378,7 @@ namespace SharedLibraryCore.Database.Models
/// <param name="unbanReason">reason for the unban</param>
/// <param name="sender">client performing the unban</param>
/// <returns></returns>
public GameEvent Unban(String unbanReason, EFClient sender)
public GameEvent Unban(string unbanReason, EFClient sender)
{
var e = new GameEvent()
{
@ -399,6 +400,32 @@ namespace SharedLibraryCore.Database.Models
return e;
}
/// <summary>
/// sets the level of the client
/// </summary>
/// <param name="permission">new permission to set client to</param>
/// <param name="sender">user performing the set level</param>
/// <returns></returns>
public GameEvent SetLevel(Permission permission, EFClient sender)
{
var e = new GameEvent()
{
Type = GameEvent.EventType.ChangePermission,
Extra = permission,
Origin = sender,
Target = this,
Owner = sender.CurrentServer
};
if (this.Level > sender.Level)
{
e.FailReason = GameEvent.EventFailReason.Permission;
}
sender.CurrentServer.Manager.GetEventHandler().AddEvent(e);
return e;
}
/// <summary>
/// Handles any client related logic on connection
/// </summary>
@ -416,9 +443,9 @@ namespace SharedLibraryCore.Database.Models
return;
}
if (Name == "Unknown Soldier" ||
Name == "UnknownSoldier" ||
Name == "CHEATER")
if (CurrentServer.Manager.GetApplicationSettings().Configuration()
.DisallowedClientNames
?.Any(_name => Regex.IsMatch(Name, _name)) ?? false)
{
CurrentServer.Logger.WriteDebug($"Kicking {this} because their name is generic");
Kick(loc["SERVER_KICK_GENERICNAME"], Utilities.IW4MAdminClient(CurrentServer));
@ -453,92 +480,121 @@ namespace SharedLibraryCore.Database.Models
await CurrentServer.Manager.GetClientService().Update(this);
}
public async Task<bool> OnJoin(int? ipAddress)
public async Task OnJoin(int? ipAddress)
{
CurrentServer.Logger.WriteDebug($"Start join for {this}::{ipAddress}::{Level.ToString()}");
IPAddress = ipAddress;
var loc = Utilities.CurrentLocalization.LocalizationIndex;
var autoKickClient = Utilities.IW4MAdminClient(CurrentServer);
if (ipAddress != null)
{
// todo: remove this in a few weeks because it's just temporary for server forwarding
if (IPAddressString == "66.150.121.184" || IPAddressString == "62.210.178.177")
{
Kick($"Your favorite servers are outdated. Please remove and re-add this server. ({CurrentServer.Hostname})", autoKickClient);
return false;
}
IPAddress = ipAddress;
await CurrentServer.Manager.GetClientService().UpdateAlias(this);
}
// we want to run any non GUID based logic here
OnConnect();
await CurrentServer.Manager.GetClientService().Update(this);
CurrentServer.Logger.WriteDebug($"OnConnect finished for {this}");
if (await CanConnect(ipAddress) && IPAddress != null)
{
var e = new GameEvent()
{
Type = GameEvent.EventType.Join,
Origin = this,
Target = this,
Owner = CurrentServer
};
#region CLIENT_BAN
CurrentServer.Manager.GetEventHandler().AddEvent(e);
await CurrentServer.Manager.GetClientService().Update(this);
}
else
{
CurrentServer.Logger.WriteDebug($"Client {this} is not allowed to join the server");
}
CurrentServer.Logger.WriteDebug($"OnJoin finished for {this}");
}
private async Task<bool> CanConnect(int? ipAddress)
{
var loc = Utilities.CurrentLocalization.LocalizationIndex;
var autoKickClient = Utilities.IW4MAdminClient(CurrentServer);
#region CLIENT_GUID_BAN
// kick them as their level is banned
if (Level == Permission.Banned)
{
CurrentServer.Logger.WriteDebug($"Kicking {this} because they are banned");
var ban = ReceivedPenalties.FirstOrDefault(_penalty => _penalty.Expires == null && _penalty.Active);
var profileBan = ReceivedPenalties.FirstOrDefault(_penalty => _penalty.Expires == null && _penalty.Active);
if (ban == null)
if (profileBan == null)
{
// this is from the old system before bans were applied to all accounts
ban = (await CurrentServer.Manager
profileBan = (await CurrentServer.Manager
.GetPenaltyService()
.GetActivePenaltiesAsync(AliasLinkId))
.FirstOrDefault(_penalty => _penalty.Type == Penalty.PenaltyType.Ban);
CurrentServer.Logger.WriteError($"Client {this} is banned, but no penalty exists for their ban");
CurrentServer.Logger.WriteWarning($"Client {this} is GUID banned, but no previous penalty exists for their ban");
if (profileBan == null)
{
profileBan = new EFPenalty() { Offense = loc["SERVER_BAN_UNKNOWN"] };
CurrentServer.Logger.WriteWarning($"Client {this} is GUID banned, but we could not find the penalty on any linked accounts");
}
// hack: re apply the automated offense to the reban
if (ban.AutomatedOffense != null)
if (profileBan.AutomatedOffense != null)
{
autoKickClient.AdministeredPenalties?.Add(new EFPenalty()
{
AutomatedOffense = ban.AutomatedOffense
AutomatedOffense = profileBan.AutomatedOffense
});
}
// this is a reban of the new GUID and IP
Ban($"{ban.Offense}", autoKickClient, false);
Ban($"{profileBan.Offense}", autoKickClient, false);
return false;
}
Kick($"{loc["SERVER_BAN_PREV"]} {ban?.Offense}", autoKickClient);
return false;
}
var tempBan = ReceivedPenalties.FirstOrDefault(_penalty => _penalty.Type == Penalty.PenaltyType.TempBan && _penalty.Expires > DateTime.UtcNow && _penalty.Active);
// they have an active tempban tied to their GUID
if (tempBan != null)
{
CurrentServer.Logger.WriteDebug($"Kicking {this} because they are temporarily banned");
Kick($"{loc["SERVER_TB_REMAIN"]} ({(tempBan.Expires.Value - DateTime.UtcNow).TimeSpanText()} {loc["WEBFRONT_PENALTY_TEMPLATE_REMAINING"]})", autoKickClient);
Kick($"{loc["SERVER_BAN_PREV"]} {profileBan?.Offense}", autoKickClient);
return false;
}
#endregion
#region CLIENT_GUID_TEMPBAN
else
{
var profileTempBan = ReceivedPenalties.FirstOrDefault(_penalty => _penalty.Type == Penalty.PenaltyType.TempBan && _penalty.Active);
// they have an active tempban tied to their GUID
if (profileTempBan != null)
{
CurrentServer.Logger.WriteDebug($"Kicking {this} because their GUID is temporarily banned");
Kick($"{loc["SERVER_TB_REMAIN"]} ({(profileTempBan.Expires.Value - DateTime.UtcNow).TimeSpanText()} {loc["WEBFRONT_PENALTY_TEMPLATE_REMAINING"]})", autoKickClient);
return false;
}
}
#endregion
#region CLIENT_LINKED_BAN
// we want to get any penalties that are tied to their IP or AliasLink (but not necessarily their GUID)
var activePenalties = await CurrentServer.Manager.GetPenaltyService().GetActivePenaltiesAsync(AliasLinkId, ipAddress);
var currentBan = activePenalties.FirstOrDefault(p => p.Type == Penalty.PenaltyType.Ban);
var tempBan = activePenalties.FirstOrDefault(_penalty => _penalty.Type == Penalty.PenaltyType.TempBan);
var currentAutoFlag = activePenalties.Where(p => p.Type == Penalty.PenaltyType.Flag && p.PunisherId == 1)
.Where(p => p.Active)
.OrderByDescending(p => p.When)
.FirstOrDefault();
// remove their auto flag status after a week
if (Level == Permission.Flagged &&
currentAutoFlag != null &&
(DateTime.UtcNow - currentAutoFlag.When).TotalDays > 7)
// they have an active tempban tied to their AliasLink
if (tempBan != null)
{
Level = Permission.User;
CurrentServer.Logger.WriteDebug($"Kicking {this} because their AliasLink is temporarily banned");
Kick($"{loc["SERVER_TB_REMAIN"]} ({(tempBan.Expires.Value - DateTime.UtcNow).TimeSpanText()} {loc["WEBFRONT_PENALTY_TEMPLATE_REMAINING"]})", autoKickClient);
return false;
}
var currentBan = activePenalties.FirstOrDefault(p => p.Type == Penalty.PenaltyType.Ban);
// they have a perm ban tied to their AliasLink
if (currentBan != null)
{
CurrentServer.Logger.WriteInfo($"Banned client {this} trying to evade...");
@ -567,18 +623,23 @@ namespace SharedLibraryCore.Database.Models
return false;
}
#endregion
else
{
var e = new GameEvent()
{
Type = GameEvent.EventType.Join,
Origin = this,
Target = this,
Owner = CurrentServer
};
var currentAutoFlag = activePenalties
.Where(p => p.Type == Penalty.PenaltyType.Flag && p.PunisherId == 1)
.OrderByDescending(p => p.When)
.FirstOrDefault();
// remove their auto flag status after a week
if (Level == Permission.Flagged &&
currentAutoFlag != null &&
(DateTime.UtcNow - currentAutoFlag.When).TotalDays > 7)
{
Level = Permission.User;
}
CurrentServer.Manager.GetEventHandler().AddEvent(e);
return true;
}
}

View File

@ -45,7 +45,6 @@ namespace SharedLibraryCore.Services
OriginEntityId = e.Origin.ClientId,
TargetEntityId = e.Target?.ClientId ?? 0,
Comment = "Executed command",
PreviousValue = "",
CurrentValue = e.Message,
TypeOfChange = EFChangeHistory.ChangeType.Command
};
@ -56,8 +55,7 @@ namespace SharedLibraryCore.Services
OriginEntityId = e.Origin.ClientId,
TargetEntityId = e.Target.ClientId,
TypeOfChange = EFChangeHistory.ChangeType.Permission,
PreviousValue = ((Change)e.Extra).PreviousValue,
CurrentValue = ((Change)e.Extra).NewValue
CurrentValue = ((EFClient.Permission)e.Extra).ToString()
};
break;
default:

View File

@ -21,7 +21,6 @@ namespace SharedLibraryCore.Services
{
Level = Permission.User,
FirstConnection = DateTime.UtcNow,
Connections = 1,
LastConnection = DateTime.UtcNow,
Masked = false,
NetworkId = entity.NetworkId,
@ -356,11 +355,25 @@ namespace SharedLibraryCore.Services
}
}
/// <summary>
/// retrieves the number of owners
/// (client level is owner)
/// </summary>
/// <returns></returns>
public async Task<int> GetOwnerCount()
{
using (var ctx = new DatabaseContext(true))
{
return await ctx.Clients.AsNoTracking()
.CountAsync(_client => _client.Level == Permission.Owner);
}
}
public async Task<List<EFClient>> GetPrivilegedClients()
{
using (var context = new DatabaseContext(disableTracking: true))
{
var iqClients = from client in context.Clients
var iqClients = from client in context.Clients.AsNoTracking()
where client.Level >= Permission.Trusted
where client.Active
select new EFClient()

View File

@ -77,7 +77,7 @@ namespace WebfrontCore.Controllers
}
catch (System.Collections.Generic.KeyNotFoundException)
catch (KeyNotFoundException)
{
// force the "banned" client to be signed out
HttpContext.SignOutAsync().Wait(5000);

View File

@ -135,8 +135,8 @@ namespace WebfrontCore.Controllers
public async Task<IActionResult> PrivilegedAsync()
{
var admins = (await Manager.GetClientService().GetPrivilegedClients())
.GroupBy(a => a.AliasLinkId).Where(_clients => _clients.FirstOrDefault(_client => _client.LastConnection == _clients.Max(c => c.LastConnection)) != null)
.Select(_client => _client.First())
.GroupBy(a => a.AliasLinkId)
.Select(_client => _client.OrderByDescending(_c => _c.LastConnection).First())
.OrderByDescending(_client => _client.Level);
var adminsDict = new Dictionary<EFClient.Permission, IList<ClientInfo>>();

View File

@ -33,30 +33,42 @@ namespace WebfrontCore.Controllers
}));
}
/// <summary>
/// retrieves all permanent bans ordered by ban date
/// if request is authorized, it will include the client's ip address.
/// </summary>
/// <returns></returns>
public async Task<IActionResult> PublicAsync()
{
IList<EFPenalty> penalties;
IList<PenaltyInfo> penalties;
using (var ctx = new DatabaseContext(disableTracking: true))
{
penalties = await ctx.Penalties
// todo: this seems like it's pulling unnecessary info from LINQ to entities.
var iqPenalties = ctx.Penalties
.Where(p => p.Type == SharedLibraryCore.Objects.Penalty.PenaltyType.Ban && p.Active)
.ToListAsync();
.OrderByDescending(_penalty => _penalty.When)
.Select(p => new PenaltyInfo()
{
Id = p.PenaltyId,
OffenderId = p.OffenderId,
Offense = p.Offense,
PunisherId = p.PunisherId,
Type = p.Type.ToString(),
TimePunished = p.When.ToString(),
TimeRemaining = "",
AutomatedOffense = Authorized ? p.AutomatedOffense : "",
NetworkId = (ulong)p.Offender.NetworkId,
IPAddress = Authorized ? p.Offender.IPAddressString : ""
});
#if DEBUG == true
var querySql = iqPenalties.ToSql();
#endif
penalties = await iqPenalties.ToListAsync();
}
var penaltiesDto = penalties.Select(p => new PenaltyInfo()
{
Id = p.PenaltyId,
OffenderId = p.OffenderId,
Offense = p.Offense,
PunisherId = p.PunisherId,
Type = p.Type.ToString(),
TimePunished = p.When.ToString(),
TimeRemaining = "",
AutomatedOffense = p.AutomatedOffense
}).ToList();
return Json(penaltiesDto);
return Json(penalties);
}
}
}

View File

@ -6,37 +6,23 @@
string gravatarUrl = Model.Meta.FirstOrDefault(m => m.Key == "GravatarEmail")?.Value;
bool isTempBanned = Model.ActivePenaltyType == "TempBan";
}
<div id="profile_wrapper" class="d-flex row pb-3">
<div id="profile_avatar" class="ml-auto mr-auto mb-4 mb-md-0 text-center level-bgcolor-@Model.LevelInt @(isTempBanned ? "penalties-bgcolor-tempban" : "")" style="background-image:url('@string.Format("https://gravatar.com/avatar/{0}?size=168&default=blank&rating=pg", gravatarUrl)')">
<div id="profile_wrapper" class="pb-3 row d-flex flex-fill">
<div id="profile_avatar" class="text-center level-bgcolor-@Model.LevelInt @(isTempBanned ? "penalties-bgcolor-tempban" : "")" style="background-image:url('@string.Format("https://gravatar.com/avatar/{0}?size=168&default=blank&rating=pg", gravatarUrl)')">
@if (string.IsNullOrEmpty(gravatarUrl))
{
<span class="profile-shortcode">@shortCode</span>
}
</div>
<div class="ml-auto mr-auto">
<div id="profile_name" class="client-name h1 pl-3 pr-3">@Model.Name</div>
<div id="profile_info" class="text-center text-md-left pr-md-3 pl-md-3">
<div class="">
<div class="text-center text-sm-left">
<div id="profile_name" class="client-name h1">@Model.Name</div>
<div id="profile_level" class="text-muted mb-2">
<h5><span class="level-color-@Model.LevelInt @(isTempBanned ? "penalties-color-tempban" : "")"><strong>@Model.Level @(isTempBanned ? $"({loc["WEBFRONT_PROFILE_TEMPBAN"]})" : "")</strong></span></h5>
</div>
<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>
<div id="profile_meta_0" class="text-center text-sm-left"></div>
</div>
</div>
<div class="flex-fill mb-1 pl-md-3 pr-md-3 align-self-end text-center text-sm-left" id="profile_meta_1">
</div>
@if (ViewBag.Authorized)
{
<div class="mr-auto ml-auto">
<div class="text-center text-sm-right mt-2">
@if (ViewBag.Authorized)
{
<div class="text-center text-sm-right col-lg-4 col-12 mt-2">
<div id="profile_aliases_btn" class="oi oi-caret-bottom h3 ml-0 ml-md-2"></div>
@if (Model.LevelInt != -1)
{
@ -81,10 +67,27 @@
}
</div>
</div>
<div class="flex-fill text-center text-sm-right" id="profile_meta_2">
</div>
}
</div>
@*<div id="profile_info" class="text-center text-md-left pr-md-3 pl-md-3">
<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>
<div id="profile_meta_0" class="text-center text-sm-left"></div>
</div>
<div class="flex-fill mb-1 pl-md-3 pr-md-3 align-self-end text-center text-sm-left" id="profile_meta_1">
</div>
<div class="flex-fill text-center text-sm-right" id="profile_meta_2">
</div>*@
</div>
<div class="row d-md-flex pt-2">
@ -100,7 +103,7 @@
<script>
const clientInfo = {};
clientInfo.clientId = @Model.ClientId;
clientInfo.Meta =@Html.Raw(Json.Serialize(@Model.Meta.Where(m => m.Show)));
clientInfo.Meta = @Html.Raw(Json.Serialize(@Model.Meta.Where(m => m.Show)));
</script>
<environment include="Development">
<script type="text/javascript" src="~/js/profile.js"></script>

View File

@ -146,13 +146,12 @@
}
#profile_avatar {
height: 10.5rem;
width: 10.5rem;
}
.profile-shortcode {
font-size: 10.5rem;
line-height: 10.5rem;
font-size: 5rem;
line-height: 5rem;
color: white;
}