@using SharedLibraryCore.Interfaces @using Data.Models @using Data.Models.Client @using WebfrontCore.Permissions @using WebfrontCore.ViewModels @model SharedLibraryCore.Dtos.PlayerInfo @{ var match = System.Text.RegularExpressions.Regex.Match(Model.Name.ToUpper(), "[A-Z]").Value; var shortCode = match == string.Empty ? "?" : match; var gravatarUrl = Model.Meta.FirstOrDefault(m => m.Key == "GravatarEmail")?.Value; var isFlagged = Model.LevelInt == (int)EFClient.Permission.Flagged; var isPermBanned = Model.LevelInt == (int)EFClient.Permission.Banned; var isTempBanned = Model.ActivePenalty?.Type == EFPenalty.PenaltyType.TempBan; var translationKey = $"WEBFRONT_PROFILE_{Model.ActivePenalty?.Type.ToString().ToUpper()}_INFO"; var ignoredMetaTypes = new[] { MetaType.Information, MetaType.Other, MetaType.QuickMessage }; string ClassForPenaltyType(EFPenalty.PenaltyType type) { return type switch { EFPenalty.PenaltyType.Ban => "alert-danger", EFPenalty.PenaltyType.Flag => "alert-secondary", EFPenalty.PenaltyType.TempBan => "alert-secondary", _ => "alert" }; } string ClassForProfileBackground() { return (ViewBag.PermissionsSet as IEnumerable<string>).HasPermission(WebfrontEntity.ClientLevel, WebfrontPermission.Read) ? $"level-bgcolor-{Model.LevelInt}" : "level-bgcolor-0"; } } <div class="content row mt-20"> <div class="col-12 col-lg-9"> @if (Model.ActivePenalty != null) { <has-permission entity="ClientLevel" required-permission="Read"> <div class="alert @ClassForPenaltyType(Model.ActivePenalty.Type) mt-10 mb-10" role="alert"> @foreach (var result in Utilities.SplitTranslationTokens(translationKey)) { switch (result.MatchValue) { case "reason": <span class="text-light-dm font-weight-lighter">@(ViewBag.Authorized ? !string.IsNullOrEmpty(Model.ActivePenalty.AutomatedOffense) && Model.ActivePenalty.Type != EFPenalty.PenaltyType.Warning ? Utilities.FormatExt(ViewBag.Localization["WEBFRONT_PROFILE_ANTICHEAT_DETECTION"], Model.ActivePenalty.AutomatedOffense) : Model.ActivePenalty.Offense.StripColors() : Model.ActivePenalty.Offense.StripColors())</span> break; case "time": <span class="text-light-dm font-weight-lighter"> @((Model.ActivePenalty.Expires.Value - DateTime.UtcNow).HumanizeForCurrentCulture()) </span> break; default: <span>@result.MatchValue</span> break; } } </div> </has-permission> } <h2 class="content-title mb-0">@ViewBag.Localization["WEBFRONT_PROFILE_TITLE"]</h2> <div class="font-size-12 text-muted">@ViewBag.Localization[$"GAME_{Model.Game}"]</div> <div id="profile_wrapper" class="mb-10 mt-10"> <!-- online status indicator --> @if (Model.Online) { <div class="bg-success rounded-circle position-absolute status-indicator z-20 mt-10 ml-10" data-toggle="tooltip" data-placement="bottom" data-title="@ViewBag.Localization["WEBFRONT_PROFILE_TOOLTIP_ONLINE"]"></div> <div class="bg-success rounded-circle position-absolute status-indicator with-ripple z-10 mt-10 ml-10"></div> } <!-- main profile row --> <div class="card p-15 ml-0 mr-0 mt-0 mb-10 d-flex flex-fill flex-wrap flex-column flex-md-row justify-content-center"> <div class="pl-5 pr-5 d-flex flex-column flex-md-row"> <div id="profile_avatar" class="w-150 w-md-100 h-150 h-md-100 mt-5 mb-5 d-flex justify-content-center align-self-center rounded @ClassForProfileBackground() @(isTempBanned ? "penalties-bgcolor-tempban" : "")" style="background-image:url('@($"https://gravatar.com/avatar/{gravatarUrl}?size=168&default=blank&rating=pg")"> @if (string.IsNullOrEmpty(gravatarUrl)) { <div class="profile-shortcode align-self-center text-dark-lm">@shortCode</div> } </div> <div class="d-flex flex-column align-self-center ml-20 mr-20 mt-10 mb-10 mt-md-0 mb-md-0 text-center text-md-left"> <!-- name --> <div id="profile_name"> <span class="font-size-20 font-weight-medium text-force-break"> <color-code value="@Model.Name"></color-code> </span> <has-permission entity="MetaAliasUpdate" required-permission="Read"> <div class="dropdown with-arrow"> <div data-toggle="dropdown" id="profileAliasHistory" aria-haspopup="true" aria-expanded="false"> @if (Model.Aliases.Any()) { <i class="oi oi-caret-bottom font-size-12" aria-hidden="true"></i> } </div> <div class="dropdown-menu dropdown-menu-center @(Model.Aliases.Where(alias => !alias.Item1.Contains(" ")).Max(alias => (int?)alias.Item1.Length) >= 15 ? "w-250" : "")" aria-labelledby="profileAliasHistory"> @foreach (var (alias, dateAdded) in Model.Aliases.OrderByDescending(alias => alias.Item2).Take(15)) { <a asp-controller="Client" asp-action="Find" asp-route-clientName="@alias.StripColors()" class="dropdown-item" data-toggle="tooltip" data-title="@dateAdded.HumanizeForCurrentCulture()"> <i class="oi oi-magnifying-glass text-muted mr-5"></i> <color-code value="@alias"></color-code> </a> } @if (Model.Aliases.Count > 15) { <div class="dropdown-divider"></div> <span class="dropdown-item bg-dark-dm bg-light-lm">@((ViewBag.Localization["WEBFRONT_PROFILE_ALIAS_COUNT_MORE_FORMAT"] as string).FormatExt(Model.Aliases.Count - 15))</span> } </div> </div> </has-permission> </div> <!-- permission level --> <has-permission entity="ClientLevel" required-permission="Read"> <div class="align-self-center align-self-md-start font-weight-bold font-size-16 level-color-@Model.LevelInt"> <div class="d-flex flex-row"> <color-code value="@Model.Level"></color-code> </div> </div> </has-permission> <!-- guid --> <has-permission entity="ClientGuid" required-permission="Read"> <div class="dropdown dropup with-arrow"> <div class="text-muted" data-toggle="dropdown" id="altGuidFormatsDropdown" aria-haspopup="true" aria-expanded="false">@Model.NetworkId.ToString("X")</div> <div class="dropdown-menu" aria-labelledby="altGuidFormatsDropdown"> <div class="p-10 font-size-12"> <div class="">@ViewBag.Localization["WEBFRONT_PROFILE_POPOVER_ALTERNATIVE_GUID"]</div> <div class="dropdown-divider mt-5 mb-5"></div> <div class="text-muted font-weight-lighter">@((ulong)Model.NetworkId)</div> </div> </div> </div> </has-permission> <!-- ip address --> <div class="align-self-center align-self-md-start d-flex flex-row"> <span class="text-muted mr-5">@Model.IPAddress</span> <has-permission entity="MetaAliasUpdate" required-permission="Read"> <div class="dropdown with-arrow"> <div data-toggle="dropdown" id="profileIPAddressHistory" aria-haspopup="true" aria-expanded="false"> @if (Model.IPs.Any(ip => !string.IsNullOrEmpty(ip.Item1))) { <i class="oi oi-caret-bottom font-size-12 text-muted" aria-hidden="true"></i> } </div> <div class="dropdown-menu dropdown-menu-center" aria-labelledby="profileAliasHistory"> @foreach (var (ip, dateAdded) in Model.IPs.OrderByDescending(ip => ip.Item2).Take(15)) { if (string.IsNullOrEmpty(ip)) { continue; } <div class="d-flex dropdown-item" data-toggle="tooltip" data-title="@dateAdded.HumanizeForCurrentCulture()"> <a asp-controller="Client" asp-action="Find" asp-route-clientName="@ip"> <i class="oi oi-magnifying-glass text-muted mr-5"></i> </a> <a href="#contextModal" class="profile-ip-lookup dropdown-item p-0 m-0" data-ip="@ip"> <color-code value="@ip"></color-code> </a> </div> } @if (Model.IPs.Count > 15) { <div class="dropdown-divider"></div> <span class="dropdown-item bg-dark-dm bg-light-lm">@((ViewBag.Localization["WEBFRONT_PROFILE_ALIAS_COUNT_MORE_FORMAT"] as string).FormatExt(Model.IPs.Count - 15))</span> } </div> </div> </has-permission> </div> </div> </div> @if (!string.IsNullOrWhiteSpace(Model.NoteMeta?.Note)) { <has-permission entity="ClientNote" required-permission="Read"> <div class="rounded border p-10 m-10 d-flex flex-column flex-md-row" style="border-style: dashed !important"> <i class="align-self-center oi oi-clipboard"></i> <div class="align-self-center font-size-12 font-weight-light pl-10 pr-10"> @foreach (var line in Model.NoteMeta.Note.Split("\n")) { <div class="text-force-break">@line.TrimEnd('\r')</div> } <div class="mt-5"> <a asp-controller="Client" asp-action="Profile" asp-route-id="@Model.NoteMeta.OriginEntityId" class="no-decoration "> <color-code value="@Model.NoteMeta.OriginEntityName"></color-code> </a> <span>— @Model.NoteMeta.ModifiedDate.HumanizeForCurrentCulture()</span> </div> </div> </div> </has-permission> } <div class="flex-fill d-flex justify-content-center justify-content-md-end mt-10 mt-md-0"> <!-- country flag --> <div id="ipGeoDropdown" class="dropdown with-arrow align-self-center"> <a href="#" data-toggle="dropdown" id="avatar-popover-toggle" aria-haspopup="true" aria-expanded="false"> @if (!string.IsNullOrEmpty(Model.GeoLocationInfo.CountryCode)) { <div class="profile-country-flag w-100 rounded align-self-center" style="background-image: url('https://flagcdn.com/w160/@(Model.GeoLocationInfo.CountryCode.ToLower()).png')" data-ip="@Model.IPAddress"></div> } </a> <div class="dropdown-menu dropdown-menu-center z-30" aria-labelledby="avatar-popover-toggle"> <has-permission entity="ClientIPAddress" required-permission="Read"> <h6 class="dropdown-header font-weight-bold">@Model.IPAddress</h6> <div class="dropdown-divider"></div> </has-permission> <div class="dropdown-item geo-country">@Model.GeoLocationInfo.Country</div> @if (!string.IsNullOrEmpty(Model.GeoLocationInfo.Region)) { <div class="dropdown-item text-muted geo-region">@Model.GeoLocationInfo.Region</div> <div class="dropdown-divider"></div> } @if (!string.IsNullOrEmpty(Model.GeoLocationInfo.Organization)) { <div class="dropdown-item geo-organization">@Model.GeoLocationInfo.Organization</div> } </div> </div> </div> <div> <hr class="mr-5 ml-5"/> <!-- meta info block --> <div class="d-flex flex-column flex-md-row text-center text-md-left flex-wrap"> <partial name="Meta/_Information.cshtml" model="@Model.Meta"/> </div> </div> </div> </div> <hr class="mt-10 mb-10"/> <!-- meta filter list --> <div class="mb-10 mt-15"> @foreach (var type in Enum.GetValues(typeof(MetaType)).Cast<MetaType>().Where(meta => !ignoredMetaTypes.Contains(meta)).OrderByDescending(meta => meta == MetaType.All)) { var buttonClass = !Model.MetaFilterType.HasValue && type == MetaType.All || Model.MetaFilterType.HasValue && Model.MetaFilterType.Value.ToString() == type.ToString() ? "btn-primary text-light" : "text-muted"; <a asp-action="Profile" asp-controller="Client" class="meta-filter no-decoration" asp-route-id="@Model.ClientId" asp-route-metaFilterType="@type" data-meta-type="@type"> <button class="btn btn-sm d-none d-md-inline mt-5 mb-5 @buttonClass">@type.ToTranslatedName()</button> <button class="btn btn-block d-block d-md-none mt-10 mb-10 @buttonClass">@type.ToTranslatedName()</button> </a> } </div> @if (!ViewBag.Authorized && !ViewBag.EnablePrivilegedUserPrivacy || ViewBag.Authorized) { <div class="row d-md-flex pt-2"> <div id="profile_events" class="text-muted text-left pl-md-0 pr-md-0"> @await Component.InvokeAsync("ProfileMetaList", new { clientId = Model.ClientId, count = 30, offset = 0, startAt = DateTime.UtcNow, metaType = Model.MetaFilterType }) </div> </div> } <hr class="mt-10 mb-10"/> <div class="text-center"> <i id="loaderLoad" class="oi oi-chevron-bottom loader-load-more text-primary" aria-hidden="true"></i> </div> </div> <!-- actions desktop --> @{ var menuItems = new SideContextMenuItems { MenuTitle = ViewBag.Localization["WEBFRONT_PROFILE_CONTEXT_MENU_TITLE"] }; if (Model.Online) { menuItems.Items.Add(new SideContextMenuItem { Title = ViewBag.Localization["WEBFRONT_PROFILE_CONTEXT_MENU_ACTION_JOIN"], IsLink = true, IsButton = true, Reference = Model.ConnectProtocolUrl, Tooltip = (ViewBag.Localization["WEBFRONT_PROFILE_CONTEXT_MENU_TOOLTIP_JOIN"] as string).FormatExt(Model.CurrentServerName.StripColors()), Icon = "oi-play-circle" }); } if (Model.LevelInt != -1 && ViewBag.Authorized) { menuItems.Items.Add(new SideContextMenuItem { Title = ViewBag.Localization["WEBFRONT_PROFILE_CONTEXT_MENU_ACTION_LEVEL"], IsButton = true, Reference = "edit", Icon = "oi-cog", EntityId = Model.ClientId }); } if (ViewBag.Authorized) { menuItems.Items.Add(new SideContextMenuItem { Title = ViewBag.Localization["WEBFRONT_PROFILE_CONTEXT_MENU_TAG"], IsButton = true, Reference = "SetClientTag", Icon = "oi-tag", EntityId = Model.ClientId }); if ((ViewBag.PermissionsSet as IEnumerable<string>).HasPermission(WebfrontEntity.ClientNote, WebfrontPermission.Write)) { menuItems.Items.Add(new SideContextMenuItem { Title = ViewBag.Localization["WEBFRONT_PROFILE_CONTEXT_MENU_NOTE"], IsButton = true, Reference = "AddClientNote", Icon = "oi-clipboard", EntityId = Model.ClientId }); } menuItems.Items.Add(new SideContextMenuItem { Title = ViewBag.Localization["WEBFRONT_PROFILE_CONTEXT_MENU_ACTION_MESSAGE"], IsButton = true, Reference = "OfflineMessage", Icon = "oi oi-envelope-closed", EntityId = Model.ClientId }); } menuItems.Items.Add(new SideContextMenuItem { Title = ViewBag.Localization["WEBFRONT_PROFILE_CONTEXT_MENU_ACTION_STATS"], IsButton = true, IsLink = true, Reference = Url.Action("Advanced", "ClientStatistics", new { id = Model.ClientId }), Icon = "oi-graph", }); if (!isPermBanned && ViewBag.Authorized) { menuItems.Items.Add(new SideContextMenuItem { Title = isFlagged ? ViewBag.Localization["WEBFRONT_ACTION_UNFLAG_NAME"] : ViewBag.Localization["WEBFRONT_ACTION_FLAG_NAME"], IsButton = true, Reference = isFlagged ? "unflag" : "flag", Icon = "oi-flag", EntityId = Model.ClientId }); } if (Model.LevelInt < (int)ViewBag.User.Level && Model.Online) { menuItems.Items.Add(new SideContextMenuItem { Title = ViewBag.Localization["WEBFRONT_ACTION_KICK_NAME"], IsButton = true, Reference = "kick", Icon = "oi-circle-x", EntityId = Model.ClientId }); } if ((Model.LevelInt < (int)ViewBag.User.Level && !Model.HasActivePenalty || isTempBanned) && ViewBag.Authorized) { menuItems.Items.Add(new SideContextMenuItem { Title = ViewBag.Localization["WEBFRONT_ACTION_BAN_NAME"], IsButton = true, Reference = "ban", Icon = "oi-lock-unlocked", EntityId = Model.ClientId }); } if ((Model.LevelInt < (int)ViewBag.User.Level && Model.HasActivePenalty || isTempBanned) && ViewBag.Authorized) { menuItems.Items.Add(new SideContextMenuItem { Title = ViewBag.Localization["WEBFRONT_ACTION_UNBAN_NAME"], IsButton = true, Reference = "unban", Icon = "oi-lock-locked", EntityId = Model.ClientId }); } } <partial name="_SideContextMenu" for="@menuItems"></partial> </div> @section targetid { <input type="hidden" name="targetId" value="@Model.ClientId"/> } @section scripts { <environment include="Development"> <script type="text/javascript" src="~/js/profile.js"></script> </environment> <script>initLoader('/Client/Meta/@Model.ClientId', '#profile_events', 30, 30, [{ 'name': 'metaFilterType', 'value': '@Model.MetaFilterType' }]);</script> }