1
0
mirror of https://github.com/RaidMax/IW4M-Admin.git synced 2025-06-10 15:20:48 -05:00

implement profile interaction registration through plugins (mute and vpn detection implementation)

This commit is contained in:
RaidMax
2022-09-08 15:03:38 -05:00
parent 7ad4615548
commit 8d8a8d869a
26 changed files with 452 additions and 26 deletions

View File

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Data.Models;
@ -24,6 +25,7 @@ namespace WebfrontCore.Controllers
{
private readonly ApplicationConfiguration _appConfig;
private readonly IMetaServiceV2 _metaService;
private readonly IInteractionRegistration _interactionRegistration;
private readonly string _banCommandName;
private readonly string _tempbanCommandName;
private readonly string _unbanCommandName;
@ -37,10 +39,12 @@ namespace WebfrontCore.Controllers
private readonly string _addClientNoteCommandName;
public ActionController(IManager manager, IEnumerable<IManagerCommand> registeredCommands,
ApplicationConfiguration appConfig, IMetaServiceV2 metaService) : base(manager)
ApplicationConfiguration appConfig, IMetaServiceV2 metaService,
IInteractionRegistration interactionRegistration) : base(manager)
{
_appConfig = appConfig;
_metaService = metaService;
_interactionRegistration = interactionRegistration;
foreach (var cmd in registeredCommands)
{
@ -86,6 +90,81 @@ namespace WebfrontCore.Controllers
}
}
public IActionResult DynamicActionForm(int? id, string meta)
{
var metaDict = JsonSerializer.Deserialize<Dictionary<string, string>>(meta);
if (metaDict is null)
{
return BadRequest();
}
metaDict.TryGetValue(nameof(ActionInfo.ActionButtonLabel), out var label);
metaDict.TryGetValue(nameof(ActionInfo.Name), out var name);
metaDict.TryGetValue(nameof(ActionInfo.ShouldRefresh), out var refresh);
metaDict.TryGetValue("Data", out var data);
metaDict.TryGetValue("InteractionId", out var interactionId);
bool.TryParse(refresh, out var shouldRefresh);
var inputs = new List<InputInfo>
{
new()
{
Name = "InteractionId",
Value = interactionId,
Type = "hidden"
},
new()
{
Name = "data",
Value = data,
Type = "hidden"
},
new()
{
Name = "TargetId",
Value = id?.ToString(),
Type = "hidden"
}
};
var info = new ActionInfo
{
ActionButtonLabel = label,
Name = name,
Action = nameof(DynamicActionAsync),
ShouldRefresh = shouldRefresh,
Inputs = inputs
};
return View("_ActionForm", info);
}
public async Task<IActionResult> DynamicActionAsync(string interactionId, string data, int? targetId,
CancellationToken token = default)
{
if (interactionId == "command")
{
var server = Manager.GetServers().First();
return await Task.FromResult(RedirectToAction("Execute", "Console", new
{
serverId = server.EndPoint,
command = $"{_appConfig.CommandPrefix}{data}"
}));
}
var game = (Reference.Game?)null;
if (targetId.HasValue)
{
game = (await Manager.GetClientService().Get(targetId.Value))?.GameName;
}
return Ok(await _interactionRegistration.ProcessInteraction(interactionId, targetId, game, token));
}
public IActionResult BanForm()
{
var info = new ActionInfo
@ -292,7 +371,7 @@ namespace WebfrontCore.Controllers
{
ClientId = Client.ClientId
});
return string.Format(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_GENERATETOKEN_SUCCESS"],
state.Token,
$"{state.RemainingTime} {Utilities.CurrentLocalization.LocalizationIndex["GLOBAL_MINUTES"]}",
@ -645,7 +724,7 @@ namespace WebfrontCore.Controllers
$"{_appConfig.CommandPrefix}{_setClientTagCommandName} @{targetId} {clientTag}"
}));
}
public async Task<IActionResult> AddClientNoteForm(int id)
{
var existingNote = await _metaService.GetPersistentMetaValue<ClientNoteMetaResponse>("ClientNotes", id);
@ -682,7 +761,7 @@ namespace WebfrontCore.Controllers
}
});
}
var server = Manager.GetServers().First();
return await Task.FromResult(RedirectToAction("Execute", "Console", new
{

View File

@ -25,14 +25,16 @@ namespace WebfrontCore.Controllers
private readonly StatsConfiguration _config;
private readonly IGeoLocationService _geoLocationService;
private readonly ClientService _clientService;
private readonly IInteractionRegistration _interactionRegistration;
public ClientController(IManager manager, IMetaServiceV2 metaService, StatsConfiguration config,
IGeoLocationService geoLocationService, ClientService clientService) : base(manager)
IGeoLocationService geoLocationService, ClientService clientService, IInteractionRegistration interactionRegistration) : base(manager)
{
_metaService = metaService;
_config = config;
_geoLocationService = geoLocationService;
_clientService = clientService;
_interactionRegistration = interactionRegistration;
}
[Obsolete]
@ -75,6 +77,8 @@ namespace WebfrontCore.Controllers
note.OriginEntityName = await _clientService.GetClientNameById(note.OriginEntityId);
}
var interactions = await _interactionRegistration.GetInteractions(id, client.GameName, token);
// even though we haven't set their level to "banned" yet
// (ie they haven't reconnected with the infringing player identifier)
// we want to show them as banned as to not confuse people.
@ -137,7 +141,8 @@ namespace WebfrontCore.Controllers
ingameClient.CurrentServer.Port),
CurrentServerName = ingameClient?.CurrentServer?.Hostname,
GeoLocationInfo = await _geoLocationService.Locate(client.IPAddressString),
NoteMeta = string.IsNullOrWhiteSpace(note?.Note) ? null: note
NoteMeta = string.IsNullOrWhiteSpace(note?.Note) ? null: note,
Interactions = interactions.ToList()
};
var meta = await _metaService.GetRuntimeMeta<InformationResponse>(new ClientPaginationRequest

View File

@ -15,7 +15,8 @@ public enum WebfrontEntity
RecentPlayersPage,
ProfilePage,
AdminMenu,
ClientNote
ClientNote,
Interaction
}
public enum WebfrontPermission

View File

@ -105,6 +105,8 @@ namespace WebfrontCore
{
options.AccessDeniedPath = "/";
options.LoginPath = "/";
options.Events.OnValidatePrincipal += ClaimsPermissionRemoval.ValidateAsync;
options.Events.OnSignedIn += ClaimsPermissionRemoval.OnSignedIn;
});
services.AddSingleton(Program.Manager);
@ -138,6 +140,7 @@ namespace WebfrontCore
services.AddSingleton(Program.ApplicationServiceProvider
.GetRequiredService<StatsConfiguration>());
services.AddSingleton(Program.ApplicationServiceProvider.GetRequiredService<IServerDataViewer>());
services.AddSingleton(Program.ApplicationServiceProvider.GetRequiredService<IInteractionRegistration>());
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.

View File

@ -12,6 +12,7 @@ public class SideContextMenuItem
public string Icon { get; set; }
public string Tooltip { get; set; }
public int? EntityId { get; set; }
public string Meta { get; set; }
}

View File

@ -3,7 +3,7 @@
@{
Layout = null;
}
<h5 class="modal-title mb-10">@Model.Name.Titleize()</h5>
<h5 class="modal-title mb-10">@Model.Name?.Titleize()</h5>
@if (Model.Inputs.Any(input => input.Type != "hidden"))
{
<hr class="mb-10"/>

View File

@ -22,7 +22,7 @@
EFPenalty.PenaltyType.Flag => "alert-secondary",
EFPenalty.PenaltyType.TempBan => "alert-secondary",
_ => "alert"
};
};
}
string ClassForProfileBackground()
@ -391,6 +391,20 @@
});
}
foreach (var interaction in Model.Interactions.Where(i => (int)ViewBag.User.Level >= ((int?)i.MinimumPermission ?? 0)))
{
menuItems.Items.Add(new SideContextMenuItem
{
Title = interaction.Name,
Tooltip = interaction.Description,
EntityId = interaction.EntityId,
Icon = interaction.DisplayMeta,
Reference = interaction.ActionPath,
Meta = System.Text.Json.JsonSerializer.Serialize(interaction.ActionMeta),
IsButton = true
});
}
}
<partial name="_SideContextMenu" for="@menuItems"></partial>

View File

@ -8,7 +8,7 @@
@foreach (var item in Model.Items)
{
<a href="@(item.IsLink ? item.Reference : "#")" class="@(item.IsLink ? "" : "profile-action")" data-action="@(item.IsLink ? "" : item.Reference)" data-action-id="@item.EntityId">
<a href="@(item.IsLink ? item.Reference : "#")" class="@(item.IsLink ? "" : "profile-action")" data-action="@(item.IsLink ? "" : item.Reference)" data-action-id="@item.EntityId" data-action-meta="@item.Meta">
<div class="@(item.IsButton ? "btn btn-block" : "")" data-title="@item.Tooltip" data-placement="left" data-toggle="@(string.IsNullOrEmpty(item.Tooltip) ? "" : "tooltip")">
<i class="@(string.IsNullOrEmpty(item.Icon) ? "" : $"oi {item.Icon}") mr-5 font-size-12"></i>
<span class="@(item.IsActive ? "text-primary" : "") text-truncate">@item.Title</span>
@ -28,7 +28,7 @@
@foreach (var item in Model.Items)
{
<div class="mt-15 mb-15">
<a href="@(item.IsLink ? item.Reference : "#")" class="@(item.IsLink ? "" : "profile-action") no-decoration" data-action="@(item.IsLink ? "" : item.Reference)" data-action-id="@item.EntityId">
<a href="@(item.IsLink ? item.Reference : "#")" class="@(item.IsLink ? "" : "profile-action") no-decoration" data-action="@(item.IsLink ? "" : item.Reference)" data-action-id="@item.EntityId" data-action-meta="@item.Meta">
<div class="btn btn-block btn-lg @(item.IsActive ? "btn-primary" : "") text-truncate" data-title="@item.Tooltip" data-toggle="@(string.IsNullOrEmpty(item.Tooltip) ? "" : "tooltip")">
<i class="@(string.IsNullOrEmpty(item.Icon) ? "" : $"oi {item.Icon}") mr-5 font-size-12"></i>
<span>@item.Title</span>

View File

@ -91,12 +91,18 @@ $(document).ready(function () {
$(document).off('click', '.profile-action');
$(document).on('click', '.profile-action', function (e) {
e.preventDefault();
const actionType = $(this).data('action');
const action = $(this).data('action');
const actionId = $(this).data('action-id');
const actionMeta = $(this).data('action-meta');
const responseDuration = $(this).data('response-duration') || 5000;
const actionIdKey = actionId === undefined ? '' : `?id=${actionId}`;
let actionKeys = actionId === undefined ? '' : `?id=${actionId}`;
if (actionMeta !== undefined) {
actionKeys = actionKeys + '&meta=' + JSON.stringify(actionMeta);
}
showLoader();
$.get(`/Action/${actionType}Form/${actionIdKey}`)
$.get(`/Action/${action}Form/${actionKeys}`)
.done(function (response) {
$('#actionModal .modal-message').fadeOut('fast')
$('#actionModal').attr('data-response-duration', responseDuration);