1
0
mirror of https://github.com/RaidMax/IW4M-Admin.git synced 2025-06-10 07:13:58 -05:00

QOL updates for profile meta

implement filterable meta for issue #158
update translations and use humanizer lib with datetime/timespan for issue #80
This commit is contained in:
RaidMax
2020-08-17 21:21:11 -05:00
parent 25ad16495e
commit 6e27dd9dce
78 changed files with 1800 additions and 775 deletions

View File

@ -53,7 +53,6 @@ namespace SharedLibraryCore.Commands
public override Task ExecuteAsync(GameEvent E)
{
MetaService.Clear();
E.Owner.Manager.Restart();
E.Origin.Tell(_translationLookup["COMMANDS_RESTART_SUCCESS"]);
return Task.CompletedTask;
@ -292,7 +291,7 @@ namespace SharedLibraryCore.Commands
switch ((await E.Target.TempBan(tempbanReason, length, E.Origin).WaitAsync(Utilities.DefaultCommandTimeout, E.Owner.Manager.CancellationToken)).FailReason)
{
case GameEvent.EventFailReason.None:
E.Origin.Tell(_translationLookup["COMMANDS_TEMPBAN_SUCCESS"].FormatExt(E.Target, length.TimeSpanText()));
E.Origin.Tell(_translationLookup["COMMANDS_TEMPBAN_SUCCESS"].FormatExt(E.Target, length.HumanizeForCurrentCulture()));
break;
case GameEvent.EventFailReason.Exception:
E.Origin.Tell(_translationLookup["SERVER_ERROR_COMMAND_INGAME"]);
@ -890,14 +889,9 @@ namespace SharedLibraryCore.Commands
return;
}
foreach (var P in db_players)
foreach (var client in db_players)
{
// they're not going by another alias
// /*P.AliasLink.Children.FirstOrDefault(a => a.Name.ToLower().Contains(E.Data.ToLower()))?.Name*/
string msg = P.Name.ToLower().Contains(E.Data.ToLower()) ?
$"[^3{P.Name}^7] [^3@{P.ClientId}^7] - [{ Utilities.ConvertLevelToColor((Permission)P.LevelInt, P.Level)}^7] - {P.IPAddress} | last seen {Utilities.GetTimePassed(P.LastConnection)}" :
$"()->[^3{P.Name}^7] [^3@{P.ClientId}^7] - [{ Utilities.ConvertLevelToColor((Permission)P.LevelInt, P.Level)}^7] - {P.IPAddress} | last seen {Utilities.GetTimePassed(P.LastConnection)}";
E.Origin.Tell(msg);
E.Origin.Tell(_translationLookup["COMMANDS_FIND_FORMAT"].FormatExt(client.Name, client.ClientId, Utilities.ConvertLevelToColor((Permission)client.LevelInt, client.Level), client.IPAddress, client.LastConnectionText));
}
}
}
@ -1259,7 +1253,7 @@ namespace SharedLibraryCore.Commands
else
{
string remainingTime = (penalty.Expires.Value - DateTime.UtcNow).TimeSpanText();
string remainingTime = (penalty.Expires.Value - DateTime.UtcNow).HumanizeForCurrentCulture();
E.Origin.Tell(_translationLookup["COMMANDS_BANINFO_TB_SUCCESS"].FormatExt(E.Target.Name, penalty.Offense, remainingTime));
}
}
@ -1543,7 +1537,9 @@ namespace SharedLibraryCore.Commands
/// </summary>
public class SetGravatarCommand : Command
{
public SetGravatarCommand(CommandConfiguration config, ITranslationLookup translationLookup) : base(config, translationLookup)
private readonly IMetaService _metaService;
public SetGravatarCommand(CommandConfiguration config, ITranslationLookup translationLookup, IMetaService metaService) : base(config, translationLookup)
{
Name = "setgravatar";
Description = _translationLookup["COMMANDS_GRAVATAR_DESC"];
@ -1558,17 +1554,17 @@ namespace SharedLibraryCore.Commands
Required = true
}
};
_metaService = metaService;
}
public override async Task ExecuteAsync(GameEvent E)
{
var metaSvc = new MetaService();
using (var md5 = MD5.Create())
{
string gravatarEmail = string.Concat(md5.ComputeHash(E.Data.ToLower().Select(d => Convert.ToByte(d)).ToArray())
.Select(h => h.ToString("x2")));
await metaSvc.AddPersistentMeta("GravatarEmail", gravatarEmail, E.Origin);
await _metaService.AddPersistentMeta("GravatarEmail", gravatarEmail, E.Origin);
}
E.Origin.Tell(_translationLookup["COMMANDS_GRAVATAR_SUCCESS_NEW"]);

View File

@ -1,6 +1,6 @@
namespace SharedLibraryCore.Dtos
{
public class FindClientRequest : PaginationInfo
public class FindClientRequest : PaginationRequest
{
/// <summary>
/// name of client

View File

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace SharedLibraryCore.Dtos.Meta.Requests
{
public class BaseClientMetaRequest : PaginationRequest
{
public int ClientId { get; set; }
}
}

View File

@ -0,0 +1,11 @@
using SharedLibraryCore.QueryHelper;
using System;
using System.Collections.Generic;
using System.Text;
namespace SharedLibraryCore.Dtos.Meta.Requests
{
public class ReceivedPenaltyRequest : BaseClientMetaRequest
{
}
}

View File

@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace SharedLibraryCore.Dtos.Meta.Responses
{
public class AdministeredPenaltyResponse : ReceivedPenaltyResponse
{
}
}

View File

@ -0,0 +1,19 @@
using SharedLibraryCore.Interfaces;
using System;
using System.Collections.Generic;
using System.Text;
namespace SharedLibraryCore.Dtos.Meta.Responses
{
public class BaseMetaResponse : IClientMeta, IClientMetaResponse
{
public int MetaId { get; set; }
public int ClientId { get; set; }
public MetaType Type { get; set; }
public DateTime When { get; set; }
public bool IsSensitive { get; set; }
public bool ShouldDisplay { get; set; }
public int? Column { get; set; }
public int? Order { get; set; }
}
}

View File

@ -0,0 +1,14 @@
using SharedLibraryCore.Interfaces;
using System;
using System.Collections.Generic;
using System.Text;
namespace SharedLibraryCore.Dtos.Meta.Responses
{
public class InformationResponse : BaseMetaResponse
{
public string Key { get; set; }
public string Value { get; set; }
public string ToolTipText { get; set; }
}
}

View File

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace SharedLibraryCore.Dtos.Meta.Responses
{
public class MessageResponse : BaseMetaResponse
{
public long ServerId { get; set; }
public string Message { get; set; }
}
}

View File

@ -0,0 +1,22 @@
using System;
using static SharedLibraryCore.Database.Models.EFPenalty;
namespace SharedLibraryCore.Dtos.Meta.Responses
{
public class ReceivedPenaltyResponse : BaseMetaResponse
{
public int PenaltyId { get; set; }
public int OffenderClientId { get; set; }
public string OffenderName { get; set; }
public string PunisherName { get; set; }
public int PunisherClientId { get; set; }
public PenaltyType PenaltyType { get; set; }
public string Offense { get; set; }
public string AutomatedOffense { get; set; }
public DateTime? ExpirationDate { get; set; }
public string ExpiresInText => ExpirationDate.HasValue && ExpirationDate.Value > DateTime.UtcNow ? (ExpirationDate - DateTime.UtcNow).Value.HumanizeForCurrentCulture() : "";
public string LengthText => ExpirationDate.HasValue ? (ExpirationDate.Value.AddMinutes(1) - When).HumanizeForCurrentCulture() : "";
public bool IsLinked { get; set; }
public int LinkedClientId { get; set; }
}
}

View File

@ -0,0 +1,22 @@
using System;
namespace SharedLibraryCore.Dtos.Meta.Responses
{
public class UpdatedAliasResponse : BaseMetaResponse
{
public string Name { get; set; }
public string IPAddress { get; set; } = "--";
public override bool Equals(object obj)
{
if (obj is UpdatedAliasResponse resp)
{
return resp.Name.StripColors() == Name.StripColors() && resp.IPAddress == IPAddress;
}
return false;
}
public override int GetHashCode() => HashCode.Combine(Name.StripColors(), IPAddress);
}
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace SharedLibraryCore.Dtos.Meta
{
public class WebfrontTranslationHelper
{
public bool IsInterpolation { get; set; }
public string MatchValue { get; set; }
public string TranslationValue { get; set; }
}
}

View File

@ -1,9 +1,11 @@
namespace SharedLibraryCore.Dtos
using System;
namespace SharedLibraryCore.Dtos
{
/// <summary>
/// pagination information holder class
/// </summary>
public class PaginationInfo
public class PaginationRequest
{
/// <summary>
/// how many items to skip
@ -24,6 +26,8 @@
/// direction of ordering
/// </summary>
public SortDirection Direction { get; set; } = SortDirection.Descending;
public DateTime? Before { get; set; }
}
public enum SortDirection

View File

@ -21,8 +21,8 @@ namespace SharedLibraryCore.Dtos
public PenaltyType PenaltyType { get; set; }
public string PenaltyTypeText => PenaltyType.ToString();
public DateTime TimePunished { get; set; }
public string TimePunishedString => Utilities.GetTimePassed(TimePunished, true);
public string TimeRemaining => DateTime.UtcNow > Expires ? "" : $"{((Expires ?? DateTime.MaxValue).Year == DateTime.MaxValue.Year ? Utilities.GetTimePassed(TimePunished, true) : Utilities.TimeSpanText((Expires ?? DateTime.MaxValue) - DateTime.UtcNow))}";
public string TimePunishedString => TimePunished.HumanizeForCurrentCulture();
public string TimeRemaining => DateTime.UtcNow > Expires ? "" : $"{((Expires ?? DateTime.MaxValue).Year == DateTime.MaxValue.Year ? TimePunishedString : ((Expires ?? DateTime.MaxValue) - DateTime.UtcNow).HumanizeForCurrentCulture())}";
public bool Expired => Expires.HasValue && Expires <= DateTime.UtcNow;
public DateTime? Expires { get; set; }
public override bool Sensitive => PenaltyType == PenaltyType.Flag || PenaltyType == PenaltyType.Unflag;

View File

@ -1,8 +1,8 @@
using System;
using SharedLibraryCore.Database.Models;
using SharedLibraryCore.Dtos.Meta.Responses;
using SharedLibraryCore.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SharedLibraryCore.Dtos
{
@ -19,11 +19,13 @@ namespace SharedLibraryCore.Dtos
public bool HasActivePenalty { get; set; }
public string ActivePenaltyType { get; set; }
public bool Authenticated { get; set; }
public List<ProfileMeta> Meta { get; set; }
public List<InformationResponse> Meta { get; set; }
public EFPenalty ActivePenalty { get; set; }
public bool Online { get; set; }
public string TimeOnline { get; set; }
public DateTime LastConnection { get; set; }
public string LastConnectionText => Utilities.GetTimePassed(LastConnection, true);
public string LastConnectionText => (DateTime.UtcNow - LastConnection).HumanizeForCurrentCulture();
public IDictionary<int, long> LinkedAccounts { get; set; }
public MetaType? MetaFilterType { get; set; }
}
}

View File

@ -1,32 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SharedLibraryCore.Dtos
{
public class ProfileMeta : SharedInfo
{
public enum MetaType
{
Other,
Information,
AliasUpdate,
ChatMessage,
Penalized,
ReceivedPenalty,
QuickMessage
}
public DateTime When { get; set; }
public string WhenString => Utilities.GetTimePassed(When, false);
public string Key { get; set; }
public dynamic Value { get; set; }
public string Extra { get; set; }
public virtual string Class => Value.GetType().ToString();
public MetaType Type { get; set; }
public int? Column { get; set; }
public int? Order { get; set; }
}
}

View File

@ -1,4 +1,6 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using SharedLibraryCore.Dtos.Meta.Responses;
namespace SharedLibraryCore.Helpers
{

View File

@ -14,6 +14,6 @@ namespace SharedLibraryCore.Interfaces
/// </summary>
/// <param name="paginationInfo">pagination info</param>
/// <returns></returns>
Task<IList<AuditInfo>> ListAuditInformation(PaginationInfo paginationInfo);
Task<IList<AuditInfo>> ListAuditInformation(PaginationRequest paginationInfo);
}
}

View File

@ -0,0 +1,31 @@
using System;
namespace SharedLibraryCore.Interfaces
{
/// <summary>
/// describes all the base attributes of a client meta object
/// </summary>
public interface IClientMeta
{
MetaType Type { get; }
DateTime When { get; }
bool IsSensitive { get; }
bool ShouldDisplay { get; }
// sorting purposes
public int? Column { get; set; }
public int? Order { get; set; }
}
public enum MetaType
{
Other,
Information,
AliasUpdate,
ChatMessage,
Penalized,
ReceivedPenalty,
QuickMessage
}
}

View File

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace SharedLibraryCore.Interfaces
{
public interface IClientMetaResponse
{
int ClientId { get;}
int MetaId { get; }
}
}

View File

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace SharedLibraryCore.Interfaces
{
public interface IMetaRegistration
{
void Register();
}
}

View File

@ -0,0 +1,51 @@
using SharedLibraryCore.Database.Models;
using SharedLibraryCore.Dtos;
using SharedLibraryCore.QueryHelper;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace SharedLibraryCore.Interfaces
{
public interface IMetaService
{
/// <summary>
/// adds or updates meta key and value to the database
/// </summary>
/// <param name="metaKey">key of meta data</param>
/// <param name="metaValue">value of the meta data</param>
/// <param name="client">client to save the meta for</param>
/// <returns></returns>
Task AddPersistentMeta(string metaKey, string metaValue, EFClient client);
/// <summary>
/// retrieves meta data for given client and key
/// </summary>
/// <param name="metaKey">key to retrieve value for</param>
/// <param name="client">client to retrieve meta for</param>
/// <returns></returns>
Task<EFMeta> GetPersistentMeta(string metaKey, EFClient client);
/// <summary>
/// adds a meta task to the runtime meta list
/// </summary>
/// <param name="metaKey">type of meta</param>
/// <param name="metaAction">action to perform</param>
void AddRuntimeMeta<T,V>(MetaType metaKey, Func<T, Task<IEnumerable<V>>> metaAction) where V : IClientMeta where T: PaginationRequest;
/// <summary>
/// retrieves all the runtime meta information for given client idea
/// </summary>
/// <param name="request">request information</param>
/// <returns></returns>
Task<IEnumerable<IClientMeta>> GetRuntimeMeta(ClientPaginationRequest request);
/// <summary>
/// retreives all the runtime of provided type
/// </summary>
/// <param name="request">>request information</param>
/// <param name="metaType">type of meta to retreive</param>
/// <returns></returns>
Task<IEnumerable<T>> GetRuntimeMeta<T>(ClientPaginationRequest request, MetaType metaType) where T : IClientMeta;
}
}

View File

@ -1,12 +1,23 @@
using SharedLibraryCore.Interfaces;
using System.Collections.Generic;
using System.Globalization;
namespace SharedLibraryCore.Localization
{
public class Layout
{
public string LocalizationName { get; set; }
private string localizationName;
public string LocalizationName
{
get => localizationName;
set
{
localizationName = value;
Culture = new CultureInfo(value);
}
}
public TranslationLookup LocalizationIndex { get; set; }
public CultureInfo Culture { get; private set; }
public Layout(Dictionary<string, string> set)
{

View File

@ -618,7 +618,7 @@ namespace SharedLibraryCore.Database.Models
if (tempbanPenalty != null)
{
CurrentServer.Logger.WriteDebug($"Kicking {this} because their GUID is temporarily banned");
Kick($"{loc["SERVER_TB_REMAIN"]} ({(tempbanPenalty.Expires.Value - DateTime.UtcNow).TimeSpanText()} {loc["WEBFRONT_PENALTY_TEMPLATE_REMAINING"]})", autoKickClient);
Kick($"{loc["SERVER_TB_REMAIN"]} ({(tempbanPenalty.Expires.Value - DateTime.UtcNow).HumanizeForCurrentCulture()} {loc["WEBFRONT_PENALTY_TEMPLATE_REMAINING"]})", autoKickClient);
return false;
}

View File

@ -0,0 +1,12 @@
using SharedLibraryCore.Dtos;
using System;
using System.Collections.Generic;
using System.Text;
namespace SharedLibraryCore.QueryHelper
{
public class ClientPaginationRequest : PaginationRequest
{
public int ClientId { get; set; }
}
}

View File

@ -20,7 +20,7 @@ namespace SharedLibraryCore.Repositories
}
/// <inheritdoc/>
public async Task<IList<AuditInfo>> ListAuditInformation(PaginationInfo paginationInfo)
public async Task<IList<AuditInfo>> ListAuditInformation(PaginationRequest paginationInfo)
{
using (var ctx = _contextFactory.CreateContext(enableTracking: false))
{

View File

@ -1,169 +0,0 @@
using Microsoft.EntityFrameworkCore;
using SharedLibraryCore.Database;
using SharedLibraryCore.Database.Models;
using SharedLibraryCore.Dtos;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace SharedLibraryCore.Services
{
public class MetaService
{
private static List<Func<int, int, int, DateTime?, Task<List<ProfileMeta>>>> _metaActions = new List<Func<int, int, int, DateTime?, Task<List<ProfileMeta>>>>();
/// <summary>
/// adds or updates meta key and value to the database
/// </summary>
/// <param name="metaKey">key of meta data</param>
/// <param name="metaValue">value of the meta data</param>
/// <param name="client">client to save the meta for</param>
/// <returns></returns>
public async Task AddPersistentMeta(string metaKey, string metaValue, EFClient client)
{
// this seems to happen if the client disconnects before they've had time to authenticate and be added
if (client.ClientId < 1)
{
return;
}
using (var ctx = new DatabaseContext())
{
var existingMeta = await ctx.EFMeta
.Where(_meta => _meta.Key == metaKey)
.Where(_meta => _meta.ClientId == client.ClientId)
.FirstOrDefaultAsync();
if (existingMeta != null)
{
existingMeta.Value = metaValue;
existingMeta.Updated = DateTime.UtcNow;
}
else
{
ctx.EFMeta.Add(new EFMeta()
{
ClientId = client.ClientId,
Created = DateTime.UtcNow,
Key = metaKey,
Value = metaValue
});
}
await ctx.SaveChangesAsync();
}
}
internal static void Clear()
{
_metaActions.Clear();
}
/// <summary>
/// retrieves meta data for given client and key
/// </summary>
/// <param name="metaKey">key to retrieve value for</param>
/// <param name="client">client to retrieve meta for</param>
/// <returns></returns>
public async Task<EFMeta> GetPersistentMeta(string metaKey, EFClient client)
{
using (var ctx = new DatabaseContext(disableTracking: true))
{
return await ctx.EFMeta
.Where(_meta => _meta.Key == metaKey)
.Where(_meta => _meta.ClientId == client.ClientId)
.Select(_meta => new EFMeta()
{
MetaId = _meta.MetaId,
Key = _meta.Key,
ClientId = _meta.ClientId,
Value = _meta.Value
})
.FirstOrDefaultAsync();
}
}
/// <summary>
/// aads a meta task to the runtime meta list
/// </summary>
/// <param name="metaAction"></param>
public static void AddRuntimeMeta(Func<int, int, int, DateTime?, Task<List<ProfileMeta>>> metaAction)
{
_metaActions.Add(metaAction);
}
/// <summary>
/// retrieves all the runtime meta information for given client idea
/// </summary>
/// <param name="clientId">id of the client</param>
/// <param name="count">number of meta items to retrieve</param>
/// <param name="offset">offset from the first item</param>
/// <returns></returns>
public static async Task<List<ProfileMeta>> GetRuntimeMeta(int clientId, int offset = 0, int count = int.MaxValue, DateTime? startAt = null)
{
var meta = new List<ProfileMeta>();
foreach (var action in _metaActions)
{
var metaItems = await action(clientId, offset, count, startAt);
meta.AddRange(metaItems);
}
if (count == 1)
{
var table = new List<List<ProfileMeta>>();
var metaWithColumn = meta
.Where(_meta => _meta.Column != null);
var columnGrouping = metaWithColumn
.GroupBy(_meta => _meta.Column);
var metaToSort = meta.Except(metaWithColumn).ToList();
foreach (var metaItem in columnGrouping)
{
table.Add(new List<ProfileMeta>(metaItem));
}
while (metaToSort.Count > 0)
{
var sortingMeta = metaToSort.First();
int indexOfSmallestColumn()
{
int index = 0;
int smallestColumnSize = int.MaxValue;
for (int i = 0; i < table.Count; i++)
{
if (table[i].Count < smallestColumnSize)
{
smallestColumnSize = table[i].Count;
index = i;
}
}
return index;
}
int columnIndex = indexOfSmallestColumn();
sortingMeta.Column = columnIndex;
sortingMeta.Order = columnGrouping
.First(_group => _group.Key == columnIndex)
.Count();
table[columnIndex].Add(sortingMeta);
metaToSort.Remove(sortingMeta);
}
return meta;
}
return meta.OrderByDescending(_meta => _meta.When)
.Take(count)
.ToList();
}
}
}

View File

@ -6,7 +6,7 @@
<ApplicationIcon />
<StartupObject />
<PackageId>RaidMax.IW4MAdmin.SharedLibraryCore</PackageId>
<Version>2.4.3</Version>
<Version>2.4.6</Version>
<Authors>RaidMax</Authors>
<Company>Forever None</Company>
<Configurations>Debug;Release;Prerelease</Configurations>
@ -20,8 +20,8 @@
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<Description>Shared Library for IW4MAdmin</Description>
<AssemblyVersion>2.4.3.0</AssemblyVersion>
<FileVersion>2.4.3.0</FileVersion>
<AssemblyVersion>2.4.6.0</AssemblyVersion>
<FileVersion>2.4.6.0</FileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Prerelease|AnyCPU'">
@ -30,30 +30,33 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentValidation" Version="8.6.2" />
<PackageReference Include="FluentValidation" Version="9.1.2" />
<PackageReference Include="Humanizer.Core" Version="2.8.26" />
<PackageReference Include="Humanizer.Core.pt" Version="2.8.26" />
<PackageReference Include="Humanizer.Core.ru" Version="2.8.26" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.2.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.3">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="3.1.3" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.3" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="3.1.3" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="3.1.3" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.1.3" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="3.1.3" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="3.1.7" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.7" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="3.1.7" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="3.1.7" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.1.7" />
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="3.1.7" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="Npgsql" Version="4.1.3.1" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="3.1.3" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="3.1.1" />
<PackageReference Include="Npgsql" Version="4.1.4" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="3.1.4" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="3.1.2" />
<PackageReference Include="SimpleCrypto.NetCore" Version="1.0.0" />
</ItemGroup>
<ItemGroup Condition="'$(Configuration)'=='Debug'">
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="3.1.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="3.1.7" />
</ItemGroup>
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">

View File

@ -1,5 +1,8 @@

using Humanizer;
using Humanizer.Localisation;
using SharedLibraryCore.Database.Models;
using SharedLibraryCore.Dtos.Meta;
using SharedLibraryCore.Helpers;
using SharedLibraryCore.Interfaces;
using System;
@ -381,57 +384,6 @@ namespace SharedLibraryCore
return !ip.HasValue ? "" : new IPAddress(BitConverter.GetBytes(ip.Value)).ToString();
}
public static string GetTimePassed(DateTime start)
{
return GetTimePassed(start, true);
}
public static string GetTimePassed(DateTime start, bool includeAgo)
{
TimeSpan Elapsed = DateTime.UtcNow - start;
string ago = includeAgo ? $" {CurrentLocalization.LocalizationIndex["WEBFRONT_PENALTY_TEMPLATE_AGO"]}" : "";
if (Elapsed.TotalSeconds < 30)
{
return CurrentLocalization.LocalizationIndex["GLOBAL_TIME_JUSTNOW"] + ago;
}
if (Elapsed.TotalMinutes < 120)
{
if (Elapsed.TotalMinutes < 1.5)
{
return $"1 {CurrentLocalization.LocalizationIndex["GLOBAL_TIME_MINUTES"]}{ago}";
}
return Math.Round(Elapsed.TotalMinutes, 0) + $" {CurrentLocalization.LocalizationIndex["GLOBAL_TIME_MINUTES"]}{ago}";
}
if (Elapsed.TotalHours <= 24)
{
if (Elapsed.TotalHours < 1.5)
{
return $"1 {CurrentLocalization.LocalizationIndex["GLOBAL_TIME_HOURS"]}{ago}";
}
return Math.Round(Elapsed.TotalHours, 0) + $" { CurrentLocalization.LocalizationIndex["GLOBAL_TIME_HOURS"]}{ago}";
}
if (Elapsed.TotalDays <= 90)
{
if (Elapsed.TotalDays < 1.5)
{
return $"1 {CurrentLocalization.LocalizationIndex["GLOBAL_TIME_DAYS"]}{ago}";
}
return Math.Round(Elapsed.TotalDays, 0) + $" {CurrentLocalization.LocalizationIndex["GLOBAL_TIME_DAYS"]}{ago}";
}
if (Elapsed.TotalDays <= 365)
{
return $"{Math.Round(Elapsed.TotalDays / 7)} {CurrentLocalization.LocalizationIndex["GLOBAL_TIME_WEEKS"]}{ago}";
}
else
{
return $"{Math.Round(Elapsed.TotalDays / 30, 0)} {CurrentLocalization.LocalizationIndex["GLOBAL_TIME_MONTHS"]}{ago}";
}
}
public static Game GetGame(string gameName)
{
if (string.IsNullOrEmpty(gameName))
@ -519,42 +471,6 @@ namespace SharedLibraryCore
return new TimeSpan(1, 0, 0);
}
public static string TimeSpanText(this TimeSpan span)
{
var loc = CurrentLocalization.LocalizationIndex;
if (span.TotalMinutes < 60)
{
return $"{span.Minutes} {loc["GLOBAL_TIME_MINUTES"]}";
}
else if (span.Hours >= 1 && span.TotalHours < 24)
{
return $"{span.Hours} {loc["GLOBAL_TIME_HOURS"]}";
}
else if (span.TotalDays >= 1 && span.TotalDays < 7)
{
return $"{span.Days} {loc["GLOBAL_TIME_DAYS"]}";
}
else if (span.TotalDays >= 7 && span.TotalDays < 90)
{
return $"{Math.Round(span.Days / 7.0, 0)} {loc["GLOBAL_TIME_WEEKS"]}";
}
else if (span.TotalDays >= 90 && span.TotalDays < 365)
{
return $"{Math.Round(span.Days / 30.0, 0)} {loc["GLOBAL_TIME_MONTHS"]}";
}
else if (span.TotalDays >= 365 && span.TotalDays < 36500)
{
return $"{Math.Round(span.Days / 365.0, 0)} {loc["GLOBAL_TIME_YEARS"]}";
}
else if (span.TotalDays >= 36500)
{
return loc["GLOBAL_TIME_FOREVER"];
}
return "unknown";
}
/// <summary>
/// returns a list of penalty types that should be shown across all profiles
/// </summary>
@ -932,7 +848,7 @@ namespace SharedLibraryCore
/// <param name="penalty"></param>
/// <param name="penaltyService"></param>
/// <param name="logger"></param>
/// <returns>true of the creat succeeds, false otherwise</returns>
/// <returns>true of the create succeeds, false otherwise</returns>
public static async Task<bool> TryCreatePenalty(this EFPenalty penalty, IEntityService<EFPenalty> penaltyService, ILogger logger)
{
try
@ -969,7 +885,50 @@ namespace SharedLibraryCore
}
public static bool ShouldHideLevel(this Permission perm) => perm == Permission.Flagged;
/// <summary>
/// parses translation string into tokens that are able to be formatted by the webfront
/// </summary>
/// <param name="translationKey">key for translation lookup</param>
/// <returns></returns>
public static WebfrontTranslationHelper[] SplitTranslationTokens(string translationKey)
{
string translationString = CurrentLocalization.LocalizationIndex[translationKey];
var builder = new StringBuilder();
var results = new List<WebfrontTranslationHelper>();
foreach (string word in translationString.Split(' '))
{
string finalWord = word;
if ((word.StartsWith("{{") && !word.EndsWith("}}")) ||
(builder.Length > 0 && !word.EndsWith("}}")))
{
builder.Append($"{word} ");
continue;
}
if (builder.Length > 0)
{
builder.Append(word);
finalWord = builder.ToString();
builder.Clear();
}
var match = Regex.Match(finalWord, @"{{([^}|^-]+)(?:->)([^}]+)}}|{{([^}]+)}}");
bool isInterpolation = match.Success;
results.Add(new WebfrontTranslationHelper
{
IsInterpolation = isInterpolation,
MatchValue = isInterpolation ? match.Groups[3].Length > 0 ? match.Groups[3].ToString() : match.Groups[1].ToString() : finalWord,
TranslationValue = isInterpolation && match.Groups[2].Length > 0 ? match.Groups[2].ToString() : ""
});
}
return results.ToArray();
}
/// <summary>
/// indicates if running in development mode
/// </summary>
@ -991,5 +950,27 @@ namespace SharedLibraryCore
return path;
}
/// <summary>
/// wrapper method for humanizee that uses current current culture
/// </summary>
public static string HumanizeForCurrentCulture(this TimeSpan timeSpan, int precision = 1, TimeUnit maxUnit = TimeUnit.Week,
TimeUnit minUnit = TimeUnit.Millisecond, string collectionSeparator = ", ", bool toWords = false)
{
return timeSpan.Humanize(precision, CurrentLocalization.Culture, maxUnit, minUnit, collectionSeparator, toWords);
}
/// <summary>
/// wrapper method for humanizee that uses current current culture
/// </summary>
public static string HumanizeForCurrentCulture(this DateTime input, bool utcDate = true, DateTime? dateToCompareAgainst = null, CultureInfo culture = null)
{
return input.Humanize(utcDate, dateToCompareAgainst, CurrentLocalization.Culture);
}
public static string ToTranslatedName(this MetaType metaType)
{
return CurrentLocalization.LocalizationIndex[$"META_TYPE_{metaType.ToString().ToUpper()}_NAME"];
}
}
}