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:
parent
1056c7c335
commit
cae6d8389e
@ -82,12 +82,8 @@ namespace IW4MAdmin
|
|||||||
};
|
};
|
||||||
|
|
||||||
Manager.GetEventHandler().AddEvent(e);
|
Manager.GetEventHandler().AddEvent(e);
|
||||||
|
|
||||||
if (client.IPAddress != null)
|
|
||||||
{
|
|
||||||
await client.OnJoin(client.IPAddress);
|
await client.OnJoin(client.IPAddress);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -186,6 +182,9 @@ namespace IW4MAdmin
|
|||||||
{
|
{
|
||||||
if (E.Type == GameEvent.EventType.ChangePermission)
|
if (E.Type == GameEvent.EventType.ChangePermission)
|
||||||
{
|
{
|
||||||
|
var newPermission = (EFClient.Permission)E.Extra;
|
||||||
|
E.Target.Level = newPermission;
|
||||||
|
|
||||||
if (!E.Target.IsPrivileged())
|
if (!E.Target.IsPrivileged())
|
||||||
{
|
{
|
||||||
// remove banned or demoted privileged user
|
// remove banned or demoted privileged user
|
||||||
@ -196,6 +195,8 @@ namespace IW4MAdmin
|
|||||||
{
|
{
|
||||||
Manager.GetPrivilegedClients()[E.Target.ClientId] = E.Target;
|
Manager.GetPrivilegedClients()[E.Target.ClientId] = E.Target;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await Manager.GetClientService().Update(E.Target);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (E.Type == GameEvent.EventType.PreConnect)
|
else if (E.Type == GameEvent.EventType.PreConnect)
|
||||||
@ -611,6 +612,17 @@ namespace IW4MAdmin
|
|||||||
if (ConnectionErrors > 0)
|
if (ConnectionErrors > 0)
|
||||||
{
|
{
|
||||||
Logger.WriteVerbose($"{loc["MANAGER_CONNECTION_REST"]} {IP}:{Port}");
|
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;
|
Throttled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -625,6 +637,19 @@ namespace IW4MAdmin
|
|||||||
{
|
{
|
||||||
Logger.WriteError($"{e.Message} {IP}:{Port}, {loc["SERVER_ERROR_POLLING"]}");
|
Logger.WriteError($"{e.Message} {IP}:{Port}, {loc["SERVER_ERROR_POLLING"]}");
|
||||||
Logger.WriteDebug($"Internal Exception: {e.Data["internal_exception"]}");
|
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;
|
Throttled = true;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -16,8 +16,8 @@ namespace IW4MAdmin.Plugins.Stats.Web.Controllers
|
|||||||
[HttpGet]
|
[HttpGet]
|
||||||
public IActionResult TopPlayersAsync()
|
public IActionResult TopPlayersAsync()
|
||||||
{
|
{
|
||||||
ViewBag.Title = Utilities.CurrentLocalization.LocalizationIndex.Set["WEBFRONT_STATS_INDEX_TITLE"];
|
ViewBag.Title = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_STATS_INDEX_TITLE"];
|
||||||
ViewBag.Description = Utilities.CurrentLocalization.LocalizationIndex.Set["WEBFRONT_STATS_INDEX_DESC"];
|
ViewBag.Description = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_STATS_INDEX_DESC"];
|
||||||
ViewBag.Servers = Manager.GetServers().Select(_server => new ServerInfo() { Name = _server.Hostname, ID = _server.EndPoint });
|
ViewBag.Servers = Manager.GetServers().Select(_server => new ServerInfo() { Name = _server.Hostname, ID = _server.EndPoint });
|
||||||
|
|
||||||
return View("Index");
|
return View("Index");
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
@if (Model.Count == 0)
|
@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)
|
@foreach (var stat in Model)
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using SharedLibraryCore.Database;
|
using SharedLibraryCore.Database;
|
||||||
using SharedLibraryCore.Database.Models;
|
using SharedLibraryCore.Database.Models;
|
||||||
using SharedLibraryCore.Events;
|
|
||||||
using SharedLibraryCore.Objects;
|
using SharedLibraryCore.Objects;
|
||||||
using SharedLibraryCore.Services;
|
using SharedLibraryCore.Services;
|
||||||
using System;
|
using System;
|
||||||
@ -35,27 +34,10 @@ namespace SharedLibraryCore.Commands
|
|||||||
|
|
||||||
public override async Task ExecuteAsync(GameEvent E)
|
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"]);
|
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
|
else
|
||||||
{
|
{
|
||||||
@ -307,11 +289,11 @@ namespace SharedLibraryCore.Commands
|
|||||||
// todo: make this better :)
|
// todo: make this better :)
|
||||||
if (P.Masked)
|
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
|
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)
|
if (count == 2 || E.Owner.GetClientsAsList().Count == 1)
|
||||||
@ -452,38 +434,41 @@ namespace SharedLibraryCore.Commands
|
|||||||
})
|
})
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
public override async Task ExecuteAsync(GameEvent E)
|
public override Task ExecuteAsync(GameEvent E)
|
||||||
{
|
{
|
||||||
if (E.Target == E.Origin)
|
|
||||||
{
|
|
||||||
E.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SETLEVEL_SELF"]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
EFClient.Permission oldPerm = E.Target.Level;
|
EFClient.Permission oldPerm = E.Target.Level;
|
||||||
EFClient.Permission newPerm = Utilities.MatchPermission(E.Data);
|
EFClient.Permission newPerm = Utilities.MatchPermission(E.Data);
|
||||||
|
|
||||||
if (newPerm == EFClient.Permission.Owner &&
|
if (E.Target == E.Origin)
|
||||||
|
{
|
||||||
|
E.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SETLEVEL_SELF"]);
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
else if (newPerm == EFClient.Permission.Owner &&
|
||||||
!E.Owner.Manager.GetApplicationSettings().Configuration().EnableMultipleOwners)
|
!E.Owner.Manager.GetApplicationSettings().Configuration().EnableMultipleOwners)
|
||||||
{
|
{
|
||||||
|
// only one owner is allowed
|
||||||
E.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SETLEVEL_OWNER"]);
|
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)
|
!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}");
|
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)
|
|
||||||
{
|
{
|
||||||
|
// 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()));
|
E.Origin.Tell(string.Format(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SETLEVEL_LEVELTOOHIGH"], E.Target.Name, (E.Origin.Level - 1).ToString()));
|
||||||
return;
|
return Task.CompletedTask;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (newPerm > EFClient.Permission.Banned)
|
else if (newPerm > EFClient.Permission.Banned)
|
||||||
@ -493,9 +478,10 @@ namespace SharedLibraryCore.Commands
|
|||||||
|
|
||||||
if (ActiveClient != null)
|
if (ActiveClient != null)
|
||||||
{
|
{
|
||||||
ActiveClient.Level = newPerm;
|
ActiveClient.SetLevel(newPerm, E.Origin);
|
||||||
await E.Owner.Manager.GetClientService().Update(ActiveClient);
|
|
||||||
|
|
||||||
|
// inform the client that they were promoted
|
||||||
|
// we don't really want to tell them if they're demoted haha
|
||||||
if (newPerm > oldPerm)
|
if (newPerm > oldPerm)
|
||||||
{
|
{
|
||||||
ActiveClient.Tell($"{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SETLEVEL_SUCCESS_TARGET"]} {newPerm}");
|
ActiveClient.Tell($"{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SETLEVEL_SUCCESS_TARGET"]} {newPerm}");
|
||||||
@ -504,26 +490,11 @@ namespace SharedLibraryCore.Commands
|
|||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
E.Target.Level = newPerm;
|
E.Target.SetLevel(newPerm, E.Origin);
|
||||||
await E.Owner.Manager.GetClientService().Update(E.Target);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var e = new GameEvent()
|
// inform the origin that the client has been updated
|
||||||
{
|
_ = newPerm < oldPerm ?
|
||||||
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 ?
|
|
||||||
E.Origin.Tell($"{Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SETLEVEL_DEMOTE_SUCCESS"]} {E.Target.Name}") :
|
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"]}");
|
E.Origin.Tell($"{E.Target.Name} {Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SETLEVEL_SUCCESS"]}");
|
||||||
}
|
}
|
||||||
@ -532,6 +503,8 @@ namespace SharedLibraryCore.Commands
|
|||||||
{
|
{
|
||||||
E.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SETLEVEL_FAIL"]);
|
E.Origin.Tell(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_SETLEVEL_FAIL"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ namespace SharedLibraryCore.Configuration
|
|||||||
public List<string> AutoMessages { get; set; }
|
public List<string> AutoMessages { get; set; }
|
||||||
public List<string> GlobalRules { get; set; }
|
public List<string> GlobalRules { get; set; }
|
||||||
public List<MapConfiguration> Maps { get; set; }
|
public List<MapConfiguration> Maps { get; set; }
|
||||||
|
public List<string> DisallowedClientNames { get; set; }
|
||||||
|
|
||||||
public IBaseConfiguration Generate()
|
public IBaseConfiguration Generate()
|
||||||
{
|
{
|
||||||
@ -61,6 +62,13 @@ namespace SharedLibraryCore.Configuration
|
|||||||
}
|
}
|
||||||
|
|
||||||
RConPollRate = 5000;
|
RConPollRate = 5000;
|
||||||
|
DisallowedClientNames = new List<string>()
|
||||||
|
{
|
||||||
|
"Unknown Soldier",
|
||||||
|
"UnknownSoldier",
|
||||||
|
"CHEATER",
|
||||||
|
"VickNet"
|
||||||
|
};
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -20,5 +20,7 @@ namespace SharedLibraryCore.Dtos
|
|||||||
public string TimePunished { get; set; }
|
public string TimePunished { get; set; }
|
||||||
public string TimeRemaining { get; set; }
|
public string TimeRemaining { get; set; }
|
||||||
public bool Expired { get; set; }
|
public bool Expired { get; set; }
|
||||||
|
public string IPAddress { get; set; }
|
||||||
|
public ulong NetworkId { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,6 +85,14 @@ namespace SharedLibraryCore
|
|||||||
/// a client's information was updated
|
/// a client's information was updated
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Update,
|
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
|
// events "generated" by clients
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -167,6 +175,10 @@ namespace SharedLibraryCore
|
|||||||
/// team info printed out by game script
|
/// team info printed out by game script
|
||||||
/// </summary>
|
/// </summary>
|
||||||
JoinTeam = 304,
|
JoinTeam = 304,
|
||||||
|
/// <summary>
|
||||||
|
/// used for community generated plugin events
|
||||||
|
/// </summary>
|
||||||
|
Other
|
||||||
}
|
}
|
||||||
|
|
||||||
static long NextEventId;
|
static long NextEventId;
|
||||||
|
@ -3,6 +3,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace SharedLibraryCore.Database.Models
|
namespace SharedLibraryCore.Database.Models
|
||||||
@ -377,7 +378,7 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
/// <param name="unbanReason">reason for the unban</param>
|
/// <param name="unbanReason">reason for the unban</param>
|
||||||
/// <param name="sender">client performing the unban</param>
|
/// <param name="sender">client performing the unban</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public GameEvent Unban(String unbanReason, EFClient sender)
|
public GameEvent Unban(string unbanReason, EFClient sender)
|
||||||
{
|
{
|
||||||
var e = new GameEvent()
|
var e = new GameEvent()
|
||||||
{
|
{
|
||||||
@ -399,6 +400,32 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
return e;
|
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>
|
/// <summary>
|
||||||
/// Handles any client related logic on connection
|
/// Handles any client related logic on connection
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -416,9 +443,9 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Name == "Unknown Soldier" ||
|
if (CurrentServer.Manager.GetApplicationSettings().Configuration()
|
||||||
Name == "UnknownSoldier" ||
|
.DisallowedClientNames
|
||||||
Name == "CHEATER")
|
?.Any(_name => Regex.IsMatch(Name, _name)) ?? false)
|
||||||
{
|
{
|
||||||
CurrentServer.Logger.WriteDebug($"Kicking {this} because their name is generic");
|
CurrentServer.Logger.WriteDebug($"Kicking {this} because their name is generic");
|
||||||
Kick(loc["SERVER_KICK_GENERICNAME"], Utilities.IW4MAdminClient(CurrentServer));
|
Kick(loc["SERVER_KICK_GENERICNAME"], Utilities.IW4MAdminClient(CurrentServer));
|
||||||
@ -453,92 +480,121 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
await CurrentServer.Manager.GetClientService().Update(this);
|
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()}");
|
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)
|
if (ipAddress != null)
|
||||||
{
|
{
|
||||||
// todo: remove this in a few weeks because it's just temporary for server forwarding
|
IPAddress = ipAddress;
|
||||||
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;
|
|
||||||
}
|
|
||||||
await CurrentServer.Manager.GetClientService().UpdateAlias(this);
|
await CurrentServer.Manager.GetClientService().UpdateAlias(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we want to run any non GUID based logic here
|
||||||
OnConnect();
|
OnConnect();
|
||||||
|
|
||||||
|
if (await CanConnect(ipAddress) && IPAddress != null)
|
||||||
|
{
|
||||||
|
var e = new GameEvent()
|
||||||
|
{
|
||||||
|
Type = GameEvent.EventType.Join,
|
||||||
|
Origin = this,
|
||||||
|
Target = this,
|
||||||
|
Owner = CurrentServer
|
||||||
|
};
|
||||||
|
|
||||||
|
CurrentServer.Manager.GetEventHandler().AddEvent(e);
|
||||||
|
|
||||||
await CurrentServer.Manager.GetClientService().Update(this);
|
await CurrentServer.Manager.GetClientService().Update(this);
|
||||||
|
}
|
||||||
|
|
||||||
CurrentServer.Logger.WriteDebug($"OnConnect finished for {this}");
|
else
|
||||||
|
{
|
||||||
|
CurrentServer.Logger.WriteDebug($"Client {this} is not allowed to join the server");
|
||||||
|
}
|
||||||
|
|
||||||
#region CLIENT_BAN
|
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
|
// kick them as their level is banned
|
||||||
if (Level == Permission.Banned)
|
if (Level == Permission.Banned)
|
||||||
{
|
{
|
||||||
CurrentServer.Logger.WriteDebug($"Kicking {this} because they are 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
|
// this is from the old system before bans were applied to all accounts
|
||||||
ban = (await CurrentServer.Manager
|
profileBan = (await CurrentServer.Manager
|
||||||
.GetPenaltyService()
|
.GetPenaltyService()
|
||||||
.GetActivePenaltiesAsync(AliasLinkId))
|
.GetActivePenaltiesAsync(AliasLinkId))
|
||||||
.FirstOrDefault(_penalty => _penalty.Type == Penalty.PenaltyType.Ban);
|
.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
|
// hack: re apply the automated offense to the reban
|
||||||
if (ban.AutomatedOffense != null)
|
if (profileBan.AutomatedOffense != null)
|
||||||
{
|
{
|
||||||
autoKickClient.AdministeredPenalties?.Add(new EFPenalty()
|
autoKickClient.AdministeredPenalties?.Add(new EFPenalty()
|
||||||
{
|
{
|
||||||
AutomatedOffense = ban.AutomatedOffense
|
AutomatedOffense = profileBan.AutomatedOffense
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is a reban of the new GUID and IP
|
// this is a reban of the new GUID and IP
|
||||||
Ban($"{ban.Offense}", autoKickClient, false);
|
Ban($"{profileBan.Offense}", autoKickClient, false);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Kick($"{loc["SERVER_BAN_PREV"]} {ban?.Offense}", autoKickClient);
|
Kick($"{loc["SERVER_BAN_PREV"]} {profileBan?.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);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
// we want to get any penalties that are tied to their IP or AliasLink (but not necessarily their GUID)
|
#region CLIENT_GUID_TEMPBAN
|
||||||
var activePenalties = await CurrentServer.Manager.GetPenaltyService().GetActivePenaltiesAsync(AliasLinkId, ipAddress);
|
else
|
||||||
var currentBan = activePenalties.FirstOrDefault(p => p.Type == Penalty.PenaltyType.Ban);
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
Level = Permission.User;
|
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 tempBan = activePenalties.FirstOrDefault(_penalty => _penalty.Type == Penalty.PenaltyType.TempBan);
|
||||||
|
|
||||||
|
// they have an active tempban tied to their AliasLink
|
||||||
|
if (tempBan != null)
|
||||||
|
{
|
||||||
|
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)
|
if (currentBan != null)
|
||||||
{
|
{
|
||||||
CurrentServer.Logger.WriteInfo($"Banned client {this} trying to evade...");
|
CurrentServer.Logger.WriteInfo($"Banned client {this} trying to evade...");
|
||||||
@ -567,18 +623,23 @@ namespace SharedLibraryCore.Database.Models
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var e = new GameEvent()
|
var currentAutoFlag = activePenalties
|
||||||
{
|
.Where(p => p.Type == Penalty.PenaltyType.Flag && p.PunisherId == 1)
|
||||||
Type = GameEvent.EventType.Join,
|
.OrderByDescending(p => p.When)
|
||||||
Origin = this,
|
.FirstOrDefault();
|
||||||
Target = this,
|
|
||||||
Owner = CurrentServer
|
// 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;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,6 @@ namespace SharedLibraryCore.Services
|
|||||||
OriginEntityId = e.Origin.ClientId,
|
OriginEntityId = e.Origin.ClientId,
|
||||||
TargetEntityId = e.Target?.ClientId ?? 0,
|
TargetEntityId = e.Target?.ClientId ?? 0,
|
||||||
Comment = "Executed command",
|
Comment = "Executed command",
|
||||||
PreviousValue = "",
|
|
||||||
CurrentValue = e.Message,
|
CurrentValue = e.Message,
|
||||||
TypeOfChange = EFChangeHistory.ChangeType.Command
|
TypeOfChange = EFChangeHistory.ChangeType.Command
|
||||||
};
|
};
|
||||||
@ -56,8 +55,7 @@ namespace SharedLibraryCore.Services
|
|||||||
OriginEntityId = e.Origin.ClientId,
|
OriginEntityId = e.Origin.ClientId,
|
||||||
TargetEntityId = e.Target.ClientId,
|
TargetEntityId = e.Target.ClientId,
|
||||||
TypeOfChange = EFChangeHistory.ChangeType.Permission,
|
TypeOfChange = EFChangeHistory.ChangeType.Permission,
|
||||||
PreviousValue = ((Change)e.Extra).PreviousValue,
|
CurrentValue = ((EFClient.Permission)e.Extra).ToString()
|
||||||
CurrentValue = ((Change)e.Extra).NewValue
|
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -21,7 +21,6 @@ namespace SharedLibraryCore.Services
|
|||||||
{
|
{
|
||||||
Level = Permission.User,
|
Level = Permission.User,
|
||||||
FirstConnection = DateTime.UtcNow,
|
FirstConnection = DateTime.UtcNow,
|
||||||
Connections = 1,
|
|
||||||
LastConnection = DateTime.UtcNow,
|
LastConnection = DateTime.UtcNow,
|
||||||
Masked = false,
|
Masked = false,
|
||||||
NetworkId = entity.NetworkId,
|
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()
|
public async Task<List<EFClient>> GetPrivilegedClients()
|
||||||
{
|
{
|
||||||
using (var context = new DatabaseContext(disableTracking: true))
|
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.Level >= Permission.Trusted
|
||||||
where client.Active
|
where client.Active
|
||||||
select new EFClient()
|
select new EFClient()
|
||||||
|
@ -77,7 +77,7 @@ namespace WebfrontCore.Controllers
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (System.Collections.Generic.KeyNotFoundException)
|
catch (KeyNotFoundException)
|
||||||
{
|
{
|
||||||
// force the "banned" client to be signed out
|
// force the "banned" client to be signed out
|
||||||
HttpContext.SignOutAsync().Wait(5000);
|
HttpContext.SignOutAsync().Wait(5000);
|
||||||
|
@ -135,8 +135,8 @@ namespace WebfrontCore.Controllers
|
|||||||
public async Task<IActionResult> PrivilegedAsync()
|
public async Task<IActionResult> PrivilegedAsync()
|
||||||
{
|
{
|
||||||
var admins = (await Manager.GetClientService().GetPrivilegedClients())
|
var admins = (await Manager.GetClientService().GetPrivilegedClients())
|
||||||
.GroupBy(a => a.AliasLinkId).Where(_clients => _clients.FirstOrDefault(_client => _client.LastConnection == _clients.Max(c => c.LastConnection)) != null)
|
.GroupBy(a => a.AliasLinkId)
|
||||||
.Select(_client => _client.First())
|
.Select(_client => _client.OrderByDescending(_c => _c.LastConnection).First())
|
||||||
.OrderByDescending(_client => _client.Level);
|
.OrderByDescending(_client => _client.Level);
|
||||||
|
|
||||||
var adminsDict = new Dictionary<EFClient.Permission, IList<ClientInfo>>();
|
var adminsDict = new Dictionary<EFClient.Permission, IList<ClientInfo>>();
|
||||||
|
@ -33,18 +33,22 @@ 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()
|
public async Task<IActionResult> PublicAsync()
|
||||||
{
|
{
|
||||||
IList<EFPenalty> penalties;
|
IList<PenaltyInfo> penalties;
|
||||||
|
|
||||||
using (var ctx = new DatabaseContext(disableTracking: true))
|
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)
|
.Where(p => p.Type == SharedLibraryCore.Objects.Penalty.PenaltyType.Ban && p.Active)
|
||||||
.ToListAsync();
|
.OrderByDescending(_penalty => _penalty.When)
|
||||||
}
|
.Select(p => new PenaltyInfo()
|
||||||
|
|
||||||
var penaltiesDto = penalties.Select(p => new PenaltyInfo()
|
|
||||||
{
|
{
|
||||||
Id = p.PenaltyId,
|
Id = p.PenaltyId,
|
||||||
OffenderId = p.OffenderId,
|
OffenderId = p.OffenderId,
|
||||||
@ -53,10 +57,18 @@ namespace WebfrontCore.Controllers
|
|||||||
Type = p.Type.ToString(),
|
Type = p.Type.ToString(),
|
||||||
TimePunished = p.When.ToString(),
|
TimePunished = p.When.ToString(),
|
||||||
TimeRemaining = "",
|
TimeRemaining = "",
|
||||||
AutomatedOffense = p.AutomatedOffense
|
AutomatedOffense = Authorized ? p.AutomatedOffense : "",
|
||||||
}).ToList();
|
NetworkId = (ulong)p.Offender.NetworkId,
|
||||||
|
IPAddress = Authorized ? p.Offender.IPAddressString : ""
|
||||||
|
});
|
||||||
|
#if DEBUG == true
|
||||||
|
var querySql = iqPenalties.ToSql();
|
||||||
|
#endif
|
||||||
|
|
||||||
return Json(penaltiesDto);
|
penalties = await iqPenalties.ToListAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Json(penalties);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,37 +6,23 @@
|
|||||||
string gravatarUrl = Model.Meta.FirstOrDefault(m => m.Key == "GravatarEmail")?.Value;
|
string gravatarUrl = Model.Meta.FirstOrDefault(m => m.Key == "GravatarEmail")?.Value;
|
||||||
bool isTempBanned = Model.ActivePenaltyType == "TempBan";
|
bool isTempBanned = Model.ActivePenaltyType == "TempBan";
|
||||||
}
|
}
|
||||||
<div id="profile_wrapper" class="d-flex row pb-3">
|
<div id="profile_wrapper" class="pb-3 row d-flex flex-fill">
|
||||||
<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_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))
|
@if (string.IsNullOrEmpty(gravatarUrl))
|
||||||
{
|
{
|
||||||
<span class="profile-shortcode">@shortCode</span>
|
<span class="profile-shortcode">@shortCode</span>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div class="ml-auto mr-auto">
|
<div class="">
|
||||||
<div id="profile_name" class="client-name h1 pl-3 pr-3">@Model.Name</div>
|
<div class="text-center text-sm-left">
|
||||||
<div id="profile_info" class="text-center text-md-left pr-md-3 pl-md-3">
|
<div id="profile_name" class="client-name h1">@Model.Name</div>
|
||||||
<div id="profile_level" class="text-muted mb-2">
|
<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>
|
<h5><span class="level-color-@Model.LevelInt @(isTempBanned ? "penalties-color-tempban" : "")"><strong>@Model.Level @(isTempBanned ? $"({loc["WEBFRONT_PROFILE_TEMPBAN"]})" : "")</strong></span></h5>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
@if (ViewBag.Authorized)
|
@if (ViewBag.Authorized)
|
||||||
{
|
{
|
||||||
<div class="mr-auto ml-auto">
|
<div class="text-center text-sm-right col-lg-4 col-12 mt-2">
|
||||||
<div class="text-center text-sm-right mt-2">
|
|
||||||
<div id="profile_aliases_btn" class="oi oi-caret-bottom h3 ml-0 ml-md-2"></div>
|
<div id="profile_aliases_btn" class="oi oi-caret-bottom h3 ml-0 ml-md-2"></div>
|
||||||
@if (Model.LevelInt != -1)
|
@if (Model.LevelInt != -1)
|
||||||
{
|
{
|
||||||
@ -81,10 +67,27 @@
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-fill text-center text-sm-right" id="profile_meta_2">
|
|
||||||
</div>
|
|
||||||
</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>
|
||||||
|
|
||||||
<div class="row d-md-flex pt-2">
|
<div class="row d-md-flex pt-2">
|
||||||
@ -100,7 +103,7 @@
|
|||||||
<script>
|
<script>
|
||||||
const clientInfo = {};
|
const clientInfo = {};
|
||||||
clientInfo.clientId = @Model.ClientId;
|
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>
|
</script>
|
||||||
<environment include="Development">
|
<environment include="Development">
|
||||||
<script type="text/javascript" src="~/js/profile.js"></script>
|
<script type="text/javascript" src="~/js/profile.js"></script>
|
||||||
|
@ -146,13 +146,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#profile_avatar {
|
#profile_avatar {
|
||||||
height: 10.5rem;
|
|
||||||
width: 10.5rem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.profile-shortcode {
|
.profile-shortcode {
|
||||||
font-size: 10.5rem;
|
font-size: 5rem;
|
||||||
line-height: 10.5rem;
|
line-height: 5rem;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user