hide chat for password protected servers for issue #162

This commit is contained in:
RaidMax 2020-08-20 10:38:11 -05:00
parent 4735864113
commit c783a04a52
39 changed files with 1171 additions and 188 deletions

View File

@ -541,14 +541,18 @@ namespace IW4MAdmin
.First(_qm => _qm.Game == GameName) .First(_qm => _qm.Game == GameName)
.Messages[E.Data.Substring(1)]; .Messages[E.Data.Substring(1)];
} }
catch { } catch
{
message = E.Data.Substring(1);
}
} }
ChatHistory.Add(new ChatInfo() ChatHistory.Add(new ChatInfo()
{ {
Name = E.Origin.Name, Name = E.Origin.Name,
Message = message, Message = message,
Time = DateTime.UtcNow Time = DateTime.UtcNow,
IsHidden = !string.IsNullOrEmpty(GamePassword)
}); });
} }
} }
@ -982,6 +986,7 @@ namespace IW4MAdmin
var logfile = await this.GetMappedDvarValueOrDefaultAsync<string>("g_log"); var logfile = await this.GetMappedDvarValueOrDefaultAsync<string>("g_log");
var logsync = await this.GetMappedDvarValueOrDefaultAsync<int>("g_logsync"); var logsync = await this.GetMappedDvarValueOrDefaultAsync<int>("g_logsync");
var ip = await this.GetMappedDvarValueOrDefaultAsync<string>("net_ip"); var ip = await this.GetMappedDvarValueOrDefaultAsync<string>("net_ip");
var gamePassword = await this.GetMappedDvarValueOrDefaultAsync("g_password", overrideDefault: "");
if (Manager.GetApplicationSettings().Configuration().EnableCustomSayName) if (Manager.GetApplicationSettings().Configuration().EnableCustomSayName)
{ {
@ -1015,6 +1020,7 @@ namespace IW4MAdmin
this.FSGame = game.Value; this.FSGame = game.Value;
this.Gametype = gametype; this.Gametype = gametype;
this.IP = ip.Value == "localhost" ? ServerConfig.IPAddress : ip.Value ?? ServerConfig.IPAddress; this.IP = ip.Value == "localhost" ? ServerConfig.IPAddress : ip.Value ?? ServerConfig.IPAddress;
this.GamePassword = gamePassword.Value;
UpdateMap(mapname); UpdateMap(mapname);
if (RconParser.CanGenerateLogPath) if (RconParser.CanGenerateLogPath)

View File

@ -10,7 +10,6 @@ using RestEase;
using SharedLibraryCore; using SharedLibraryCore;
using SharedLibraryCore.Configuration; using SharedLibraryCore.Configuration;
using SharedLibraryCore.Database.Models; using SharedLibraryCore.Database.Models;
using SharedLibraryCore.Dtos.Meta.Requests;
using SharedLibraryCore.Dtos.Meta.Responses; using SharedLibraryCore.Dtos.Meta.Responses;
using SharedLibraryCore.Exceptions; using SharedLibraryCore.Exceptions;
using SharedLibraryCore.Helpers; using SharedLibraryCore.Helpers;
@ -18,6 +17,8 @@ using SharedLibraryCore.Interfaces;
using SharedLibraryCore.QueryHelper; using SharedLibraryCore.QueryHelper;
using SharedLibraryCore.Repositories; using SharedLibraryCore.Repositories;
using SharedLibraryCore.Services; using SharedLibraryCore.Services;
using Stats.Dtos;
using StatsWeb;
using System; using System;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -251,6 +252,7 @@ namespace IW4MAdmin.Application
.AddSingleton<IResourceQueryHelper<ClientPaginationRequest, ReceivedPenaltyResponse>, ReceivedPenaltyResourceQueryHelper>() .AddSingleton<IResourceQueryHelper<ClientPaginationRequest, ReceivedPenaltyResponse>, ReceivedPenaltyResourceQueryHelper>()
.AddSingleton<IResourceQueryHelper<ClientPaginationRequest, AdministeredPenaltyResponse>, AdministeredPenaltyResourceQueryHelper>() .AddSingleton<IResourceQueryHelper<ClientPaginationRequest, AdministeredPenaltyResponse>, AdministeredPenaltyResourceQueryHelper>()
.AddSingleton<IResourceQueryHelper<ClientPaginationRequest, UpdatedAliasResponse>, UpdatedAliasResourceQueryHelper>() .AddSingleton<IResourceQueryHelper<ClientPaginationRequest, UpdatedAliasResponse>, UpdatedAliasResourceQueryHelper>()
.AddSingleton<IResourceQueryHelper<ChatSearchQuery, MessageResponse>, ChatResourceQueryHelper>()
.AddTransient<IParserPatternMatcher, ParserPatternMatcher>() .AddTransient<IParserPatternMatcher, ParserPatternMatcher>()
.AddSingleton(_serviceProvider => .AddSingleton(_serviceProvider =>
{ {

View File

@ -10,7 +10,7 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.SyndicationFeed.ReaderWriter" Version="1.0.2" /> <PackageReference Include="Microsoft.SyndicationFeed.ReaderWriter" Version="1.0.2" />
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.4.7" PrivateAssets="All" /> <PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.4.9" PrivateAssets="All" />
</ItemGroup> </ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent"> <Target Name="PostBuild" AfterTargets="PostBuildEvent">

View File

@ -10,7 +10,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.4.7" PrivateAssets="All" /> <PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.4.9" PrivateAssets="All" />
</ItemGroup> </ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent"> <Target Name="PostBuild" AfterTargets="PostBuildEvent">

View File

@ -16,7 +16,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.4.7" PrivateAssets="All" /> <PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.4.9" PrivateAssets="All" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -23,7 +23,7 @@
</Target> </Target>
<ItemGroup> <ItemGroup>
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.4.7" PrivateAssets="All" /> <PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.4.9" PrivateAssets="All" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -16,7 +16,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.4.7" PrivateAssets="All" /> <PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.4.9" PrivateAssets="All" />
</ItemGroup> </ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent"> <Target Name="PostBuild" AfterTargets="PostBuildEvent">

View File

@ -1,8 +1,7 @@
using SharedLibraryCore.Dtos; using SharedLibraryCore.QueryHelper;
using SharedLibraryCore.QueryHelper;
using System; using System;
namespace StatsWeb.Dtos namespace Stats.Dtos
{ {
public class ChatSearchQuery : ClientPaginationRequest public class ChatSearchQuery : ClientPaginationRequest
{ {
@ -30,5 +29,10 @@ namespace StatsWeb.Dtos
/// only look for messages sent before this date0 /// only look for messages sent before this date0
/// </summary> /// </summary>
public DateTime SentBefore { get; set; } = DateTime.UtcNow; public DateTime SentBefore { get; set; } = DateTime.UtcNow;
/// <summary>
/// indicates if the chat is on the meta page
/// </summary>
public bool IsProfileMeta { get; set; }
} }
} }

View File

@ -248,6 +248,10 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
ctx.Entry(server).Property(_prop => _prop.HostName).IsModified = true; ctx.Entry(server).Property(_prop => _prop.HostName).IsModified = true;
ctx.SaveChanges(); ctx.SaveChanges();
} }
ctx.Entry(server).Property(_prop => _prop.IsPasswordProtected).IsModified = true;
server.IsPasswordProtected = !string.IsNullOrEmpty(sv.GamePassword);
ctx.SaveChanges();
} }
// check to see if the stats have ever been initialized // check to see if the stats have ever been initialized

View File

@ -16,5 +16,6 @@ namespace IW4MAdmin.Plugins.Stats.Models
public string EndPoint { get; set; } public string EndPoint { get; set; }
public Game? GameName { get; set; } public Game? GameName { get; set; }
public string HostName { get; set; } public string HostName { get; set; }
public bool IsPasswordProtected { get; set; }
} }
} }

View File

@ -5,12 +5,11 @@ using Microsoft.EntityFrameworkCore;
using SharedLibraryCore; using SharedLibraryCore;
using SharedLibraryCore.Database; using SharedLibraryCore.Database;
using SharedLibraryCore.Database.Models; using SharedLibraryCore.Database.Models;
using SharedLibraryCore.Dtos;
using SharedLibraryCore.Dtos.Meta.Responses; using SharedLibraryCore.Dtos.Meta.Responses;
using SharedLibraryCore.Helpers; using SharedLibraryCore.Helpers;
using SharedLibraryCore.Interfaces; using SharedLibraryCore.Interfaces;
using SharedLibraryCore.QueryHelper; using SharedLibraryCore.QueryHelper;
using SharedLibraryCore.Services; using Stats.Dtos;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -36,14 +35,16 @@ namespace IW4MAdmin.Plugins.Stats
private readonly IDatabaseContextFactory _databaseContextFactory; private readonly IDatabaseContextFactory _databaseContextFactory;
private readonly ITranslationLookup _translationLookup; private readonly ITranslationLookup _translationLookup;
private readonly IMetaService _metaService; private readonly IMetaService _metaService;
private readonly IResourceQueryHelper<ChatSearchQuery, MessageResponse> _chatQueryHelper;
public Plugin(IConfigurationHandlerFactory configurationHandlerFactory, IDatabaseContextFactory databaseContextFactory, public Plugin(IConfigurationHandlerFactory configurationHandlerFactory, IDatabaseContextFactory databaseContextFactory,
ITranslationLookup translationLookup, IMetaService metaService) ITranslationLookup translationLookup, IMetaService metaService, IResourceQueryHelper<ChatSearchQuery, MessageResponse> chatQueryHelper)
{ {
Config = configurationHandlerFactory.GetConfigurationHandler<StatsConfiguration>("StatsPluginSettings"); Config = configurationHandlerFactory.GetConfigurationHandler<StatsConfiguration>("StatsPluginSettings");
_databaseContextFactory = databaseContextFactory; _databaseContextFactory = databaseContextFactory;
_translationLookup = translationLookup; _translationLookup = translationLookup;
_metaService = metaService; _metaService = metaService;
_chatQueryHelper = chatQueryHelper;
} }
public async Task OnEventAsync(GameEvent E, Server S) public async Task OnEventAsync(GameEvent E, Server S)
@ -199,7 +200,7 @@ namespace IW4MAdmin.Plugins.Stats
using (var ctx = _databaseContextFactory.CreateContext(enableTracking: false)) using (var ctx = _databaseContextFactory.CreateContext(enableTracking: false))
{ {
clientStats = await ctx.Set<EFClientStatistics>().Where(c => c.ClientId == request.ClientId).ToListAsync(); clientStats = await ctx.Set<EFClientStatistics>().Where(c => c.ClientId == request.ClientId).ToListAsync();
messageCount = await ctx.Set<EFClientMessage>().CountAsync(_message => _message.ClientId == request.ClientId); messageCount = await ctx.Set<EFClientMessage>().CountAsync(_message => _message.ClientId == request.ClientId);
} }
int kills = clientStats.Sum(c => c.Kills); int kills = clientStats.Sum(c => c.Kills);
@ -392,45 +393,16 @@ namespace IW4MAdmin.Plugins.Stats
async Task<IEnumerable<MessageResponse>> getMessages(ClientPaginationRequest request) async Task<IEnumerable<MessageResponse>> getMessages(ClientPaginationRequest request)
{ {
List<MessageResponse> messageMeta; var query = new ChatSearchQuery()
using (var ctx = _databaseContextFactory.CreateContext(enableTracking: false))
{ {
var messages = ctx.Set<EFClientMessage>() ClientId = request.ClientId,
.Where(m => m.ClientId == request.ClientId) Before = request.Before,
.Where(_message => _message.TimeSent < request.Before) SentBefore = request.Before ?? DateTime.UtcNow,
.OrderByDescending(_message => _message.TimeSent) Count = request.Count,
.Take(request.Count); IsProfileMeta = true
};
messageMeta = await messages.Select(m => new MessageResponse() return (await _chatQueryHelper.QueryResource(query)).Results;
{
// todo: game name
Message = m.Message,
When = m.TimeSent,
ServerId = m.ServerId,
Type = MetaType.ChatMessage
}).ToListAsync();
foreach (var meta in messageMeta)
{
if ((meta.Message).IsQuickMessage())
{
try
{
var quickMessages = ServerManager.GetApplicationSettings().Configuration()
.QuickMessages
.First(/*_qm => _qm.Game == meta.GameName*/);
meta.Message = quickMessages.Messages[(meta.Message as string).Substring(1)];
meta.Type = MetaType.QuickMessage;
}
catch
{
}
}
}
}
return messageMeta;
} }
if (Config.Configuration().EnableAntiCheat) if (Config.Configuration().EnableAntiCheat)

View File

@ -16,7 +16,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.4.7" PrivateAssets="All" /> <PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.4.9" PrivateAssets="All" />
</ItemGroup> </ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent"> <Target Name="PostBuild" AfterTargets="PostBuildEvent">

View File

@ -1,9 +1,13 @@
using IW4MAdmin.Plugins.Stats.Models; using IW4MAdmin.Plugins.Stats.Models;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using SharedLibraryCore;
using SharedLibraryCore.Configuration;
using SharedLibraryCore.Dtos.Meta.Responses;
using SharedLibraryCore.Helpers; using SharedLibraryCore.Helpers;
using SharedLibraryCore.Interfaces; using SharedLibraryCore.Interfaces;
using StatsWeb.Dtos; using Stats.Dtos;
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -12,31 +16,44 @@ namespace StatsWeb
/// <summary> /// <summary>
/// implementation of IResourceQueryHelper /// implementation of IResourceQueryHelper
/// </summary> /// </summary>
public class ChatResourceQueryHelper : IResourceQueryHelper<ChatSearchQuery, ChatSearchResult> public class ChatResourceQueryHelper : IResourceQueryHelper<ChatSearchQuery, MessageResponse>
{ {
private readonly IDatabaseContextFactory _contextFactory; private readonly IDatabaseContextFactory _contextFactory;
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly ApplicationConfiguration _appConfig;
private List<EFServer> serverCache;
public ChatResourceQueryHelper(ILogger logger, IDatabaseContextFactory contextFactory) public ChatResourceQueryHelper(ILogger logger, IDatabaseContextFactory contextFactory, ApplicationConfiguration appConfig)
{ {
_contextFactory = contextFactory; _contextFactory = contextFactory;
_logger = logger; _logger = logger;
_appConfig = appConfig;
} }
/// <inheritdoc/> /// <inheritdoc/>
public async Task<ResourceQueryHelperResult<ChatSearchResult>> QueryResource(ChatSearchQuery query) public async Task<ResourceQueryHelperResult<MessageResponse>> QueryResource(ChatSearchQuery query)
{ {
if (query == null) if (query == null)
{ {
throw new ArgumentException("Query must be specified"); throw new ArgumentException("Query must be specified");
} }
var result = new ResourceQueryHelperResult<ChatSearchResult>(); var result = new ResourceQueryHelperResult<MessageResponse>();
using var context = _contextFactory.CreateContext(enableTracking: false); using var context = _contextFactory.CreateContext(enableTracking: false);
if (serverCache == null)
{
serverCache = await context.Set<EFServer>().ToListAsync();
}
if (int.TryParse(query.ServerId, out int serverId))
{
query.ServerId = serverCache.FirstOrDefault(_server => _server.ServerId == serverId)?.EndPoint ?? query.ServerId;
}
var iqMessages = context.Set<EFClientMessage>() var iqMessages = context.Set<EFClientMessage>()
.Where(_message => _message.TimeSent >= query.SentAfter) .Where(_message => _message.TimeSent >= query.SentAfter)
.Where(_message => _message.TimeSent <= query.SentBefore); .Where(_message => _message.TimeSent < query.SentBefore);
if (query.ClientId != null) if (query.ClientId != null)
{ {
@ -50,27 +67,29 @@ namespace StatsWeb
if (!string.IsNullOrEmpty(query.MessageContains)) if (!string.IsNullOrEmpty(query.MessageContains))
{ {
iqMessages = iqMessages.Where(_message => EF.Functions.Like(_message.Message, $"%{query.MessageContains}%")); iqMessages = iqMessages.Where(_message => EF.Functions.Like(_message.Message.ToLower(), $"%{query.MessageContains.ToLower()}%"));
} }
var iqResponse = iqMessages var iqResponse = iqMessages
.Select(_message => new ChatSearchResult .Select(_message => new MessageResponse
{ {
ClientId = _message.ClientId, ClientId = _message.ClientId,
ClientName = _message.Client.CurrentAlias.Name, ClientName = query.IsProfileMeta ? "" : _message.Client.CurrentAlias.Name,
Date = _message.TimeSent, ServerId = _message.ServerId,
When = _message.TimeSent,
Message = _message.Message, Message = _message.Message,
ServerName = _message.Server.HostName ServerName = query.IsProfileMeta ? "" : _message.Server.HostName,
GameName = _message.Server.GameName == null ? Server.Game.IW4 : _message.Server.GameName.Value
}); });
if (query.Direction == SharedLibraryCore.Dtos.SortDirection.Descending) if (query.Direction == SharedLibraryCore.Dtos.SortDirection.Descending)
{ {
iqResponse = iqResponse.OrderByDescending(_message => _message.Date); iqResponse = iqResponse.OrderByDescending(_message => _message.When);
} }
else else
{ {
iqResponse = iqResponse.OrderBy(_message => _message.Date); iqResponse = iqResponse.OrderBy(_message => _message.When);
} }
var resultList = await iqResponse var resultList = await iqResponse
@ -78,6 +97,27 @@ namespace StatsWeb
.Take(query.Count) .Take(query.Count)
.ToListAsync(); .ToListAsync();
foreach (var message in resultList)
{
message.IsHidden = serverCache.Any(server => server.ServerId == message.ServerId && server.IsPasswordProtected);
if (message.Message.IsQuickMessage())
{
try
{
var quickMessages = _appConfig
.QuickMessages
.First(_qm => _qm.Game == message.GameName);
message.Message = quickMessages.Messages[message.Message.Substring(1)];
message.IsQuickMessage = true;
}
catch
{
message.Message = message.Message.Substring(1);
}
}
}
result.TotalResultCount = await iqResponse.CountAsync(); result.TotalResultCount = await iqResponse.CountAsync();
result.Results = resultList; result.Results = resultList;
result.RetrievedResultCount = resultList.Count; result.RetrievedResultCount = resultList.Count;

View File

@ -5,8 +5,9 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using SharedLibraryCore; using SharedLibraryCore;
using SharedLibraryCore.Dtos; using SharedLibraryCore.Dtos;
using SharedLibraryCore.Dtos.Meta.Responses;
using SharedLibraryCore.Interfaces; using SharedLibraryCore.Interfaces;
using StatsWeb.Dtos; using Stats.Dtos;
using StatsWeb.Extensions; using StatsWeb.Extensions;
using System; using System;
using System.Linq; using System.Linq;
@ -18,10 +19,10 @@ namespace IW4MAdmin.Plugins.Web.StatsWeb.Controllers
{ {
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IManager _manager; private readonly IManager _manager;
private readonly IResourceQueryHelper<ChatSearchQuery, ChatSearchResult> _chatResourceQueryHelper; private readonly IResourceQueryHelper<ChatSearchQuery, MessageResponse> _chatResourceQueryHelper;
private readonly ITranslationLookup _translationLookup; private readonly ITranslationLookup _translationLookup;
public StatsController(ILogger logger, IManager manager, IResourceQueryHelper<ChatSearchQuery, ChatSearchResult> resourceQueryHelper, public StatsController(ILogger logger, IManager manager, IResourceQueryHelper<ChatSearchQuery, MessageResponse> resourceQueryHelper,
ITranslationLookup translationLookup) : base(manager) ITranslationLookup translationLookup) : base(manager)
{ {
_logger = logger; _logger = logger;
@ -72,51 +73,24 @@ namespace IW4MAdmin.Plugins.Web.StatsWeb.Controllers
} }
[HttpGet] [HttpGet]
public async Task<IActionResult> GetMessageAsync(int serverId, long when) public async Task<IActionResult> GetMessageAsync(string serverId, long when)
{ {
var whenTime = DateTime.FromFileTimeUtc(when); var whenTime = DateTime.FromFileTimeUtc(when);
var whenUpper = whenTime.AddMinutes(5); var whenUpper = whenTime.AddMinutes(5);
var whenLower = whenTime.AddMinutes(-5); var whenLower = whenTime.AddMinutes(-5);
using (var ctx = new SharedLibraryCore.Database.DatabaseContext(true)) var messages = await _chatResourceQueryHelper.QueryResource(new ChatSearchQuery()
{ {
var iqMessages = from message in ctx.Set<Stats.Models.EFClientMessage>() ServerId = serverId,
where message.ServerId == serverId SentBefore = whenUpper,
where message.TimeSent >= whenLower SentAfter = whenLower
where message.TimeSent <= whenUpper });
select new ChatInfo()
{
ClientId = message.ClientId,
Message = message.Message,
Name = message.Client.CurrentAlias.Name,
Time = message.TimeSent,
ServerGame = message.Server.GameName ?? Server.Game.IW4
};
var messages = await iqMessages.ToListAsync(); return View("_MessageContext", messages.Results);
foreach (var message in messages)
{
if (message.Message.IsQuickMessage())
{
try
{
var quickMessages = _manager.GetApplicationSettings().Configuration()
.QuickMessages
.First(_qm => _qm.Game == message.ServerGame);
message.Message = quickMessages.Messages[message.Message.Substring(1)];
message.IsQuickMessage = true;
}
catch { }
}
}
return View("_MessageContext", messages);
}
} }
[HttpGet("Message/Find")] [HttpGet("Message/Find")]
public async Task<IActionResult> FindMessage([FromQuery]string query) public async Task<IActionResult> FindMessage([FromQuery] string query)
{ {
ViewBag.Localization = _translationLookup; ViewBag.Localization = _translationLookup;
ViewBag.EnableColorCodes = _manager.GetApplicationSettings().Configuration().EnableColorCodes; ViewBag.EnableColorCodes = _manager.GetApplicationSettings().Configuration().EnableColorCodes;
@ -151,7 +125,7 @@ namespace IW4MAdmin.Plugins.Web.StatsWeb.Controllers
} }
[HttpGet("Message/FindNext")] [HttpGet("Message/FindNext")]
public async Task<IActionResult> FindNextMessages([FromQuery]string query, [FromQuery]int count, [FromQuery]int offset) public async Task<IActionResult> FindNextMessages([FromQuery] string query, [FromQuery] int count, [FromQuery] int offset)
{ {
ChatSearchQuery searchRequest; ChatSearchQuery searchRequest;

View File

@ -1,32 +0,0 @@
using System;
namespace StatsWeb.Dtos
{
public class ChatSearchResult
{
/// <summary>
/// name of the client
/// </summary>
public string ClientName { get; set; }
/// <summary>
/// client id
/// </summary>
public int ClientId { get; set; }
/// <summary>
/// hostname of the server
/// </summary>
public string ServerName { get; set; }
/// <summary>
/// chat message
/// </summary>
public string Message { get; set; }
/// <summary>
/// date the chat occured on
/// </summary>
public DateTime Date { get; set; }
}
}

View File

@ -1,5 +1,5 @@
using SharedLibraryCore.Dtos; using SharedLibraryCore.Dtos;
using StatsWeb.Dtos; using Stats.Dtos;
using System; using System;
using System.Linq; using System.Linq;

View File

@ -14,7 +14,7 @@
<RunPostBuildEvent>Always</RunPostBuildEvent> <RunPostBuildEvent>Always</RunPostBuildEvent>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.4.7" PrivateAssets="All" /> <PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.4.9" PrivateAssets="All" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -1,4 +1,5 @@
@model SharedLibraryCore.Helpers.ResourceQueryHelperResult<StatsWeb.Dtos.ChatSearchResult> @using SharedLibraryCore.Dtos.Meta.Responses
@model SharedLibraryCore.Helpers.ResourceQueryHelperResult<MessageResponse>
@if (ViewBag.Error != null) @if (ViewBag.Error != null)
{ {

View File

@ -1,4 +1,5 @@
@model IEnumerable<StatsWeb.Dtos.ChatSearchResult> @using SharedLibraryCore.Dtos.Meta.Responses
@model IEnumerable<MessageResponse>
@foreach (var message in Model) @foreach (var message in Model)
{ {
@ -10,13 +11,20 @@
</a> </a>
</td> </td>
<td class="text-light w-50 text-break"> <td class="text-light w-50 text-break">
<color-code value="@message.Message" allow="@ViewBag.EnableColorCodes"></color-code> @if (message.IsHidden && !ViewBag.Authorized)
{
<color-code value="@SharedLibraryCore.Utilities.FormatExt(ViewBag.Localization["WEBFRONT_CLIENT_META_CHAT_HIDDEN"], message.HiddenMessage)" allow="@ViewBag.EnableColorCodes"></color-code>
}
else
{
<color-code value="@message.Message" allow="@ViewBag.EnableColorCodes"></color-code>
}
</td> </td>
<td class="text-light"> <td class="text-light">
<color-code value="@(message.ServerName ?? "--")" allow="@ViewBag.EnableColorCodes"></color-code> <color-code value="@(message.ServerName ?? "--")" allow="@ViewBag.EnableColorCodes"></color-code>
</td> </td>
<td class="text-right text-light"> <td class="text-right text-light">
@message.Date @message.When
</td> </td>
</tr> </tr>
@ -33,7 +41,14 @@
<tr class="d-table-row d-lg-none bg-dark"> <tr class="d-table-row d-lg-none bg-dark">
<th scope="row" class="bg-primary">@ViewBag.Localization["WEBFRONT_ACTION_LABEL_MESSAGE"]</th> <th scope="row" class="bg-primary">@ViewBag.Localization["WEBFRONT_ACTION_LABEL_MESSAGE"]</th>
<td class="text-light"> <td class="text-light">
<color-code value="@message.Message" allow="@ViewBag.EnableColorCodes"></color-code> @if (message.IsHidden && !ViewBag.Authorized)
{
<color-code value="@SharedLibraryCore.Utilities.FormatExt(ViewBag.Localization["WEBFRONT_CLIENT_META_CHAT_HIDDEN"], message.HiddenMessage)" allow="@ViewBag.EnableColorCodes"></color-code>
}
else
{
<color-code value="@message.Message" allow="@ViewBag.EnableColorCodes"></color-code>
}
</td> </td>
</tr> </tr>
@ -47,7 +62,7 @@
<tr class="d-table-row d-lg-none bg-dark"> <tr class="d-table-row d-lg-none bg-dark">
<th scope="row" class="bg-primary" style="border-bottom: 1px solid #222">@ViewBag.Localization["WEBFRONT_ADMIN_AUDIT_LOG_TIME"]</th> <th scope="row" class="bg-primary" style="border-bottom: 1px solid #222">@ViewBag.Localization["WEBFRONT_ADMIN_AUDIT_LOG_TIME"]</th>
<td class="text-light mb-2 border-bottom"> <td class="text-light mb-2 border-bottom">
@message.Date @message.When
</td> </td>
</tr> </tr>
} }

View File

@ -1,20 +1,21 @@
@model IEnumerable<SharedLibraryCore.Dtos.ChatInfo> @using SharedLibraryCore.Dtos.Meta.Responses
@model IEnumerable<MessageResponse>
@{ @{
Layout = null; Layout = null;
} }
<div class="client-message-context"> <div class="client-message-context">
<h5 class="bg-primary pt-2 pb-2 pl-3 mb-0 mt-2 text-white">@Model.First().Time.ToString()</h5> <h5 class="bg-primary pt-2 pb-2 pl-3 mb-0 mt-2 text-white">@Model.First().When.ToString()</h5>
<div class="bg-dark p-3 mb-2 border-bottom"> <div class="bg-dark p-3 mb-2 border-bottom">
@foreach (var message in Model) @foreach (var message in Model)
{ {
<span class="text-white"> <span class="text-white">
<color-code value="@message.Name" allow="ViewBag.EnableColorCodes"></color-code> <color-code value="@message.ClientName" allow="ViewBag.EnableColorCodes"></color-code>
</span> </span>
<span> <span>
&mdash; &mdash;
<span class="@(message.IsQuickMessage ? "font-italic" : "")"> <span class="@(message.IsQuickMessage ? "font-italic" : "")">
<color-code value="@message.Message" allow="ViewBag.EnableColorCodes"></color-code> <color-code value="@(message.IsHidden ? message.HiddenMessage : message.Message)" allow="ViewBag.EnableColorCodes"></color-code>
</span> </span>
</span> </span>
<br /> <br />

View File

@ -16,7 +16,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.4.7" PrivateAssets="All" /> <PackageReference Include="RaidMax.IW4MAdmin.SharedLibraryCore" Version="2.4.9" PrivateAssets="All" />
</ItemGroup> </ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent"> <Target Name="PostBuild" AfterTargets="PostBuildEvent">

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Linq;
using static SharedLibraryCore.Server; using static SharedLibraryCore.Server;
namespace SharedLibraryCore.Dtos namespace SharedLibraryCore.Dtos
@ -11,5 +12,7 @@ namespace SharedLibraryCore.Dtos
public string Name { get; set; } public string Name { get; set; }
public Game ServerGame { get; set; } public Game ServerGame { get; set; }
public bool IsQuickMessage { get; set; } public bool IsQuickMessage { get; set; }
public bool IsHidden { get; set; }
public string HiddenMessage => string.Concat(Enumerable.Repeat('●', Message.Length));
} }
} }

View File

@ -1,6 +1,4 @@
using System; using System.Linq;
using System.Collections.Generic;
using System.Text;
namespace SharedLibraryCore.Dtos.Meta.Responses namespace SharedLibraryCore.Dtos.Meta.Responses
{ {
@ -8,5 +6,28 @@ namespace SharedLibraryCore.Dtos.Meta.Responses
{ {
public long ServerId { get; set; } public long ServerId { get; set; }
public string Message { get; set; } public string Message { get; set; }
public bool IsHidden { get; set; }
/// <summary>
/// name of the client
/// </summary>
public string ClientName { get; set; }
/// <summary>
/// hostname of the server
/// </summary>
public string ServerName { get; set; }
/// <summary>
/// specifies the game the chat occured on
/// </summary>
public Server.Game GameName { get; set; }
/// <summary>
/// indicates if the chat message is a quick message phrase
/// </summary>
public bool IsQuickMessage { get; set; }
public string HiddenMessage => string.Concat(Enumerable.Repeat('●', Message.Length));
} }
} }

View File

@ -21,5 +21,6 @@ namespace SharedLibraryCore.Dtos
public bool Online { get; set; } public bool Online { get; set; }
public string ConnectProtocolUrl { get; set; } public string ConnectProtocolUrl { get; set; }
public string IPAddress { get; set; } public string IPAddress { get; set; }
public bool IsPasswordProtected { get; set; }
} }
} }

View File

@ -0,0 +1,925 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using SharedLibraryCore.Database;
namespace SharedLibraryCore.Migrations
{
[DbContext(typeof(DatabaseContext))]
[Migration("20200819224119_AddIsPasswordProtectedColumn")]
partial class AddIsPasswordProtectedColumn
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "3.1.7");
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b =>
{
b.Property<int>("SnapshotId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<bool>("Active")
.HasColumnType("INTEGER");
b.Property<int>("ClientId")
.HasColumnType("INTEGER");
b.Property<int>("CurrentSessionLength")
.HasColumnType("INTEGER");
b.Property<double>("CurrentStrain")
.HasColumnType("REAL");
b.Property<int>("CurrentViewAngleId")
.HasColumnType("INTEGER");
b.Property<int>("Deaths")
.HasColumnType("INTEGER");
b.Property<double>("Distance")
.HasColumnType("REAL");
b.Property<double>("EloRating")
.HasColumnType("REAL");
b.Property<int>("HitDestinationId")
.HasColumnType("INTEGER");
b.Property<int>("HitLocation")
.HasColumnType("INTEGER");
b.Property<int>("HitOriginId")
.HasColumnType("INTEGER");
b.Property<int>("HitType")
.HasColumnType("INTEGER");
b.Property<int>("Hits")
.HasColumnType("INTEGER");
b.Property<int>("Kills")
.HasColumnType("INTEGER");
b.Property<int>("LastStrainAngleId")
.HasColumnType("INTEGER");
b.Property<double>("RecoilOffset")
.HasColumnType("REAL");
b.Property<double>("SessionAngleOffset")
.HasColumnType("REAL");
b.Property<double>("SessionAverageSnapValue")
.HasColumnType("REAL");
b.Property<double>("SessionSPM")
.HasColumnType("REAL");
b.Property<int>("SessionScore")
.HasColumnType("INTEGER");
b.Property<int>("SessionSnapHits")
.HasColumnType("INTEGER");
b.Property<double>("StrainAngleBetween")
.HasColumnType("REAL");
b.Property<int>("TimeSinceLastEvent")
.HasColumnType("INTEGER");
b.Property<int>("WeaponId")
.HasColumnType("INTEGER");
b.Property<DateTime>("When")
.HasColumnType("TEXT");
b.HasKey("SnapshotId");
b.HasIndex("ClientId");
b.HasIndex("CurrentViewAngleId");
b.HasIndex("HitDestinationId");
b.HasIndex("HitOriginId");
b.HasIndex("LastStrainAngleId");
b.ToTable("EFACSnapshot");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshotVector3", b =>
{
b.Property<int>("ACSnapshotVector3Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<bool>("Active")
.HasColumnType("INTEGER");
b.Property<int>("SnapshotId")
.HasColumnType("INTEGER");
b.Property<int>("Vector3Id")
.HasColumnType("INTEGER");
b.HasKey("ACSnapshotVector3Id");
b.HasIndex("SnapshotId");
b.HasIndex("Vector3Id");
b.ToTable("EFACSnapshotVector3");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b =>
{
b.Property<long>("KillId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<bool>("Active")
.HasColumnType("INTEGER");
b.Property<int>("AttackerId")
.HasColumnType("INTEGER");
b.Property<int>("Damage")
.HasColumnType("INTEGER");
b.Property<int?>("DeathOriginVector3Id")
.HasColumnType("INTEGER");
b.Property<int>("DeathType")
.HasColumnType("INTEGER");
b.Property<double>("Fraction")
.HasColumnType("REAL");
b.Property<int>("HitLoc")
.HasColumnType("INTEGER");
b.Property<bool>("IsKill")
.HasColumnType("INTEGER");
b.Property<int?>("KillOriginVector3Id")
.HasColumnType("INTEGER");
b.Property<int>("Map")
.HasColumnType("INTEGER");
b.Property<long>("ServerId")
.HasColumnType("INTEGER");
b.Property<int>("VictimId")
.HasColumnType("INTEGER");
b.Property<int?>("ViewAnglesVector3Id")
.HasColumnType("INTEGER");
b.Property<double>("VisibilityPercentage")
.HasColumnType("REAL");
b.Property<int>("Weapon")
.HasColumnType("INTEGER");
b.Property<DateTime>("When")
.HasColumnType("TEXT");
b.HasKey("KillId");
b.HasIndex("AttackerId");
b.HasIndex("DeathOriginVector3Id");
b.HasIndex("KillOriginVector3Id");
b.HasIndex("ServerId");
b.HasIndex("VictimId");
b.HasIndex("ViewAnglesVector3Id");
b.ToTable("EFClientKills");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientMessage", b =>
{
b.Property<long>("MessageId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<bool>("Active")
.HasColumnType("INTEGER");
b.Property<int>("ClientId")
.HasColumnType("INTEGER");
b.Property<string>("Message")
.HasColumnType("TEXT");
b.Property<long>("ServerId")
.HasColumnType("INTEGER");
b.Property<DateTime>("TimeSent")
.HasColumnType("TEXT");
b.HasKey("MessageId");
b.HasIndex("ClientId");
b.HasIndex("ServerId");
b.HasIndex("TimeSent");
b.ToTable("EFClientMessages");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", b =>
{
b.Property<int>("RatingHistoryId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<bool>("Active")
.HasColumnType("INTEGER");
b.Property<int>("ClientId")
.HasColumnType("INTEGER");
b.HasKey("RatingHistoryId");
b.HasIndex("ClientId");
b.ToTable("EFClientRatingHistory");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b =>
{
b.Property<int>("ClientId")
.HasColumnType("INTEGER");
b.Property<long>("ServerId")
.HasColumnType("INTEGER");
b.Property<bool>("Active")
.HasColumnType("INTEGER");
b.Property<double>("AverageRecoilOffset")
.HasColumnType("REAL");
b.Property<double>("AverageSnapValue")
.HasColumnType("REAL");
b.Property<int>("Deaths")
.HasColumnType("INTEGER");
b.Property<double>("EloRating")
.HasColumnType("REAL");
b.Property<int>("Kills")
.HasColumnType("INTEGER");
b.Property<double>("MaxStrain")
.HasColumnType("REAL");
b.Property<double>("RollingWeightedKDR")
.HasColumnType("REAL");
b.Property<double>("SPM")
.HasColumnType("REAL");
b.Property<double>("Skill")
.HasColumnType("REAL");
b.Property<int>("SnapHitCount")
.HasColumnType("INTEGER");
b.Property<int>("TimePlayed")
.HasColumnType("INTEGER");
b.Property<double>("VisionAverage")
.HasColumnType("REAL");
b.HasKey("ClientId", "ServerId");
b.HasIndex("ServerId");
b.ToTable("EFClientStatistics");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFHitLocationCount", b =>
{
b.Property<int>("HitLocationCountId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<bool>("Active")
.HasColumnType("INTEGER");
b.Property<int>("EFClientStatisticsClientId")
.HasColumnName("EFClientStatisticsClientId")
.HasColumnType("INTEGER");
b.Property<long>("EFClientStatisticsServerId")
.HasColumnName("EFClientStatisticsServerId")
.HasColumnType("INTEGER");
b.Property<int>("HitCount")
.HasColumnType("INTEGER");
b.Property<float>("HitOffsetAverage")
.HasColumnType("REAL");
b.Property<int>("Location")
.HasColumnType("INTEGER");
b.Property<float>("MaxAngleDistance")
.HasColumnType("REAL");
b.HasKey("HitLocationCountId");
b.HasIndex("EFClientStatisticsServerId");
b.HasIndex("EFClientStatisticsClientId", "EFClientStatisticsServerId");
b.ToTable("EFHitLocationCounts");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b =>
{
b.Property<int>("RatingId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<bool>("Active")
.HasColumnType("INTEGER");
b.Property<int>("ActivityAmount")
.HasColumnType("INTEGER");
b.Property<bool>("Newest")
.HasColumnType("INTEGER");
b.Property<double>("Performance")
.HasColumnType("REAL");
b.Property<int>("Ranking")
.HasColumnType("INTEGER");
b.Property<int>("RatingHistoryId")
.HasColumnType("INTEGER");
b.Property<long?>("ServerId")
.HasColumnType("INTEGER");
b.Property<DateTime>("When")
.HasColumnType("TEXT");
b.HasKey("RatingId");
b.HasIndex("RatingHistoryId");
b.HasIndex("ServerId");
b.HasIndex("Performance", "Ranking", "When");
b.ToTable("EFRating");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServer", b =>
{
b.Property<long>("ServerId")
.HasColumnType("INTEGER");
b.Property<bool>("Active")
.HasColumnType("INTEGER");
b.Property<string>("EndPoint")
.HasColumnType("TEXT");
b.Property<int?>("GameName")
.HasColumnType("INTEGER");
b.Property<string>("HostName")
.HasColumnType("TEXT");
b.Property<bool>("IsPasswordProtected")
.HasColumnType("INTEGER");
b.Property<int>("Port")
.HasColumnType("INTEGER");
b.HasKey("ServerId");
b.ToTable("EFServers");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b =>
{
b.Property<int>("StatisticId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<bool>("Active")
.HasColumnType("INTEGER");
b.Property<long>("ServerId")
.HasColumnType("INTEGER");
b.Property<long>("TotalKills")
.HasColumnType("INTEGER");
b.Property<long>("TotalPlayTime")
.HasColumnType("INTEGER");
b.HasKey("StatisticId");
b.HasIndex("ServerId");
b.ToTable("EFServerStatistics");
});
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAlias", b =>
{
b.Property<int>("AliasId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<bool>("Active")
.HasColumnType("INTEGER");
b.Property<DateTime>("DateAdded")
.HasColumnType("TEXT");
b.Property<int?>("IPAddress")
.HasColumnType("INTEGER");
b.Property<int>("LinkId")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("TEXT")
.HasMaxLength(24);
b.Property<string>("SearchableName")
.HasColumnType("TEXT")
.HasMaxLength(24);
b.HasKey("AliasId");
b.HasIndex("IPAddress");
b.HasIndex("LinkId");
b.HasIndex("Name");
b.HasIndex("SearchableName");
b.HasIndex("Name", "IPAddress")
.IsUnique();
b.ToTable("EFAlias");
});
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAliasLink", b =>
{
b.Property<int>("AliasLinkId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<bool>("Active")
.HasColumnType("INTEGER");
b.HasKey("AliasLinkId");
b.ToTable("EFAliasLinks");
});
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFChangeHistory", b =>
{
b.Property<int>("ChangeHistoryId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<bool>("Active")
.HasColumnType("INTEGER");
b.Property<string>("Comment")
.HasColumnType("TEXT")
.HasMaxLength(128);
b.Property<string>("CurrentValue")
.HasColumnType("TEXT");
b.Property<int?>("ImpersonationEntityId")
.HasColumnType("INTEGER");
b.Property<int>("OriginEntityId")
.HasColumnType("INTEGER");
b.Property<string>("PreviousValue")
.HasColumnType("TEXT");
b.Property<int>("TargetEntityId")
.HasColumnType("INTEGER");
b.Property<DateTime>("TimeChanged")
.HasColumnType("TEXT");
b.Property<int>("TypeOfChange")
.HasColumnType("INTEGER");
b.HasKey("ChangeHistoryId");
b.ToTable("EFChangeHistory");
});
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFClient", b =>
{
b.Property<int>("ClientId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<bool>("Active")
.HasColumnType("INTEGER");
b.Property<int>("AliasLinkId")
.HasColumnType("INTEGER");
b.Property<int>("Connections")
.HasColumnType("INTEGER");
b.Property<int>("CurrentAliasId")
.HasColumnType("INTEGER");
b.Property<DateTime>("FirstConnection")
.HasColumnType("TEXT");
b.Property<DateTime>("LastConnection")
.HasColumnType("TEXT");
b.Property<int>("Level")
.HasColumnType("INTEGER");
b.Property<bool>("Masked")
.HasColumnType("INTEGER");
b.Property<long>("NetworkId")
.HasColumnType("INTEGER");
b.Property<string>("Password")
.HasColumnType("TEXT");
b.Property<string>("PasswordSalt")
.HasColumnType("TEXT");
b.Property<int>("TotalConnectionTime")
.HasColumnType("INTEGER");
b.HasKey("ClientId");
b.HasIndex("AliasLinkId");
b.HasIndex("CurrentAliasId");
b.HasIndex("NetworkId")
.IsUnique();
b.ToTable("EFClients");
});
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFMeta", b =>
{
b.Property<int>("MetaId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<bool>("Active")
.HasColumnType("INTEGER");
b.Property<int>("ClientId")
.HasColumnType("INTEGER");
b.Property<DateTime>("Created")
.HasColumnType("TEXT");
b.Property<string>("Extra")
.HasColumnType("TEXT");
b.Property<string>("Key")
.IsRequired()
.HasColumnType("TEXT")
.HasMaxLength(32);
b.Property<DateTime>("Updated")
.HasColumnType("TEXT");
b.Property<string>("Value")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("MetaId");
b.HasIndex("ClientId");
b.HasIndex("Key");
b.ToTable("EFMeta");
});
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFPenalty", b =>
{
b.Property<int>("PenaltyId")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<bool>("Active")
.HasColumnType("INTEGER");
b.Property<string>("AutomatedOffense")
.HasColumnType("TEXT");
b.Property<DateTime?>("Expires")
.HasColumnType("TEXT");
b.Property<bool>("IsEvadedOffense")
.HasColumnType("INTEGER");
b.Property<int>("LinkId")
.HasColumnType("INTEGER");
b.Property<int>("OffenderId")
.HasColumnType("INTEGER");
b.Property<string>("Offense")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("PunisherId")
.HasColumnType("INTEGER");
b.Property<int>("Type")
.HasColumnType("INTEGER");
b.Property<DateTime>("When")
.HasColumnType("TEXT");
b.HasKey("PenaltyId");
b.HasIndex("LinkId");
b.HasIndex("OffenderId");
b.HasIndex("PunisherId");
b.ToTable("EFPenalties");
});
modelBuilder.Entity("SharedLibraryCore.Helpers.Vector3", b =>
{
b.Property<int>("Vector3Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<float>("X")
.HasColumnType("REAL");
b.Property<float>("Y")
.HasColumnType("REAL");
b.Property<float>("Z")
.HasColumnType("REAL");
b.HasKey("Vector3Id");
b.ToTable("Vector3");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b =>
{
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
.WithMany()
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("SharedLibraryCore.Helpers.Vector3", "CurrentViewAngle")
.WithMany()
.HasForeignKey("CurrentViewAngleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("SharedLibraryCore.Helpers.Vector3", "HitDestination")
.WithMany()
.HasForeignKey("HitDestinationId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("SharedLibraryCore.Helpers.Vector3", "HitOrigin")
.WithMany()
.HasForeignKey("HitOriginId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("SharedLibraryCore.Helpers.Vector3", "LastStrainAngle")
.WithMany()
.HasForeignKey("LastStrainAngleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshotVector3", b =>
{
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", "Snapshot")
.WithMany("PredictedViewAngles")
.HasForeignKey("SnapshotId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("SharedLibraryCore.Helpers.Vector3", "Vector")
.WithMany()
.HasForeignKey("Vector3Id")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b =>
{
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Attacker")
.WithMany()
.HasForeignKey("AttackerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("SharedLibraryCore.Helpers.Vector3", "DeathOrigin")
.WithMany()
.HasForeignKey("DeathOriginVector3Id");
b.HasOne("SharedLibraryCore.Helpers.Vector3", "KillOrigin")
.WithMany()
.HasForeignKey("KillOriginVector3Id");
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
.WithMany()
.HasForeignKey("ServerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Victim")
.WithMany()
.HasForeignKey("VictimId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("SharedLibraryCore.Helpers.Vector3", "ViewAngles")
.WithMany()
.HasForeignKey("ViewAnglesVector3Id");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientMessage", b =>
{
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
.WithMany()
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
.WithMany()
.HasForeignKey("ServerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", b =>
{
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
.WithMany()
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b =>
{
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
.WithMany()
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
.WithMany()
.HasForeignKey("ServerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFHitLocationCount", b =>
{
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
.WithMany()
.HasForeignKey("EFClientStatisticsClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
.WithMany()
.HasForeignKey("EFClientStatisticsServerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", null)
.WithMany("HitLocations")
.HasForeignKey("EFClientStatisticsClientId", "EFClientStatisticsServerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b =>
{
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", "RatingHistory")
.WithMany("Ratings")
.HasForeignKey("RatingHistoryId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
.WithMany()
.HasForeignKey("ServerId");
});
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b =>
{
b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
.WithMany()
.HasForeignKey("ServerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAlias", b =>
{
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "Link")
.WithMany("Children")
.HasForeignKey("LinkId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
});
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFClient", b =>
{
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "AliasLink")
.WithMany()
.HasForeignKey("AliasLinkId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("SharedLibraryCore.Database.Models.EFAlias", "CurrentAlias")
.WithMany()
.HasForeignKey("CurrentAliasId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFMeta", b =>
{
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
.WithMany("Meta")
.HasForeignKey("ClientId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("SharedLibraryCore.Database.Models.EFPenalty", b =>
{
b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "Link")
.WithMany("ReceivedPenalties")
.HasForeignKey("LinkId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Offender")
.WithMany("ReceivedPenalties")
.HasForeignKey("OffenderId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Punisher")
.WithMany("AdministeredPenalties")
.HasForeignKey("PunisherId")
.OnDelete(DeleteBehavior.Restrict)
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,35 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace SharedLibraryCore.Migrations
{
public partial class AddIsPasswordProtectedColumn : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
if (migrationBuilder.ActiveProvider == "Npgsql.EntityFrameworkCore.PostgreSQL")
{
migrationBuilder.AddColumn<bool>(
name: "IsPasswordProtected",
type: "bool",
table: "EFServers",
nullable: false,
defaultValue: false);
}
else
{
migrationBuilder.AddColumn<bool>(
name: "IsPasswordProtected",
table: "EFServers",
nullable: false,
defaultValue: false);
}
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "IsPasswordProtected",
table: "EFServers");
}
}
}

View File

@ -14,7 +14,7 @@ namespace SharedLibraryCore.Migrations
{ {
#pragma warning disable 612, 618 #pragma warning disable 612, 618
modelBuilder modelBuilder
.HasAnnotation("ProductVersion", "3.1.3"); .HasAnnotation("ProductVersion", "3.1.7");
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b => modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b =>
{ {
@ -408,6 +408,9 @@ namespace SharedLibraryCore.Migrations
b.Property<string>("HostName") b.Property<string>("HostName")
.HasColumnType("TEXT"); .HasColumnType("TEXT");
b.Property<bool>("IsPasswordProtected")
.HasColumnType("INTEGER");
b.Property<int>("Port") b.Property<int>("Port")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");

View File

@ -293,6 +293,7 @@ namespace SharedLibraryCore
public string Hostname { get => ServerConfig.CustomHostname ?? hostname; protected set => hostname = value; } public string Hostname { get => ServerConfig.CustomHostname ?? hostname; protected set => hostname = value; }
public string Website { get; protected set; } public string Website { get; protected set; }
public string Gametype { get; set; } public string Gametype { get; set; }
public string GamePassword { get; protected set; }
public Map CurrentMap { get; set; } public Map CurrentMap { get; set; }
public int ClientNum public int ClientNum
{ {

View File

@ -6,7 +6,7 @@
<ApplicationIcon /> <ApplicationIcon />
<StartupObject /> <StartupObject />
<PackageId>RaidMax.IW4MAdmin.SharedLibraryCore</PackageId> <PackageId>RaidMax.IW4MAdmin.SharedLibraryCore</PackageId>
<Version>2.4.7</Version> <Version>2.4.9</Version>
<Authors>RaidMax</Authors> <Authors>RaidMax</Authors>
<Company>Forever None</Company> <Company>Forever None</Company>
<Configurations>Debug;Release;Prerelease</Configurations> <Configurations>Debug;Release;Prerelease</Configurations>
@ -21,8 +21,8 @@
<IsPackable>true</IsPackable> <IsPackable>true</IsPackable>
<PackageLicenseExpression>MIT</PackageLicenseExpression> <PackageLicenseExpression>MIT</PackageLicenseExpression>
<Description>Shared Library for IW4MAdmin</Description> <Description>Shared Library for IW4MAdmin</Description>
<AssemblyVersion>2.4.7.0</AssemblyVersion> <AssemblyVersion>2.4.9.0</AssemblyVersion>
<FileVersion>2.4.7.0</FileVersion> <FileVersion>2.4.9.0</FileVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Prerelease|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Prerelease|AnyCPU'">

View File

@ -672,11 +672,11 @@ namespace SharedLibraryCore
return server.RconParser.GetDvarAsync(server.RemoteConnection, dvarName, fallbackValue); return server.RconParser.GetDvarAsync(server.RemoteConnection, dvarName, fallbackValue);
} }
public static async Task<Dvar<T>> GetMappedDvarValueOrDefaultAsync<T>(this Server server, string dvarName, string infoResponseName = null, IDictionary<string, string> infoResponse = null) public static async Task<Dvar<T>> GetMappedDvarValueOrDefaultAsync<T>(this Server server, string dvarName, string infoResponseName = null, IDictionary<string, string> infoResponse = null, T overrideDefault = default)
{ {
// todo: unit test this // todo: unit test this
string mappedKey = server.RconParser.GetOverrideDvarName(dvarName); string mappedKey = server.RconParser.GetOverrideDvarName(dvarName);
var defaultValue = server.RconParser.GetDefaultDvarValue<T>(mappedKey); var defaultValue = server.RconParser.GetDefaultDvarValue<T>(mappedKey) ?? overrideDefault;
string foundKey = infoResponse?.Keys.Where(_key => new[] { mappedKey, dvarName, infoResponseName ?? dvarName }.Contains(_key)).FirstOrDefault(); string foundKey = infoResponse?.Keys.Where(_key => new[] { mappedKey, dvarName, infoResponseName ?? dvarName }.Contains(_key)).FirstOrDefault();
@ -811,7 +811,7 @@ namespace SharedLibraryCore
/// <returns>true if the </returns> /// <returns>true if the </returns>
public static bool IsQuickMessage(this string message) public static bool IsQuickMessage(this string message)
{ {
return Regex.IsMatch(message, @"^\u0014(?:[A-Z]|_)+$"); return Regex.IsMatch(message, @"^\u0014(?:\w|_|!|\s)+$");
} }
/// <summary> /// <summary>

View File

@ -9,7 +9,6 @@ using SharedLibraryCore.Dtos;
using SharedLibraryCore.Helpers; using SharedLibraryCore.Helpers;
using SharedLibraryCore.Interfaces; using SharedLibraryCore.Interfaces;
using Stats.Dtos; using Stats.Dtos;
using StatsWeb.Dtos;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;

View File

@ -18,7 +18,7 @@ namespace ApplicationTests.Fixtures
Say = "say" Say = "say"
} }
}; };
public static ApplicationConfiguration CreateApplicationConfiguration() => new ApplicationConfiguration() { Servers = new[] { CreateServerConfiguration() } }; public static ApplicationConfiguration CreateApplicationConfiguration() => new ApplicationConfiguration() { Servers = new[] { CreateServerConfiguration() }, QuickMessages = new QuickMessageConfiguration[0] };
public static CommandConfiguration CreateCommandConfiguration() => new CommandConfiguration(); public static CommandConfiguration CreateCommandConfiguration() => new CommandConfiguration();
} }
} }

View File

@ -19,7 +19,7 @@ namespace ApplicationTests.Fixtures
return new EFClientMessage() return new EFClientMessage()
{ {
Active = true, Active = true,
Message = content, Message = content ?? "test",
TimeSent = sent.Value, TimeSent = sent.Value,
Client = new EFClient() Client = new EFClient()
{ {

View File

@ -154,7 +154,7 @@ namespace ApplicationTests
var query = $"chat|after {DateTime.Now.ToString()}".ParseSearchInfo(1, 0); var query = $"chat|after {DateTime.Now.ToString()}".ParseSearchInfo(1, 0);
var result = await queryHelper.QueryResource(query); var result = await queryHelper.QueryResource(query);
Assert.AreEqual(oneHourAhead, result.Results.First().Date); Assert.AreEqual(oneHourAhead, result.Results.First().When);
dbContext.Remove(msg); dbContext.Remove(msg);
await dbContext.SaveChangesAsync(); await dbContext.SaveChangesAsync();
@ -173,7 +173,7 @@ namespace ApplicationTests
var query = $"chat|before {DateTime.Now.ToString()}".ParseSearchInfo(1, 0); var query = $"chat|before {DateTime.Now.ToString()}".ParseSearchInfo(1, 0);
var result = await queryHelper.QueryResource(query); var result = await queryHelper.QueryResource(query);
Assert.AreEqual(oneHourAgo, result.Results.First().Date); Assert.AreEqual(oneHourAgo, result.Results.First().When);
dbContext.Remove(msg); dbContext.Remove(msg);
await dbContext.SaveChangesAsync(); await dbContext.SaveChangesAsync();
@ -251,14 +251,14 @@ namespace ApplicationTests
var query = $"chat|sort {SortDirection.Ascending}".ParseSearchInfo(2, 0); var query = $"chat|sort {SortDirection.Ascending}".ParseSearchInfo(2, 0);
var result = await queryHelper.QueryResource(query); var result = await queryHelper.QueryResource(query);
Assert.AreEqual(firstMessage.TimeSent, result.Results.First().Date); Assert.AreEqual(firstMessage.TimeSent, result.Results.First().When);
Assert.AreEqual(secondMessage.TimeSent, result.Results.Last().Date); Assert.AreEqual(secondMessage.TimeSent, result.Results.Last().When);
query = $"chat|sort {SortDirection.Descending}".ParseSearchInfo(2, 0); query = $"chat|sort {SortDirection.Descending}".ParseSearchInfo(2, 0);
result = await queryHelper.QueryResource(query); result = await queryHelper.QueryResource(query);
Assert.AreEqual(firstMessage.TimeSent, result.Results.Last().Date); Assert.AreEqual(firstMessage.TimeSent, result.Results.Last().When);
Assert.AreEqual(secondMessage.TimeSent, result.Results.First().Date); Assert.AreEqual(secondMessage.TimeSent, result.Results.First().When);
dbContext.Remove(firstMessage); dbContext.Remove(firstMessage);
dbContext.Remove(secondMessage); dbContext.Remove(secondMessage);

View File

@ -42,7 +42,8 @@ namespace WebfrontCore.Controllers
LevelInt = (int)p.Level LevelInt = (int)p.Level
}).ToList(), }).ToList(),
ChatHistory = s.ChatHistory.ToList(), ChatHistory = s.ChatHistory.ToList(),
PlayerHistory = s.ClientHistory.ToArray() PlayerHistory = s.ClientHistory.ToArray(),
IsPasswordProtected = !string.IsNullOrEmpty(s.GamePassword)
}; };
return PartialView("_ClientActivity", serverInfo); return PartialView("_ClientActivity", serverInfo);
} }

View File

@ -5,31 +5,24 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.ApplicationParts; using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using SharedLibraryCore; using SharedLibraryCore;
using SharedLibraryCore.Configuration;
using SharedLibraryCore.Database; using SharedLibraryCore.Database;
using SharedLibraryCore.Dtos; using SharedLibraryCore.Dtos;
using SharedLibraryCore.Helpers; using SharedLibraryCore.Dtos.Meta.Responses;
using SharedLibraryCore.Interfaces; using SharedLibraryCore.Interfaces;
using SharedLibraryCore.Services; using SharedLibraryCore.Services;
using Stats.Dtos; using Stats.Dtos;
using Stats.Helpers; using Stats.Helpers;
using StatsWeb; using StatsWeb;
using StatsWeb.Dtos;
/*using Stats.Dtos;
using Stats.Helpers;
using StatsWeb;
using StatsWeb.Dtos;*/
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks; using System.Threading.Tasks;
using WebfrontCore.Controllers.API.Dtos;
using WebfrontCore.Controllers.API.Validation; using WebfrontCore.Controllers.API.Validation;
using WebfrontCore.Middleware; using WebfrontCore.Middleware;
@ -117,7 +110,7 @@ namespace WebfrontCore
#endif #endif
services.AddSingleton(Program.Manager); services.AddSingleton(Program.Manager);
services.AddSingleton<IResourceQueryHelper<ChatSearchQuery, ChatSearchResult>, ChatResourceQueryHelper>(); services.AddSingleton<IResourceQueryHelper<ChatSearchQuery, MessageResponse>, ChatResourceQueryHelper>();
services.AddTransient<IValidator<FindClientRequest>, FindClientRequestValidator>(); services.AddTransient<IValidator<FindClientRequest>, FindClientRequestValidator>();
services.AddSingleton<IResourceQueryHelper<FindClientRequest, FindClientResult>, ClientService>(); services.AddSingleton<IResourceQueryHelper<FindClientRequest, FindClientResult>, ClientService>();
services.AddSingleton<IResourceQueryHelper<StatsInfoRequest, StatsInfoResult>, StatsResourceQueryHelper>(); services.AddSingleton<IResourceQueryHelper<StatsInfoRequest, StatsInfoResult>, StatsResourceQueryHelper>();
@ -130,6 +123,7 @@ namespace WebfrontCore
services.AddSingleton(Program.ApplicationServiceProvider.GetService<SharedLibraryCore.Interfaces.ILogger>()); services.AddSingleton(Program.ApplicationServiceProvider.GetService<SharedLibraryCore.Interfaces.ILogger>());
services.AddSingleton(Program.ApplicationServiceProvider.GetService<IEnumerable<IManagerCommand>>()); services.AddSingleton(Program.ApplicationServiceProvider.GetService<IEnumerable<IManagerCommand>>());
services.AddSingleton(Program.ApplicationServiceProvider.GetService<IMetaService>()); services.AddSingleton(Program.ApplicationServiceProvider.GetService<IMetaService>());
services.AddSingleton(Program.ApplicationServiceProvider.GetService<ApplicationConfiguration>());
} }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.

View File

@ -1,9 +1,17 @@
@using SharedLibraryCore.Dtos.Meta.Responses; @using SharedLibraryCore.Dtos.Meta.Responses
@model MessageResponse @model MessageResponse
<span class="client-message" data-serverid="@Model.ServerId" data-when="@Model.When.ToFileTimeUtc()"> <span class="client-message" data-serverid="@Model.ServerId" data-when="@Model.When.ToFileTimeUtc()">
<span class="oi oi-chevron-right text-white-50 align-middle client-message-prefix" title="@ViewBag.Localization["WEBFRONT_PROFILE_MESSAGE_CONTEXT"]" style="font-size: 0.75rem; margin-top: -0.256rem"></span> <span class="oi oi-chevron-right text-white-50 align-middle client-message-prefix" title="@ViewBag.Localization["WEBFRONT_PROFILE_MESSAGE_CONTEXT"]" style="font-size: 0.75rem; margin-top: -0.256rem"></span>
<span class="text-muted"> <span class="text-muted @(Model.IsQuickMessage ? "font-weight-bold": "")">
<color-code value="@Model.Message" allow="@ViewBag.EnableColorCodes"></color-code> @if (Model.IsHidden && !ViewBag.Authorized)
{
<color-code value="@SharedLibraryCore.Utilities.FormatExt(ViewBag.Localization["WEBFRONT_CLIENT_META_CHAT_HIDDEN"], Model.HiddenMessage)" allow="@ViewBag.EnableColorCodes"></color-code>
}
else
{
<color-code value="@Model.Message" allow="@ViewBag.EnableColorCodes"></color-code>
}
</span> </span>
</span> </span>

View File

@ -15,6 +15,8 @@
continue; continue;
} }
string message = Model.ChatHistory[i].IsHidden && !ViewBag.Authorized ? Model.ChatHistory[i].HiddenMessage : Model.ChatHistory[i].Message;
if (Model.ChatHistory[i].Message == "CONNECTED") if (Model.ChatHistory[i].Message == "CONNECTED")
{ {
<span class="text-light"> <span class="text-light">
@ -36,7 +38,7 @@
</span> </span>
<span> <span>
&mdash; &mdash;
<color-code value="@Model.ChatHistory[i].Message.CapClientName(48)" allow="@ViewBag.EnableColorCodes"></color-code> <color-code value="@message.CapClientName(48)" allow="@ViewBag.EnableColorCodes"></color-code>
</span><br /> </span><br />
} }
} }
@ -114,6 +116,8 @@
continue; continue;
} }
string message = Model.ChatHistory[i].IsHidden && !ViewBag.Authorized ? Model.ChatHistory[i].HiddenMessage : Model.ChatHistory[i].Message;
if (Model.ChatHistory[i].Message == "CONNECTED") if (Model.ChatHistory[i].Message == "CONNECTED")
{ {
<span class="text-light"> <span class="text-light">
@ -135,7 +139,7 @@
</span> </span>
<span> <span>
&mdash; &mdash;
<color-code value="@Model.ChatHistory[i].Message.CapClientName(48)" allow="@ViewBag.EnableColorCodes"></color-code> <color-code value="@message.CapClientName(48)" allow="@ViewBag.EnableColorCodes"></color-code>
</span><br /> </span><br />
} }
} }

View File

@ -12,7 +12,7 @@ function initLoader(location, loaderId, count = 10, start = count, additional) {
loaderResponseId = loaderId; loaderResponseId = loaderId;
loadCount = count; loadCount = count;
loaderOffset = start; loaderOffset = start;
additionalParams = additional; additionalParams = additional ?? [];
setupListeners(); setupListeners();
} }