add support for plugin generated pages (interactions). add disallow vpn command
This commit is contained in:
parent
3295315339
commit
3367c5c22f
@ -24,7 +24,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Jint" Version="3.0.0-beta-2038" />
|
||||
<PackageReference Include="Jint" Version="3.0.0-beta-2041" />
|
||||
<PackageReference Include="MaxMind.GeoIP2" Version="5.1.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.8">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
|
@ -85,7 +85,7 @@ namespace IW4MAdmin.Application
|
||||
IEnumerable<IPlugin> plugins, IParserRegexFactory parserRegexFactory, IEnumerable<IRegisterEvent> customParserEvents,
|
||||
IEventHandler eventHandler, IScriptCommandFactory scriptCommandFactory, IDatabaseContextFactory contextFactory,
|
||||
IMetaRegistration metaRegistration, IScriptPluginServiceResolver scriptPluginServiceResolver, ClientService clientService, IServiceProvider serviceProvider,
|
||||
ChangeHistoryService changeHistoryService, ApplicationConfiguration appConfig, PenaltyService penaltyService, IAlertManager alertManager)
|
||||
ChangeHistoryService changeHistoryService, ApplicationConfiguration appConfig, PenaltyService penaltyService, IAlertManager alertManager, IInteractionRegistration interactionRegistration)
|
||||
{
|
||||
MiddlewareActionHandler = actionHandler;
|
||||
_servers = new ConcurrentBag<Server>();
|
||||
@ -115,9 +115,11 @@ namespace IW4MAdmin.Application
|
||||
_changeHistoryService = changeHistoryService;
|
||||
_appConfig = appConfig;
|
||||
Plugins = plugins;
|
||||
InteractionRegistration = interactionRegistration;
|
||||
}
|
||||
|
||||
public IEnumerable<IPlugin> Plugins { get; }
|
||||
public IInteractionRegistration InteractionRegistration { get; }
|
||||
|
||||
public async Task ExecuteEvent(GameEvent newEvent)
|
||||
{
|
||||
|
21
Application/Extensions/ScriptPluginExtensions.cs
Normal file
21
Application/Extensions/ScriptPluginExtensions.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace IW4MAdmin.Application.Extensions;
|
||||
|
||||
public static class ScriptPluginExtensions
|
||||
{
|
||||
public static IEnumerable<object> GetClientsBasicData(
|
||||
this DbSet<Data.Models.Client.EFClient> set, int[] clientIds)
|
||||
{
|
||||
return set.Where(client => clientIds.Contains(client.ClientId))
|
||||
.Select(client => new
|
||||
{
|
||||
client.ClientId,
|
||||
client.CurrentAlias,
|
||||
client.Level,
|
||||
client.NetworkId
|
||||
}).ToList();
|
||||
}
|
||||
}
|
@ -70,23 +70,11 @@ public class InteractionRegistration : IInteractionRegistration
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<IInteractionData>> GetInteractions(int? clientId = null,
|
||||
public async Task<IEnumerable<IInteractionData>> GetInteractions(string interactionPrefix = null,
|
||||
int? clientId = null,
|
||||
Reference.Game? game = null, CancellationToken token = default)
|
||||
{
|
||||
return (await Task.WhenAll(_interactions.Select(async kvp =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return await kvp.Value(clientId, game, token);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex,
|
||||
"Could not get interaction for interaction {InteractionName} and ClientId {ClientId}", kvp.Key,
|
||||
clientId);
|
||||
return null;
|
||||
}
|
||||
}))).Where(interaction => interaction is not null);
|
||||
return await GetInteractionsPrivate(interactionPrefix, clientId, game, token);
|
||||
}
|
||||
|
||||
public async Task<string> ProcessInteraction(string interactionId, int originId, int? targetId = null,
|
||||
@ -115,17 +103,40 @@ public class InteractionRegistration : IInteractionRegistration
|
||||
continue;
|
||||
}
|
||||
|
||||
return scriptPlugin.ExecuteAction<string>(interaction.ScriptAction, originId, targetId, game, meta, token);
|
||||
return scriptPlugin.ExecuteAction<string>(interaction.ScriptAction, originId, targetId, game, meta,
|
||||
token);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex,
|
||||
"Could not process interaction for interaction {InteractionName} and OriginId {ClientId}",
|
||||
"Could not process interaction for {InteractionName} and OriginId {ClientId}",
|
||||
interactionId, originId);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<IInteractionData>> GetInteractionsPrivate(string prefix = null, int? clientId = null,
|
||||
Reference.Game? game = null, CancellationToken token = default)
|
||||
{
|
||||
return (await Task.WhenAll(_interactions
|
||||
.Where(interaction => string.IsNullOrWhiteSpace(prefix) || interaction.Key.StartsWith(prefix)).Select(
|
||||
async kvp =>
|
||||
{
|
||||
try
|
||||
{
|
||||
return await kvp.Value(clientId, game, token);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex,
|
||||
"Could not get interaction for {InteractionName} and ClientId {ClientId}",
|
||||
kvp.Key,
|
||||
clientId);
|
||||
return null;
|
||||
}
|
||||
}))).Where(interaction => interaction is not null);
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using IW4MAdmin.Application.Extensions;
|
||||
using Jint.Runtime.Interop;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Serilog.Context;
|
||||
@ -112,7 +113,7 @@ namespace IW4MAdmin.Application.Misc
|
||||
}
|
||||
|
||||
_scriptEngine = new Engine(cfg =>
|
||||
cfg.AddExtensionMethods(typeof(Utilities), typeof(Enumerable), typeof(Queryable))
|
||||
cfg.AddExtensionMethods(typeof(Utilities), typeof(Enumerable), typeof(Queryable), typeof(ScriptPluginExtensions))
|
||||
.AllowClr(new[]
|
||||
{
|
||||
typeof(System.Net.Http.HttpClient).Assembly,
|
||||
|
@ -22,7 +22,7 @@ public class Plugin : IPlugin
|
||||
private static readonly string[] DisabledCommands = {nameof(PrivateMessageAdminsCommand), "PrivateMessageCommand"};
|
||||
private readonly IInteractionRegistration _interactionRegistration;
|
||||
private readonly IRemoteCommandService _remoteCommandService;
|
||||
private static readonly string MuteInteraction = nameof(MuteInteraction);
|
||||
private static readonly string MuteInteraction = "Webfront::Profile::Mute";
|
||||
|
||||
public Plugin(ILogger<Plugin> logger, IMetaServiceV2 metaService, IInteractionRegistration interactionRegistration,
|
||||
ITranslationLookup translationLookup, IRemoteCommandService remoteCommandService)
|
||||
|
@ -1,4 +1,7 @@
|
||||
let vpnExceptionIds = [];
|
||||
const vpnAllowListKey = 'Webfront::Nav::Admin::VPNAllowList';
|
||||
const vpnWhitelistKey = 'Webfront::Profile::VPNWhitelist';
|
||||
|
||||
const commands = [{
|
||||
name: 'whitelistvpn',
|
||||
description: 'whitelists a player\'s client id from VPN detection',
|
||||
@ -15,8 +18,35 @@ const commands = [{
|
||||
|
||||
gameEvent.Origin.Tell(`Successfully whitelisted ${gameEvent.Target.Name}`);
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'disallowvpn',
|
||||
description: 'disallows a player from connecting with a VPN',
|
||||
alias: 'dv',
|
||||
permission: 'SeniorAdmin',
|
||||
targetRequired: true,
|
||||
arguments: [{
|
||||
name: 'player',
|
||||
required: true
|
||||
}],
|
||||
execute: (gameEvent) => {
|
||||
vpnExceptionIds = vpnExceptionIds.filter(exception => parseInt(exception) !== parseInt(gameEvent.Target.ClientId));
|
||||
plugin.configHandler.SetValue('vpnExceptionIds', vpnExceptionIds);
|
||||
|
||||
gameEvent.Origin.Tell(`Successfully disallowed ${gameEvent.Target.Name} from connecting with VPN`);
|
||||
}
|
||||
}];
|
||||
|
||||
const getClientsData = (clientIds) => {
|
||||
const contextFactory = _serviceResolver.ResolveService('IDatabaseContextFactory');
|
||||
const context = contextFactory.CreateContext(false);
|
||||
const clientSet = context.Clients;
|
||||
const clients = clientSet.GetClientsBasicData(clientIds);
|
||||
context.Dispose();
|
||||
|
||||
return clients;
|
||||
}
|
||||
|
||||
const plugin = {
|
||||
author: 'RaidMax',
|
||||
version: 1.5,
|
||||
@ -28,7 +58,7 @@ const plugin = {
|
||||
let exempt = false;
|
||||
// prevent players that are exempt from being kicked
|
||||
vpnExceptionIds.forEach(function (id) {
|
||||
if (id == origin.ClientId) { // when loaded from the config the "id" type is not the same as the ClientId type
|
||||
if (parseInt(id) === parseInt(origin.ClientId)) {
|
||||
exempt = true;
|
||||
return false;
|
||||
}
|
||||
@ -83,33 +113,99 @@ const plugin = {
|
||||
this.logger.WriteInfo(`Loaded ${vpnExceptionIds.length} ids into whitelist`);
|
||||
|
||||
this.interactionRegistration = _serviceResolver.ResolveService('IInteractionRegistration');
|
||||
this.interactionRegistration.RegisterScriptInteraction('WhitelistVPN', this.name, (targetId, game, token) => {
|
||||
if (vpnExceptionIds.includes(targetId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// registers the profile action
|
||||
this.interactionRegistration.RegisterScriptInteraction(vpnWhitelistKey, this.name, (targetId, game, token) => {
|
||||
const helpers = importNamespace('SharedLibraryCore.Helpers');
|
||||
const interactionData = new helpers.InteractionData();
|
||||
|
||||
interactionData.EntityId = targetId;
|
||||
interactionData.Name = 'Whitelist VPN';
|
||||
interactionData.DisplayMeta = 'oi-circle-check';
|
||||
|
||||
interactionData.ActionMeta.Add('InteractionId', 'command');
|
||||
interactionData.ActionMeta.Add('Data', `whitelistvpn`);
|
||||
interactionData.ActionMeta.Add('ActionButtonLabel', 'Allow');
|
||||
interactionData.ActionMeta.Add('Name', 'Allow VPN Connection');
|
||||
interactionData.ActionMeta.Add('ShouldRefresh', true.toString());
|
||||
|
||||
interactionData.ActionPath = 'DynamicAction';
|
||||
interactionData.InteractionId = vpnWhitelistKey;
|
||||
interactionData.EntityId = targetId;
|
||||
interactionData.MinimumPermission = 3;
|
||||
interactionData.Source = this.name;
|
||||
interactionData.ActionMeta.Add('InteractionId', 'command'); // indicate we're wanting to execute a command
|
||||
interactionData.ActionMeta.Add('ShouldRefresh', true.toString()); // indicates that the page should refresh after performing the action
|
||||
|
||||
if (vpnExceptionIds.includes(targetId)) {
|
||||
interactionData.Name = _localization.LocalizationIndex['WEBFRONT_VPN_BUTTON_DISALLOW']; // text for the profile button
|
||||
interactionData.DisplayMeta = 'oi-circle-x';
|
||||
|
||||
interactionData.ActionMeta.Add('Data', `disallowvpn`); // command to execute
|
||||
interactionData.ActionMeta.Add('ActionButtonLabel', _localization.LocalizationIndex['WEBFRONT_VPN_ACTION_DISALLOW_CONFIRM']); // confirm button on the dialog
|
||||
interactionData.ActionMeta.Add('Name', _localization.LocalizationIndex['WEBFRONT_VPN_ACTION_DISALLOW_TITLE']); // title on the confirm dialog
|
||||
} else {
|
||||
interactionData.Name = _localization.LocalizationIndex['WEBFRONT_VPN_ACTION_ALLOW']; // text for the profile button
|
||||
interactionData.DisplayMeta = 'oi-circle-check';
|
||||
|
||||
interactionData.ActionMeta.Add('Data', `whitelistvpn`); // command to execute
|
||||
interactionData.ActionMeta.Add('ActionButtonLabel', _localization.LocalizationIndex['WEBFRONT_VPN_ACTION_ALLOW_CONFIRM']); // confirm button on the dialog
|
||||
interactionData.ActionMeta.Add('Name', _localization.LocalizationIndex['WEBFRONT_VPN_ACTION_ALLOW_TITLE']); // title on the confirm dialog
|
||||
}
|
||||
|
||||
return interactionData;
|
||||
});
|
||||
|
||||
// registers the navigation/page
|
||||
this.interactionRegistration.RegisterScriptInteraction(vpnAllowListKey, this.name, (targetId, game, token) => {
|
||||
|
||||
const helpers = importNamespace('SharedLibraryCore.Helpers');
|
||||
const interactionData = new helpers.InteractionData();
|
||||
|
||||
interactionData.Name = _localization.LocalizationIndex['WEBFRONT_NAV_VPN_TITLE']; // navigation link name
|
||||
interactionData.Description = _localization.LocalizationIndex['WEBFRONT_NAV_VPN_DESC']; // alt and title
|
||||
interactionData.DisplayMeta = 'oi-circle-check'; // nav icon
|
||||
interactionData.InteractionId = vpnAllowListKey;
|
||||
interactionData.MinimumPermission = 3; // moderator
|
||||
interactionData.InteractionType = 2; // 1 is RawContent for apis etc..., 2 is
|
||||
interactionData.Source = this.name;
|
||||
|
||||
interactionData.ScriptAction = (sourceId, targetId, game, meta, token) => {
|
||||
const clientsData = getClientsData(vpnExceptionIds);
|
||||
|
||||
let table = '<table class="table bg-dark-dm bg-light-lm">';
|
||||
|
||||
const disallowInteraction = {
|
||||
InteractionId: 'command',
|
||||
Data: 'disallowvpn',
|
||||
ActionButtonLabel: _localization.LocalizationIndex['WEBFRONT_VPN_ACTION_DISALLOW_CONFIRM'],
|
||||
Name: _localization.LocalizationIndex['WEBFRONT_VPN_ACTION_DISALLOW_TITLE']
|
||||
};
|
||||
|
||||
if (clientsData.length === 0)
|
||||
{
|
||||
table += `<tr><td>No players are whitelisted.</td></tr>`
|
||||
}
|
||||
|
||||
clientsData.forEach(client => {
|
||||
table += `<tr>
|
||||
<td>
|
||||
<a href="/Client/Profile/${client.ClientId}" class="level-color-${client.Level.toLowerCase()} no-decoration">${client.CurrentAlias.Name.StripColors()}</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="#" class="profile-action no-decoration float-right" data-action="DynamicAction" data-action-id="${client.ClientId}"
|
||||
data-action-meta="${encodeURI(JSON.stringify(disallowInteraction))}">
|
||||
<div class="btn">
|
||||
<i class="oi oi-circle-x mr-5 font-size-12"></i>
|
||||
<span class="text-truncate">${_localization.LocalizationIndex['WEBFRONT_VPN_BUTTON_DISALLOW']}</span>
|
||||
</div>
|
||||
</a>
|
||||
</td>
|
||||
</tr>`;
|
||||
});
|
||||
|
||||
table += '</table>';
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
return interactionData;
|
||||
});
|
||||
},
|
||||
|
||||
onUnloadAsync: function () {
|
||||
this.interactionRegistration.UnregisterInteraction('WhitelistVPN');
|
||||
this.interactionRegistration.UnregisterInteraction(vpnWhitelistKey);
|
||||
this.interactionRegistration.UnregisterInteraction(vpnAllowListKey);
|
||||
},
|
||||
|
||||
onTickAsync: function (server) {
|
||||
|
@ -19,6 +19,7 @@ namespace SharedLibraryCore
|
||||
{
|
||||
public class BaseController : Controller
|
||||
{
|
||||
protected readonly IInteractionRegistration InteractionRegistration;
|
||||
protected readonly IAlertManager AlertManager;
|
||||
|
||||
/// <summary>
|
||||
@ -41,6 +42,7 @@ namespace SharedLibraryCore
|
||||
|
||||
public BaseController(IManager manager)
|
||||
{
|
||||
InteractionRegistration = manager.InteractionRegistration;
|
||||
AlertManager = manager.AlertManager;
|
||||
Manager = manager;
|
||||
Localization = Utilities.CurrentLocalization.LocalizationIndex;
|
||||
@ -71,9 +73,7 @@ namespace SharedLibraryCore
|
||||
CurrentAlias = new EFAlias { Name = "Webfront Guest" }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
protected async Task SignInAsync(ClaimsPrincipal claimsPrinciple)
|
||||
{
|
||||
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, claimsPrinciple,
|
||||
@ -86,7 +86,7 @@ namespace SharedLibraryCore
|
||||
});
|
||||
}
|
||||
|
||||
public override void OnActionExecuting(ActionExecutingContext context)
|
||||
public override async void OnActionExecuting(ActionExecutingContext context)
|
||||
{
|
||||
if (!HttpContext.Connection.RemoteIpAddress.GetAddressBytes().SequenceEqual(LocalHost))
|
||||
{
|
||||
@ -154,6 +154,7 @@ namespace SharedLibraryCore
|
||||
&& !communityName.Contains("IW4MAdmin")
|
||||
&& AppConfig.CommunityInformation.IsEnabled;
|
||||
|
||||
ViewBag.Interactions = await InteractionRegistration.GetInteractions("Webfront::Nav");
|
||||
ViewBag.Authorized = Authorized;
|
||||
ViewBag.Url = AppConfig.WebfrontUrl;
|
||||
ViewBag.User = Client;
|
||||
|
@ -10,6 +10,8 @@ namespace SharedLibraryCore.Helpers;
|
||||
public class InteractionData : IInteractionData
|
||||
{
|
||||
public int? EntityId { get; set; }
|
||||
public string InteractionId { get; set; }
|
||||
public InteractionType InteractionType { get; set; }
|
||||
public bool Enabled { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Description { get; set; }
|
||||
|
@ -8,6 +8,8 @@ namespace SharedLibraryCore.Interfaces;
|
||||
public interface IInteractionData
|
||||
{
|
||||
int? EntityId { get; }
|
||||
string InteractionId { get; }
|
||||
InteractionType InteractionType { get; }
|
||||
bool Enabled { get; }
|
||||
string Name { get; }
|
||||
string Description { get; }
|
||||
@ -22,3 +24,10 @@ public interface IInteractionData
|
||||
InteractionCallback Action { get; }
|
||||
Delegate ScriptAction { get; }
|
||||
}
|
||||
|
||||
public enum InteractionType
|
||||
{
|
||||
ActionButton,
|
||||
RawContent,
|
||||
TemplateContent
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ public interface IInteractionRegistration
|
||||
void RegisterScriptInteraction(string interactionName, string source, Delegate interactionRegistration);
|
||||
void RegisterInteraction(string interactionName, Func<int?, Reference.Game?, CancellationToken, Task<IInteractionData>> interactionRegistration);
|
||||
void UnregisterInteraction(string interactionName);
|
||||
Task<IEnumerable<IInteractionData>> GetInteractions(int? clientId = null,
|
||||
Task<IEnumerable<IInteractionData>> GetInteractions(string interactionPrefix = null, int? clientId = null,
|
||||
Reference.Game? game = null, CancellationToken token = default);
|
||||
Task<string> ProcessInteraction(string interactionId, int originId, int? targetId = null, Reference.Game? game = null, IDictionary<string, string> meta = null, CancellationToken token = default);
|
||||
}
|
||||
|
@ -105,5 +105,6 @@ namespace SharedLibraryCore.Interfaces
|
||||
event EventHandler<GameEvent> OnGameEventExecuted;
|
||||
|
||||
IAlertManager AlertManager { get; }
|
||||
IInteractionRegistration InteractionRegistration { get; }
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ namespace WebfrontCore.Controllers
|
||||
private readonly IMetaServiceV2 _metaService;
|
||||
private readonly IInteractionRegistration _interactionRegistration;
|
||||
private readonly IRemoteCommandService _remoteCommandService;
|
||||
private readonly ITranslationLookup _translationLookup;
|
||||
private readonly string _banCommandName;
|
||||
private readonly string _tempbanCommandName;
|
||||
private readonly string _unbanCommandName;
|
||||
@ -41,12 +42,14 @@ namespace WebfrontCore.Controllers
|
||||
|
||||
public ActionController(IManager manager, IEnumerable<IManagerCommand> registeredCommands,
|
||||
ApplicationConfiguration appConfig, IMetaServiceV2 metaService,
|
||||
IInteractionRegistration interactionRegistration, IRemoteCommandService remoteCommandService) : base(manager)
|
||||
IInteractionRegistration interactionRegistration, IRemoteCommandService remoteCommandService,
|
||||
ITranslationLookup translationLookup) : base(manager)
|
||||
{
|
||||
_appConfig = appConfig;
|
||||
_metaService = metaService;
|
||||
_interactionRegistration = interactionRegistration;
|
||||
_remoteCommandService = remoteCommandService;
|
||||
_translationLookup = translationLookup;
|
||||
|
||||
foreach (var cmd in registeredCommands)
|
||||
{
|
||||
@ -94,7 +97,18 @@ namespace WebfrontCore.Controllers
|
||||
|
||||
public IActionResult DynamicActionForm(int? id, string meta)
|
||||
{
|
||||
var metaDict = JsonSerializer.Deserialize<Dictionary<string, string>>(meta);
|
||||
if (Client.ClientId < 1)
|
||||
{
|
||||
return Ok(new[]
|
||||
{
|
||||
new CommandResponseInfo
|
||||
{
|
||||
Response = _translationLookup["SERVER_COMMANDS_INTERCEPTED"]
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var metaDict = JsonSerializer.Deserialize<Dictionary<string, string>>(meta.TrimEnd('"').TrimStart('"'));
|
||||
|
||||
if (metaDict is null)
|
||||
{
|
||||
@ -170,6 +184,17 @@ namespace WebfrontCore.Controllers
|
||||
|
||||
public async Task<IActionResult> DynamicActionAsync(CancellationToken token = default)
|
||||
{
|
||||
if (Client.ClientId < 1)
|
||||
{
|
||||
return Ok(new[]
|
||||
{
|
||||
new CommandResponseInfo
|
||||
{
|
||||
Response = _translationLookup["SERVER_COMMANDS_INTERCEPTED"]
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
HttpContext.Request.Query.TryGetValue("InteractionId", out var interactionId);
|
||||
HttpContext.Request.Query.TryGetValue("CustomInputKeys", out var inputKeys);
|
||||
HttpContext.Request.Query.TryGetValue("Data", out var data);
|
||||
|
@ -77,7 +77,8 @@ namespace WebfrontCore.Controllers
|
||||
note.OriginEntityName = await _clientService.GetClientNameById(note.OriginEntityId);
|
||||
}
|
||||
|
||||
var interactions = await _interactionRegistration.GetInteractions(id, client.GameName, token);
|
||||
var interactions =
|
||||
await _interactionRegistration.GetInteractions("Webfront::Profile", 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)
|
||||
|
37
WebfrontCore/Controllers/InteractionController.cs
Normal file
37
WebfrontCore/Controllers/InteractionController.cs
Normal file
@ -0,0 +1,37 @@
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using SharedLibraryCore;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
|
||||
namespace WebfrontCore.Controllers;
|
||||
|
||||
public class InteractionController : BaseController
|
||||
{
|
||||
private readonly IInteractionRegistration _interactionRegistration;
|
||||
|
||||
public InteractionController(IManager manager, IInteractionRegistration interactionRegistration) : base(manager)
|
||||
{
|
||||
_interactionRegistration = interactionRegistration;
|
||||
}
|
||||
|
||||
[HttpGet("[controller]/[action]/{interactionName}")]
|
||||
public async Task<IActionResult> Render([FromRoute]string interactionName, CancellationToken token)
|
||||
{
|
||||
var interactionData = (await _interactionRegistration.GetInteractions(interactionName, token: token)).FirstOrDefault();
|
||||
|
||||
if (interactionData is null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
ViewBag.Title = interactionData.Description;
|
||||
|
||||
var result = await _interactionRegistration.ProcessInteraction(interactionName, Client.ClientId, token: token);
|
||||
|
||||
return interactionData.InteractionType == InteractionType.TemplateContent
|
||||
? View("Render", result ?? "")
|
||||
: Ok(result);
|
||||
}
|
||||
}
|
8
WebfrontCore/Views/Interaction/Render.cshtml
Normal file
8
WebfrontCore/Views/Interaction/Render.cshtml
Normal file
@ -0,0 +1,8 @@
|
||||
@model string
|
||||
|
||||
<div class="content text-wrap mt-20">
|
||||
<h2 class="content-title">
|
||||
<color-code value="@ViewBag.Title"></color-code>
|
||||
</h2>
|
||||
@Html.Raw(Model)
|
||||
</div>
|
@ -1,6 +1,7 @@
|
||||
@using SharedLibraryCore.Configuration
|
||||
@using SharedLibraryCore.Dtos
|
||||
@using Data.Models.Client
|
||||
@using SharedLibraryCore.Interfaces
|
||||
|
||||
<!-- left side navigation -->
|
||||
<div class="sidebar-overlay" onclick="halfmoon.toggleSidebar()"></div>
|
||||
@ -43,6 +44,23 @@
|
||||
<span class="name">@ViewBag.Localization["WEBFRONT_NAV_HELP"]</span>
|
||||
</a>
|
||||
</has-permission>
|
||||
|
||||
@foreach (IInteractionData interactionData in ViewBag.Interactions)
|
||||
{
|
||||
if (!interactionData.InteractionId.StartsWith("Webfront::Nav::Main"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ViewBag.User.Level >= interactionData.MinimumPermission)
|
||||
{
|
||||
<a asp-controller="Interaction" asp-action="Render" asp-route-interactionName="@interactionData.InteractionId" class="sidebar-link">
|
||||
<i class="oi @interactionData.DisplayMeta mr-5"></i>
|
||||
<span class="name">@interactionData.Name</span>
|
||||
</a>
|
||||
}
|
||||
}
|
||||
|
||||
<!-- profile -->
|
||||
<has-permission entity="ProfilePage" required-permission="Read">
|
||||
<a asp-controller="Client" asp-action="Profile" asp-route-id="@ViewBag.User.ClientId" class="sidebar-link">
|
||||
@ -104,6 +122,23 @@
|
||||
</div>
|
||||
</a>
|
||||
}
|
||||
|
||||
@foreach (IInteractionData interactionData in ViewBag.Interactions)
|
||||
{
|
||||
if (!interactionData.InteractionId.StartsWith("Webfront::Nav::Social"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ViewBag.User.Level >= interactionData.MinimumPermission)
|
||||
{
|
||||
<a asp-controller="Interaction" asp-action="Render" asp-route-interactionName="@interactionData.InteractionId" class="sidebar-link">
|
||||
<i class="oi @interactionData.DisplayMeta mr-5"></i>
|
||||
<span class="name">@interactionData.Name</span>
|
||||
</a>
|
||||
}
|
||||
}
|
||||
|
||||
<br/>
|
||||
|
||||
<!-- admin -->
|
||||
@ -142,6 +177,22 @@
|
||||
<span class="name">@ViewBag.Localization["WEBFRONT_ACTION_RECENT_CLIENTS"]</span>
|
||||
</a>
|
||||
</has-permission>
|
||||
|
||||
@foreach (IInteractionData interactionData in ViewBag.Interactions)
|
||||
{
|
||||
if (!interactionData.InteractionId.StartsWith("Webfront::Nav::Admin"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ViewBag.User.Level >= interactionData.MinimumPermission)
|
||||
{
|
||||
<a asp-controller="Interaction" asp-action="Render" asp-route-interactionName="@interactionData.InteractionId" class="sidebar-link">
|
||||
<i class="oi @interactionData.DisplayMeta mr-5"></i>
|
||||
<span class="name">@interactionData.Name</span>
|
||||
</a>
|
||||
}
|
||||
}
|
||||
|
||||
@if (ViewBag.Authorized)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user