=== Summary: 675 files | 7 generated | 484 fresh | 4605 untracked | 4268 adopted | 355 marked | 466 validated-ok | 2+0 stale (sig+body) | 0 skipped | 0 failed | elapsed 11:08:11.442 (40091.44s) ===
This commit is contained in:
@@ -8,6 +8,7 @@ namespace adas_core.Domain.Utils;
|
||||
/// <remarks>
|
||||
/// This class is sealed and cannot be inherited.
|
||||
/// </remarks>
|
||||
/// <!-- aidoc:v1 sig=830b168 -->
|
||||
public sealed class AuthUtils
|
||||
{
|
||||
private LoginResponse _loginResponse = new();
|
||||
@@ -55,6 +56,7 @@ public sealed class AuthUtils
|
||||
/// Retrieves the current <see cref="LoginResponse"/> in a thread-safe manner by acquiring a lock on the underlying field.
|
||||
/// </summary>
|
||||
/// <returns>The current <see cref="LoginResponse"/> instance.</returns>
|
||||
/// <!-- aidoc:v1 sig=041b791 body=ad62115 -->
|
||||
public LoginResponse GetLoginResponse()
|
||||
{
|
||||
lock (_loginResponse)
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace adas_core.Domain.Utils;
|
||||
/// <summary>
|
||||
/// Provides static utility methods for working with BSON (Binary JSON) data.
|
||||
/// </summary>
|
||||
/// <!-- aidoc:v1 sig=bd71742 -->
|
||||
public static class BsonUtils
|
||||
{
|
||||
/// <summary>
|
||||
@@ -12,6 +13,7 @@ public static class BsonUtils
|
||||
/// </summary>
|
||||
/// <param name="val">The <see cref="BsonValue"/> instance to convert to a CLR object.</param>
|
||||
/// <returns>The underlying CLR value when <paramref name="val"/> is an Int32, Int64, Double, valid DateTime (in UTC), or String; otherwise <see langword="null"/>.</returns>
|
||||
/// <!-- aidoc:v1 sig=29fed77 body=dde4c14 -->
|
||||
public static object? ToObject(this BsonValue val)
|
||||
{
|
||||
if (val.IsInt32) return val.AsInt32;
|
||||
@@ -33,6 +35,7 @@ public static class BsonUtils
|
||||
/// <param name="doc">The BSON document to search for the key.</param>
|
||||
/// <param name="key">The key of the value to retrieve.</param>
|
||||
/// <returns>The <see cref="BsonValue"/> associated with <paramref name="key"/>, or <c>null</c> if the key does not exist.</returns>
|
||||
/// <!-- aidoc:v1 sig=1ab6e35 body=441c98c -->
|
||||
public static BsonValue? Get(this BsonDocument doc, string key)
|
||||
{
|
||||
return doc.TryGetValue(key, out var value) ? value : null;
|
||||
|
||||
@@ -14,6 +14,7 @@ namespace adas_core.Domain.Utils
|
||||
/// - Caída a GlobalSeconds del backend si no hay TTL específico
|
||||
/// - Si el TTL resultante es null o menor o igual a 0 sin expiración
|
||||
/// </summary>
|
||||
/// <!-- aidoc:v1 sig=d7c4909 -->
|
||||
public static class CacheKeyTtl
|
||||
{
|
||||
/// <summary>
|
||||
@@ -21,6 +22,7 @@ namespace adas_core.Domain.Utils
|
||||
/// </summary>
|
||||
/// <param name="seconds">The number of seconds to convert.</param>
|
||||
/// <returns>A <see cref="TimeSpan"/> representing <paramref name="seconds"/>, or <c>null</c> when <paramref name="seconds"/> is <c>null</c> or less than or equal to zero.</returns>
|
||||
/// <!-- aidoc:v1 sig=967178f -->
|
||||
private static TimeSpan? SecondsOrNull(int? seconds)
|
||||
=> seconds is > 0
|
||||
? TimeSpan.FromSeconds(seconds.Value)
|
||||
@@ -32,6 +34,7 @@ namespace adas_core.Domain.Utils
|
||||
/// <param name="selector">A function that selects the desired <see cref="int?"/> value from a <see cref="TtlSettings"/> instance.</param>
|
||||
/// <param name="s">The cache settings whose in-memory TTL configuration is used as the source.</param>
|
||||
/// <returns>The nullable integer value produced by applying <paramref name="selector"/> to the in-memory <see cref="TtlSettings"/>.</returns>
|
||||
/// <!-- aidoc:v1 sig=a263f69 -->
|
||||
private static int? FromInMemory(Func<TtlSettings, int?> selector, CacheSettings s)
|
||||
=> selector(s.InMemory.Ttl);
|
||||
|
||||
@@ -42,6 +45,7 @@ namespace adas_core.Domain.Utils
|
||||
/// <param name="selector">A function that derives a nullable integer from a <see cref="TtlSettings"/> instance, or null to short-circuit the operation.</param>
|
||||
/// <param name="s">The cache settings whose Redis TTL configuration will be inspected, or null to use a default <see cref="TtlSettings"/>.</param>
|
||||
/// <returns>The nullable integer produced by invoking the selector on the resolved <see cref="TtlSettings"/>, or null if the selector is null.</returns>
|
||||
/// <!-- aidoc:v1 sig=219e390 -->
|
||||
private static int? FromRedis(Func<TtlSettings, int?>? selector, CacheSettings? s)
|
||||
=> selector?.Invoke(s?.Redis.Ttl ?? new TtlSettings());
|
||||
|
||||
@@ -50,6 +54,7 @@ namespace adas_core.Domain.Utils
|
||||
/// </summary>
|
||||
/// <param name="s">The cache settings containing the in-memory TTL configuration, or <c>null</c>.</param>
|
||||
/// <returns>A <see cref="TimeSpan"/> representing the global in-memory TTL converted from seconds, or <c>null</c> if <paramref name="s"/> is <c>null</c> or the global seconds value is not set.</returns>
|
||||
/// <!-- aidoc:v1 sig=08c6cf7 -->
|
||||
private static TimeSpan? GlobalInMemory(CacheSettings? s)
|
||||
=> SecondsOrNull(s?.InMemory.Ttl.GlobalSeconds);
|
||||
|
||||
@@ -58,12 +63,19 @@ namespace adas_core.Domain.Utils
|
||||
/// </summary>
|
||||
/// <param name="s">The cache settings containing the Redis TTL configuration, or <c>null</c>.</param>
|
||||
/// <returns>A <see cref="TimeSpan"/> representing the global Redis TTL, or <c>null</c> if the configuration is unavailable.</returns>
|
||||
/// <!-- aidoc:v1 sig=3ee947c -->
|
||||
private static TimeSpan? GlobalRedis(CacheSettings? s)
|
||||
=> SecondsOrNull(s?.Redis.Ttl.GlobalSeconds);
|
||||
|
||||
/// <summary>
|
||||
/// Resuelve TTL para una entidad concreta, respetando el backend configurado para dicha entidad.
|
||||
/// </summary>
|
||||
/// <!-- aidoc-review:v1 severity=medium kind=missing_param
|
||||
/// "Parameter 'settings' (CacheSettings?) is not documented." -->
|
||||
/// <!-- aidoc-review:v1 severity=medium kind=missing_param
|
||||
/// "Parameter 'entity' (CacheEnum.EntityType) is not documented." -->
|
||||
/// <!-- aidoc-review:v1 severity=medium kind=missing_returns
|
||||
/// "Return value (TimeSpan?) is not documented." -->
|
||||
public static TimeSpan? ResolveForEntity(CacheSettings? settings, CacheEnum.EntityType entity)
|
||||
{
|
||||
// Selección del backend según la entidad
|
||||
@@ -115,6 +127,7 @@ namespace adas_core.Domain.Utils
|
||||
/// <summary>
|
||||
/// Dada una clave, clasifica la entidad y resuelve el TTL para esa clave.
|
||||
/// </summary>
|
||||
/// <!-- aidoc:v1 sig=e7e1d98 body=1fb058f -->
|
||||
public static TimeSpan? ResolveForKey(CacheSettings settings, string key)
|
||||
{
|
||||
var entity = CacheKeyClassifier.Classify(key);
|
||||
@@ -129,6 +142,7 @@ namespace adas_core.Domain.Utils
|
||||
/// - Prefijos normalizados para que el CacheDispatcher clasifique el backend.
|
||||
/// - Overloads "KeyWithTtl" para devolver (key, ttl) en una llamada.
|
||||
/// </summary>
|
||||
/// <!-- aidoc:v1 sig=6c8a7c2 -->
|
||||
public static class CacheKeys
|
||||
{
|
||||
#region ConfigObservations
|
||||
@@ -137,6 +151,7 @@ namespace adas_core.Domain.Utils
|
||||
/// Returns the configuration key string "configObservations:all", typically used to identify a setting or cache entry related to all configuration observations.
|
||||
/// </summary>
|
||||
/// <returns>The string "configObservations:all".</returns>
|
||||
/// <!-- aidoc:v1 sig=588468f -->
|
||||
public static string ConfigObservationsAll()
|
||||
=> "configObservations:all";
|
||||
|
||||
@@ -163,6 +178,7 @@ namespace adas_core.Domain.Utils
|
||||
/// </summary>
|
||||
/// <param name="displayId">The identifier of the display whose base key is being generated.</param>
|
||||
/// <returns>A formatted key string combining the display section, the display identifier, and the "base" suffix.</returns>
|
||||
/// <!-- aidoc:v1 sig=c78d13f -->
|
||||
public static string DisplayBase(ObjectId displayId)
|
||||
=> $"configDisplays:display:{displayId}:base";
|
||||
|
||||
@@ -172,6 +188,7 @@ namespace adas_core.Domain.Utils
|
||||
/// <param name="settings">Optional cache settings used to resolve the TTL for display entities. When null, a default TTL is applied.</param>
|
||||
/// <param name="displayId">The identifier of the display used to compose the base cache key.</param>
|
||||
/// <returns>A tuple containing the generated cache key and the resolved TTL for the display entity.</returns>
|
||||
/// <!-- aidoc:v1 sig=506cbc3 body=cd54390 -->
|
||||
public static (string Key, TimeSpan? Ttl) DisplayBaseKeyWithTtl(
|
||||
CacheSettings? settings,
|
||||
ObjectId displayId)
|
||||
@@ -186,6 +203,7 @@ namespace adas_core.Domain.Utils
|
||||
/// </summary>
|
||||
/// <param name="displayId">The identifier of the display whose configuration key is being generated.</param>
|
||||
/// <returns>A formatted string key in the form "configDisplays:display:{displayId}:config" representing the display's configuration entry.</returns>
|
||||
/// <!-- aidoc:v1 sig=034d7aa -->
|
||||
public static string DisplayWithConfig(ObjectId displayId)
|
||||
=> $"configDisplays:display:{displayId}:config";
|
||||
|
||||
@@ -195,6 +213,7 @@ namespace adas_core.Domain.Utils
|
||||
/// <param name="settings">The cache settings used to resolve the TTL for the display entity; may be <c>null</c>.</param>
|
||||
/// <param name="displayId">The identifier of the display entity for which the cache key is generated.</param>
|
||||
/// <returns>A tuple containing the generated cache key and the resolved TTL, which may be <c>null</c> if no TTL is configured.</returns>
|
||||
/// <!-- aidoc:v1 sig=1334a3e body=0bbecb4 -->
|
||||
public static (string Key, TimeSpan? Ttl) DisplayWithConfigKeyWithTtl(
|
||||
CacheSettings? settings,
|
||||
ObjectId displayId)
|
||||
@@ -212,6 +231,7 @@ namespace adas_core.Domain.Utils
|
||||
/// </summary>
|
||||
/// <param name="pocId">The unique identifier of the Point of Care entity whose base reference key is being generated.</param>
|
||||
/// <returns>A formatted string that combines the "pointOfCare" prefix, the provided <paramref name="pocId"/>, and the "base" suffix to uniquely identify the base resource of the Point of Care.</returns>
|
||||
/// <!-- aidoc:v1 sig=76872a0 -->
|
||||
public static string PointOfCareBase(ObjectId pocId)
|
||||
=> $"pointOfCare:{pocId}:base";
|
||||
|
||||
@@ -221,6 +241,7 @@ namespace adas_core.Domain.Utils
|
||||
/// <param name="settings">The cache settings used by the TTL resolver. May be null, in which case the resolver falls back to its default behavior.</param>
|
||||
/// <param name="pocId">The identifier of the Point of Care entity used to generate the cache key.</param>
|
||||
/// <returns>A tuple containing the generated cache key and the resolved TTL, which may be null when no expiration is configured.</returns>
|
||||
/// <!-- aidoc:v1 sig=b4d58ed body=d0c1f0e -->
|
||||
public static (string Key, TimeSpan? Ttl) PointOfCareBaseKeyWithTtl(
|
||||
CacheSettings? settings, ObjectId pocId)
|
||||
{
|
||||
@@ -234,6 +255,7 @@ namespace adas_core.Domain.Utils
|
||||
/// </summary>
|
||||
/// <param name="pocId">The identifier of the point of care used to compose the cache key.</param>
|
||||
/// <returns>A formatted cache key string in the form <c>pointOfCare:{pocId}:withInfo</c>.</returns>
|
||||
/// <!-- aidoc:v1 sig=373f954 -->
|
||||
public static string PointOfCareWithInfoKeyWithTtl(ObjectId pocId)
|
||||
=> $"pointOfCare:{pocId}:withInfo";
|
||||
|
||||
@@ -243,6 +265,7 @@ namespace adas_core.Domain.Utils
|
||||
/// <param name="settings">Optional cache settings used to resolve the TTL for the point of care entity. May be <c>null</c>.</param>
|
||||
/// <param name="pocId">The identifier of the point of care used to build the cache key.</param>
|
||||
/// <returns>A tuple containing the generated cache key and the resolved TTL, which may be <c>null</c> when no TTL is configured.</returns>
|
||||
/// <!-- aidoc:v1 sig=e93cb06 body=e1c096f -->
|
||||
public static (string Key, TimeSpan? Ttl) PointOfCareWithInfoKeyWithTtl(
|
||||
CacheSettings? settings, ObjectId pocId)
|
||||
{
|
||||
@@ -261,6 +284,7 @@ namespace adas_core.Domain.Utils
|
||||
/// <param name="fieldNames">The collection of field names to include in the key, normalized via <c>Normalize</c>.</param>
|
||||
/// <param name="last">Optional maximum number of recent observations to consider; when <c>null</c>, defaults to <c>0</c>.</param>
|
||||
/// <returns>A formatted cache key string combining the patient id, normalized field names, and the last value.</returns>
|
||||
/// <!-- aidoc:v1 sig=6571377 -->
|
||||
public static string LatestObservations(ObjectId patientId, IEnumerable<string> fieldNames, int? last = null)
|
||||
=> $"patients:latestObs:{patientId}:{Normalize(fieldNames)}:{last ?? 0}";
|
||||
|
||||
@@ -273,6 +297,7 @@ namespace adas_core.Domain.Utils
|
||||
/// <param name="fieldNames">The collection of field names to include in the latest observations cache key.</param>
|
||||
/// <param name="last">The optional number of most recent observations to consider when building the cache key.</param>
|
||||
/// <returns>A tuple containing the generated cache key and the resolved TTL for the cache entry.</returns>
|
||||
/// <!-- aidoc:v1 sig=c42ebf0 body=17e9521 -->
|
||||
public static (string Key, TimeSpan? Ttl) LatestObservationsKeyWithTtl(
|
||||
CacheSettings? settings, ObjectId patientId, IEnumerable<string> fieldNames, int? last = null)
|
||||
{
|
||||
@@ -290,6 +315,7 @@ namespace adas_core.Domain.Utils
|
||||
/// <param name="patientId">The unique identifier of the patient whose latest pump observations are being requested.</param>
|
||||
/// <param name="last">The optional number of most recent pump observation entries to include; when null, zero is used as a fallback.</param>
|
||||
/// <returns>A formatted cache key string of the form <c>pumpObs:latest:{patientId}:{last}</c>, with <c>last</c> resolved to <c>0</c> when null.</returns>
|
||||
/// <!-- aidoc:v1 sig=b2d398b -->
|
||||
public static string LatestPumps(ObjectId patientId, int? last = null)
|
||||
=> $"pumpObs:latest:{patientId}:{last ?? 0}";
|
||||
|
||||
@@ -300,6 +326,7 @@ namespace adas_core.Domain.Utils
|
||||
/// <param name="patientId">The identifier of the patient whose latest pump observations are being cached.</param>
|
||||
/// <param name="last">The optional maximum number of latest pump entries to include in the cache key.</param>
|
||||
/// <returns>A tuple containing the generated cache key and the resolved TTL, which may be <see langword="null"/> if no TTL is configured.</returns>
|
||||
/// <!-- aidoc:v1 sig=480ebe1 body=28bba9f -->
|
||||
public static (string Key, TimeSpan? Ttl) LatestPumpsKeyWithTtl(
|
||||
CacheSettings settings, ObjectId patientId, int? last = null)
|
||||
{
|
||||
@@ -316,6 +343,7 @@ namespace adas_core.Domain.Utils
|
||||
/// </summary>
|
||||
/// <param name="patientId">The unique identifier of the patient whose appointments are being keyed.</param>
|
||||
/// <returns>A formatted cache key string combining the patient identifier and the current UTC date.</returns>
|
||||
/// <!-- aidoc:v1 sig=5ef1337 body=ac8edc0 -->
|
||||
public static string PatientAppointmentsToday(ObjectId patientId)
|
||||
{
|
||||
var dateKey = DateTime.UtcNow.ToString("yyyyMMdd");
|
||||
@@ -328,6 +356,7 @@ namespace adas_core.Domain.Utils
|
||||
/// <param name="settings">Optional cache settings used to resolve the TTL for the appointments entity.</param>
|
||||
/// <param name="patientId">The identifier of the patient whose appointments cache key is being generated.</param>
|
||||
/// <returns>A tuple containing the generated cache key and the resolved TTL, which may be null when no TTL is configured.</returns>
|
||||
/// <!-- aidoc:v1 sig=ff8616a body=e708272 -->
|
||||
public static (string Key, TimeSpan? Ttl) PatientAppointmentsTodayKeyWithTtl(
|
||||
CacheSettings? settings,
|
||||
ObjectId patientId)
|
||||
@@ -342,6 +371,7 @@ namespace adas_core.Domain.Utils
|
||||
/// </summary>
|
||||
/// <param name="pocId">The identifier of the Point of Contact whose appointments are being keyed.</param>
|
||||
/// <returns>A formatted cache key string combining the PoC identifier and today's UTC date in <c>yyyyMMdd</c> format.</returns>
|
||||
/// <!-- aidoc:v1 sig=86e2e65 body=2c278cf -->
|
||||
public static string PocAppointmentsToday(ObjectId pocId)
|
||||
{
|
||||
var dateKey = DateTime.UtcNow.ToString("yyyyMMdd");
|
||||
@@ -354,6 +384,7 @@ namespace adas_core.Domain.Utils
|
||||
/// <param name="settings">The cache settings used to resolve the TTL; may be <c>null</c> when no settings are supplied.</param>
|
||||
/// <param name="pocId">The identifier of the Point of Care whose today's appointments cache key is being generated.</param>
|
||||
/// <returns>A tuple containing the generated cache key and the resolved TTL as a nullable <see cref="TimeSpan"/>.</returns>
|
||||
/// <!-- aidoc:v1 sig=55982d2 body=03e4a32 -->
|
||||
public static (string Key, TimeSpan? Ttl) PocAppointmentsTodayKeyWithTtl(
|
||||
CacheSettings? settings,
|
||||
ObjectId pocId)
|
||||
@@ -372,6 +403,7 @@ namespace adas_core.Domain.Utils
|
||||
/// <param name="patientId">The unique identifier of the patient whose grouped observations are being addressed.</param>
|
||||
/// <param name="groupedFieldName">The name of the grouped field used to categorize the observations.</param>
|
||||
/// <returns>A formatted string in the pattern <c>groupedObs:{groupedFieldName}:patient:{patientId}</c>.</returns>
|
||||
/// <!-- aidoc:v1 sig=66bcd8e -->
|
||||
public static string GroupedObs(ObjectId patientId, string groupedFieldName)
|
||||
=> $"groupedObs:{groupedFieldName}:patient:{patientId}";
|
||||
|
||||
@@ -382,6 +414,7 @@ namespace adas_core.Domain.Utils
|
||||
/// <param name="patientId">The identifier of the patient whose grouped observations are being cached.</param>
|
||||
/// <param name="groupedFieldName">The name of the grouped field used to compose the cache key.</param>
|
||||
/// <returns>A tuple containing the generated cache key and the resolved TTL, which may be <c>null</c> when no expiry is configured.</returns>
|
||||
/// <!-- aidoc:v1 sig=2c64810 body=ce29e10 -->
|
||||
public static (string Key, TimeSpan? Ttl) GroupedObsKeyWithTtl(
|
||||
CacheSettings? settings, ObjectId patientId, string groupedFieldName)
|
||||
{
|
||||
@@ -398,6 +431,7 @@ namespace adas_core.Domain.Utils
|
||||
/// </summary>
|
||||
/// <param name="items">The collection of strings to normalize.</param>
|
||||
/// <returns>A pipe-delimited string of the cleaned and sorted values, or an empty string if no valid entries are supplied.</returns>
|
||||
/// <!-- aidoc:v1 sig=6dd057a -->
|
||||
public static string Normalize(IEnumerable<string> items)
|
||||
=> string.Join("|", items
|
||||
.Where(s => !string.IsNullOrWhiteSpace(s))
|
||||
@@ -411,6 +445,7 @@ namespace adas_core.Domain.Utils
|
||||
/// Clasificador de claves basado en prefijos.
|
||||
/// Permite al CacheDispatcher seleccionar el backend adecuado (Redis, InMemory, None).
|
||||
/// </summary>
|
||||
/// <!-- aidoc:v1 sig=933c0c4 -->
|
||||
public static class CacheKeyClassifier
|
||||
{
|
||||
/// <summary>
|
||||
@@ -421,6 +456,7 @@ namespace adas_core.Domain.Utils
|
||||
/// </summary>
|
||||
/// <param name="key">The cache key to classify.</param>
|
||||
/// <returns>The <see cref="CacheEnum.EntityType"/> that matches the key's prefix, or <see cref="CacheEnum.EntityType.Unknown"/> when no prefix is recognized.</returns>
|
||||
/// <!-- aidoc:v1 sig=8dce21c body=135a132 -->
|
||||
public static CacheEnum.EntityType Classify(string key)
|
||||
{
|
||||
if (key.StartsWith("patients:", StringComparison.OrdinalIgnoreCase))
|
||||
@@ -450,6 +486,7 @@ namespace adas_core.Domain.Utils
|
||||
/// <summary>
|
||||
/// Patrones para DeleteByPattern (Redis) u operaciones masivas por prefijo.
|
||||
/// </summary>
|
||||
/// <!-- aidoc:v1 sig=6408068 -->
|
||||
public static class CacheKeyPatterns
|
||||
{
|
||||
/// <summary>
|
||||
@@ -457,6 +494,7 @@ namespace adas_core.Domain.Utils
|
||||
/// </summary>
|
||||
/// <param name="type">The entity type for which a cache key pattern is being generated.</param>
|
||||
/// <returns>A string representing the cache key pattern associated with the given entity type, or "*" if the entity type is not recognized.</returns>
|
||||
/// <!-- aidoc:v1 sig=fc7e3c6 -->
|
||||
public static string ForEntity(CacheEnum.EntityType type)
|
||||
=> type switch
|
||||
{
|
||||
@@ -474,6 +512,7 @@ namespace adas_core.Domain.Utils
|
||||
/// </summary>
|
||||
/// <param name="prefix">The key prefix to match against.</param>
|
||||
/// <returns>A formatted string combining <paramref name="prefix"/> and ":*" used as a wildcard pattern.</returns>
|
||||
/// <!-- aidoc:v1 sig=5dfcb40 -->
|
||||
public static string ByPrefix(string prefix)
|
||||
=> $"{prefix}:*";
|
||||
|
||||
@@ -483,6 +522,7 @@ namespace adas_core.Domain.Utils
|
||||
/// <param name="prefix">The category or context prefix prepended to the pattern.</param>
|
||||
/// <param name="patientId">The patient identifier used to scope the wildcard pattern.</param>
|
||||
/// <returns>A formatted pattern string in the form <c>{prefix}:*:{patientId}*</c>.</returns>
|
||||
/// <!-- aidoc:v1 sig=1b8b063 -->
|
||||
public static string ByPatient(string prefix, string patientId)
|
||||
=> $"{prefix}:*:{patientId}*";
|
||||
|
||||
@@ -492,6 +532,7 @@ namespace adas_core.Domain.Utils
|
||||
/// <param name="prefix">The prefix segment to include at the beginning of the returned string.</param>
|
||||
/// <param name="date">The date segment to include at the end of the returned string.</param>
|
||||
/// <returns>A string formatted as <c>{prefix}:*:{date}</c>.</returns>
|
||||
/// <!-- aidoc:v1 sig=5bc6f05 -->
|
||||
public static string ByDate(string prefix, string date)
|
||||
=> $"{prefix}:*:{date}";
|
||||
}
|
||||
@@ -501,6 +542,7 @@ namespace adas_core.Domain.Utils
|
||||
/// Utilidad para extraer información estructurada útil para trazas.
|
||||
/// No usada por la lógica de caché, pero sí por logs y diagnósticos.
|
||||
/// </summary>
|
||||
/// <!-- aidoc:v1 sig=9ba5b41 -->
|
||||
public static class CacheKeyInspector
|
||||
{
|
||||
private static readonly Regex _patientRegex =
|
||||
@@ -518,6 +560,7 @@ namespace adas_core.Domain.Utils
|
||||
/// </summary>
|
||||
/// <param name="key">The input string from which to extract the patient identifier.</param>
|
||||
/// <returns>The extracted patient identifier, or <c>null</c> if no match is found.</returns>
|
||||
/// <!-- aidoc:v1 sig=1aa2718 body=b3a8f76 -->
|
||||
public static string? ExtractPatientId(string key)
|
||||
{
|
||||
var match = _patientRegex.Match(key);
|
||||
@@ -529,6 +572,7 @@ namespace adas_core.Domain.Utils
|
||||
/// </summary>
|
||||
/// <param name="key">The grouped observation key to parse.</param>
|
||||
/// <returns>A tuple containing the extracted field name and patient identifier, or <c>(null, null)</c> if the key does not match the pattern.</returns>
|
||||
/// <!-- aidoc:v1 sig=3435318 body=f175ccc -->
|
||||
public static (string? Field, string? PatientId) ExtractGroupedObservationInfo(string key)
|
||||
{
|
||||
var match = _groupedRegex.Match(key);
|
||||
@@ -543,6 +587,7 @@ namespace adas_core.Domain.Utils
|
||||
/// </summary>
|
||||
/// <param name="key">The input string expected to contain a location and a date in <c>yyyyMMdd</c> format.</param>
|
||||
/// <returns>A tuple containing the extracted <c>Location</c> string and the parsed <c>Date</c>; either value may be <c>null</c> when extraction or parsing fails.</returns>
|
||||
/// <!-- aidoc:v1 sig=45672a9 body=450f3c1 -->
|
||||
public static (string? Location, DateTime? Date) ExtractAppointmentInfo(string key)
|
||||
{
|
||||
var match = _appointmentDayRegex.Match(key);
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace adas_core.Domain.Utils;
|
||||
/// <remarks>
|
||||
/// This class is a static container for extension methods that extend the capabilities of the <see cref="CardConfig"/> type.
|
||||
/// </remarks>
|
||||
/// <!-- aidoc:v1 sig=966db52 -->
|
||||
public static class CardConfigExtensions
|
||||
{
|
||||
// Método principal para extraer todos los nombres
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace adas_core.Domain.Utils;
|
||||
/// <summary>
|
||||
/// Provides static utility methods for working with collections.
|
||||
/// </summary>
|
||||
/// <!-- aidoc:v1 sig=50818c2 -->
|
||||
public static class CollectionsUtils
|
||||
{
|
||||
/// <summary>
|
||||
@@ -12,6 +13,7 @@ public static class CollectionsUtils
|
||||
/// </summary>
|
||||
/// <param name="value">The list to evaluate.</param>
|
||||
/// <returns><see langword="true"/> if the list is null or empty; otherwise, <see langword="false"/>.</returns>
|
||||
/// <!-- aidoc:v1 sig=dfb5373 body=1cd2a38 -->
|
||||
public static bool IsNullOrEmpty<T>(this List<T>? value)
|
||||
{
|
||||
return value == null || !value.Any();
|
||||
@@ -22,6 +24,7 @@ public static class CollectionsUtils
|
||||
/// </summary>
|
||||
/// <param name="value">The list to evaluate.</param>
|
||||
/// <returns><see langword="true"/> if the list is <see langword="null"/> or empty; otherwise, <see langword="false"/>.</returns>
|
||||
/// <!-- aidoc:v1 sig=5038079 body=1cd2a38 -->
|
||||
public static bool IsEmptyOrNull<T>(List<T>? value)
|
||||
{
|
||||
return value == null || !value.Any();
|
||||
@@ -32,6 +35,7 @@ public static class CollectionsUtils
|
||||
/// </summary>
|
||||
/// <param name="value">The list to evaluate. May be <c>null</c>.</param>
|
||||
/// <returns><c>true</c> if <paramref name="value"/> is not <c>null</c> and contains one or more elements; otherwise, <c>false</c>.</returns>
|
||||
/// <!-- aidoc:v1 sig=2c3b8ff body=0269891 -->
|
||||
public static bool HasElements<T>(List<T>? value)
|
||||
{
|
||||
return value != null && value.Any();
|
||||
@@ -42,6 +46,7 @@ public static class CollectionsUtils
|
||||
/// </summary>
|
||||
/// <param name="value">The list to evaluate.</param>
|
||||
/// <returns><see langword="true"/> if the list is not null and contains at least one element; otherwise, <see langword="false"/>.</returns>
|
||||
/// <!-- aidoc:v1 sig=61945f3 body=2b7a733 -->
|
||||
public static bool IsNotEmpty<T>(List<T> value)
|
||||
{
|
||||
return !IsEmptyOrNull(value);
|
||||
@@ -52,6 +57,7 @@ public static class CollectionsUtils
|
||||
/// </summary>
|
||||
/// <param name="value">The list to evaluate; may be <see langword="null"/>.</param>
|
||||
/// <returns>The original <paramref name="value"/> if it is not null; otherwise, an empty <see cref="List{T}"/>.</returns>
|
||||
/// <!-- aidoc:v1 sig=4b33799 body=5556777 -->
|
||||
public static List<T> EmptyIfNull<T>(List<T>? value)
|
||||
{
|
||||
return value ?? [];
|
||||
@@ -62,6 +68,7 @@ public static class CollectionsUtils
|
||||
/// </summary>
|
||||
/// <param name="value">The list to evaluate.</param>
|
||||
/// <returns>The original <paramref name="value"/> when it is not null and not empty; otherwise, <c>null</c>.</returns>
|
||||
/// <!-- aidoc:v1 sig=a05f7fc body=74812a2 -->
|
||||
public static List<T>? NullIfEmpty<T>(List<T> value)
|
||||
{
|
||||
return IsEmptyOrNull(value) ? null : value;
|
||||
@@ -73,6 +80,7 @@ public static class CollectionsUtils
|
||||
/// <param name="collection">The source collection whose elements are copied into the new array.</param>
|
||||
/// <param name="type">The element <see cref="Type"/> of the array to create.</param>
|
||||
/// <returns>A new <see cref="Array"/> of the specified type containing the elements copied from the collection.</returns>
|
||||
/// <!-- aidoc:v1 sig=98732cd body=d08ef3a -->
|
||||
public static Array ToArray(ICollection collection, Type type)
|
||||
{
|
||||
var result = Array.CreateInstance(type, collection.Count);
|
||||
@@ -86,6 +94,7 @@ public static class CollectionsUtils
|
||||
/// <param name="list">The list to evaluate for a null or empty state.</param>
|
||||
/// <param name="defaultList">The fallback list returned when <paramref name="list"/> is null or empty.</param>
|
||||
/// <returns>The original <paramref name="list"/> when it contains items; otherwise <paramref name="defaultList"/>.</returns>
|
||||
/// <!-- aidoc:v1 sig=c865748 body=df53ea7 -->
|
||||
public static List<string> IfEmptyOrNull(List<string> list, List<string> defaultList)
|
||||
{
|
||||
return IsEmptyOrNull(list) ? defaultList : list;
|
||||
|
||||
@@ -10,12 +10,14 @@ namespace adas_core.Domain.Utils;
|
||||
/// <remarks>
|
||||
/// Inherits from <see cref="Dictionary{TKey, TValue}"/> and enforces that both keys and values are non-nullable.
|
||||
/// </remarks>
|
||||
/// <!-- aidoc:v1 sig=1d1f5d7 -->
|
||||
public class ComparableDictionary<TKey, TValue> : Dictionary<TKey, TValue> where TKey : notnull where TValue : notnull
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates a hash code for the collection by concatenating the string representations of all key-value pairs, separated by underscores and double percent signs, and returning the hash code of the resulting string.
|
||||
/// </summary>
|
||||
/// <returns>An integer hash code derived from the concatenated key-value pairs of the collection.</returns>
|
||||
/// <!-- aidoc:v1 sig=eb26c4a body=e3340b4 -->
|
||||
public override int GetHashCode()
|
||||
{
|
||||
StringBuilder str = new();
|
||||
|
||||
@@ -17,12 +17,14 @@ namespace adas_core.Domain.Utils;
|
||||
/// <remarks>
|
||||
/// Declared as a partial class, allowing its definition to be split across multiple files.
|
||||
/// </remarks>
|
||||
/// <!-- aidoc:v1 sig=bc11fa0 -->
|
||||
public partial class ComplexObjectValueTypeSerializer : SerializerBase<object>
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides a compiled regular expression for matching MongoDB ObjectId references, such as <c>ObjectId("...")</c>, that wrap a 24-character hexadecimal identifier.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="Regex"/> that matches strings containing an <c>ObjectId</c> call with a 24-character hexadecimal value enclosed in delimiters.</returns>
|
||||
/// <!-- aidoc:v1 sig=ebf18cf -->
|
||||
[GeneratedRegex("ObjectId\\((.[a-f0-9]{24}.)\\)")]
|
||||
private static partial Regex ObjectIdRegex();
|
||||
|
||||
@@ -176,6 +178,7 @@ public partial class ComplexObjectValueTypeSerializer : SerializerBase<object>
|
||||
/// <param name="context">The BSON serialization context that provides the writer used to emit the serialized output.</param>
|
||||
/// <param name="args">Additional BSON serialization arguments passed through to the underlying serializers.</param>
|
||||
/// <param name="value">The runtime value to serialize. A <c>null</c> value is written as a BSON null; all other values are dispatched based on their concrete type.</param>
|
||||
/// <!-- aidoc:v1 sig=afd2b33 body=331ada7 -->
|
||||
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value)
|
||||
{
|
||||
switch (value)
|
||||
@@ -241,6 +244,7 @@ public partial class ComplexObjectValueTypeSerializer : SerializerBase<object>
|
||||
/// </summary>
|
||||
/// <param name="bsonArray">The BSON array whose element type needs to be resolved.</param>
|
||||
/// <returns>The resolved <see cref="Type"/> for the array elements, or <c>null</c> when no matching type can be determined.</returns>
|
||||
/// <!-- aidoc:v1 sig=c18a474 body=ae05e3b -->
|
||||
private Type? GetElementTypeFromBsonArray(BsonArray bsonArray)
|
||||
{
|
||||
if (bsonArray.Count == 1 && bsonArray.Values.Any(c => c.IsBsonNull))
|
||||
@@ -289,6 +293,7 @@ public partial class ComplexObjectValueTypeSerializer : SerializerBase<object>
|
||||
/// Provides serialization for <see cref="List{T}"/> instances while ignoring null elements.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of elements contained in the list being serialized.</typeparam>
|
||||
/// <!-- aidoc:v1 sig=886b1df -->
|
||||
public class NullIgnoringListSerializer<T> : SerializerBase<List<T>>
|
||||
{
|
||||
/// <summary>
|
||||
@@ -297,6 +302,7 @@ public partial class ComplexObjectValueTypeSerializer : SerializerBase<object>
|
||||
/// <param name="context">The BSON deserialization context providing the reader used to read the BSON data.</param>
|
||||
/// <param name="args">Additional arguments that influence the deserialization process.</param>
|
||||
/// <returns>A <see cref="List{T}"/> containing the deserialized elements, or an empty list if the BSON value is null.</returns>
|
||||
/// <!-- aidoc:v1 sig=df18c1f body=b9d1e6d -->
|
||||
public override List<T> Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
|
||||
{
|
||||
var bsonType = context.Reader.GetCurrentBsonType();
|
||||
@@ -324,6 +330,7 @@ public partial class ComplexObjectValueTypeSerializer : SerializerBase<object>
|
||||
/// <param name="context">The BSON serialization context providing the writer used to emit the array and its elements.</param>
|
||||
/// <param name="args">The BSON serialization arguments supplying additional options for the serialization process.</param>
|
||||
/// <param name="value">The list of items to serialize as a BSON array.</param>
|
||||
/// <!-- aidoc:v1 sig=e2b49d6 body=1f2669b -->
|
||||
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, List<T> value)
|
||||
{
|
||||
context.Writer.WriteStartArray();
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace adas_core.Domain.Utils;
|
||||
/// <summary>
|
||||
/// Provides a static container for cryptographic operations and utilities related to the Adas domain.
|
||||
/// </summary>
|
||||
/// <!-- aidoc:v1 sig=2c4859b -->
|
||||
public static class CryptoAdas
|
||||
{
|
||||
private static readonly Regex PassRegex = new("^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$");
|
||||
@@ -19,6 +20,7 @@ public static class CryptoAdas
|
||||
/// </summary>
|
||||
/// <param name="input">The string to hash. Its ASCII byte representation is used as the input to the MD5 algorithm.</param>
|
||||
/// <returns>The MD5 hash of <paramref name="input"/> formatted as an uppercase hexadecimal string.</returns>
|
||||
/// <!-- aidoc:v1 sig=e509d6c body=5733afd -->
|
||||
public static string CreateMd5(string input)
|
||||
{
|
||||
using var md5 = MD5.Create();
|
||||
@@ -39,6 +41,7 @@ public static class CryptoAdas
|
||||
/// <param name="gF">The grouped field whose names, max, since, regularity, and results are included in the hash input.</param>
|
||||
/// <param name="patientId">The identifier of the patient whose data is being hashed.</param>
|
||||
/// <returns>An MD5 hash string representing the combined patient and grouped field data.</returns>
|
||||
/// <!-- aidoc:v1 sig=0805f4d body=4e67e9c -->
|
||||
public static string CreateMd5GroupedObs(GroupedField gF, ObjectId patientId)
|
||||
{
|
||||
var names = CollectionsUtils.IfEmptyOrNull(gF.Names, [gF.Name ?? string.Empty]);
|
||||
@@ -56,6 +59,7 @@ public static class CryptoAdas
|
||||
/// </summary>
|
||||
/// <param name="input">The plain text string to be hashed.</param>
|
||||
/// <returns>A BCrypt hashed representation of the input string.</returns>
|
||||
/// <!-- aidoc:v1 sig=095e787 body=667d6d0 -->
|
||||
public static string CreateBCrypt(string input)
|
||||
{
|
||||
return BCrypt.Net.BCrypt.HashPassword(input);
|
||||
@@ -67,6 +71,7 @@ public static class CryptoAdas
|
||||
/// <param name="loginPass">The plain text password entered by the user during login.</param>
|
||||
/// <param name="passwordHash">The stored BCrypt hash to compare the password against.</param>
|
||||
/// <returns><c>true</c> if the password matches the hash; otherwise, <c>false</c>.</returns>
|
||||
/// <!-- aidoc:v1 sig=a06bd55 body=9f08488 -->
|
||||
public static bool VerifyPassword(string loginPass, string passwordHash)
|
||||
{
|
||||
return BCrypt.Net.BCrypt.Verify(loginPass, passwordHash);
|
||||
@@ -77,6 +82,7 @@ public static class CryptoAdas
|
||||
/// </summary>
|
||||
/// <param name="password">The password string to evaluate against the strong password requirements.</param>
|
||||
/// <returns><c>true</c> if the password matches the strong password pattern; otherwise, <c>false</c>.</returns>
|
||||
/// <!-- aidoc:v1 sig=fc43cf7 body=9a130ab -->
|
||||
public static bool IsStrongPassword(string password)
|
||||
{
|
||||
return PassRegex.IsMatch(password);
|
||||
|
||||
@@ -8,6 +8,8 @@ namespace adas_core.Domain.Utils;
|
||||
/// <remarks>
|
||||
/// This is a static utility class that cannot be instantiated and is intended to extend the functionality of <see cref="DetailConfigExtension"/> through extension method definitions.
|
||||
/// </remarks>
|
||||
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
|
||||
/// "The documentation states the class provides extension methods for 'DetailConfigExtension' itself, but by convention a class named 'DetailConfigExtension' is meant to extend another type (likely 'DetailConfig'), not itself." -->
|
||||
public static class DetailConfigExtension
|
||||
{
|
||||
// Método principal para iniciar la extracción
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
/// <summary>
|
||||
/// Provides static extension methods to augment the functionality of dictionary types.
|
||||
/// </summary>
|
||||
/// <!-- aidoc:v1 sig=02a7d52 -->
|
||||
public static class DictionaryEx
|
||||
{
|
||||
/// <summary>
|
||||
@@ -12,6 +13,7 @@ public static class DictionaryEx
|
||||
/// <param name="key">The key whose associated value should be returned.</param>
|
||||
/// <param name="defaultValue">The value to return when the key is not present in the dictionary. Defaults to the default value of <typeparamref name="TV"/>.</param>
|
||||
/// <returns>The value associated with the key if found; otherwise, <paramref name="defaultValue"/>.</returns>
|
||||
/// <!-- aidoc:v1 sig=b234e0b body=dba24e5 -->
|
||||
public static TV? GetValue<TK, TV>(this IDictionary<TK, TV> dict, TK key, TV? defaultValue = default)
|
||||
{
|
||||
return dict.TryGetValue(key, out var value) ? value : defaultValue;
|
||||
@@ -24,6 +26,7 @@ public static class DictionaryEx
|
||||
/// <param name="itemSeparator">The separator placed between each formatted key-value pair in the resulting string.</param>
|
||||
/// <param name="keySeparator">The separator placed between a key and its corresponding value within each pair.</param>
|
||||
/// <returns>A single string containing all dictionary entries formatted and joined using the specified separators.</returns>
|
||||
/// <!-- aidoc:v1 sig=8568016 body=8f9bb50 -->
|
||||
public static string ToListString<TK, TV>(this IDictionary<TK, TV> dict, string itemSeparator = ", ",
|
||||
string keySeparator = ": ")
|
||||
{
|
||||
@@ -38,6 +41,7 @@ public static class DictionaryEx
|
||||
/// <param name="dictionary">The dictionary to search for the key.</param>
|
||||
/// <param name="key">The key whose associated value should be retrieved.</param>
|
||||
/// <returns>The value associated with the key, or null if the key was not found in the dictionary.</returns>
|
||||
/// <!-- aidoc:v1 sig=9a17711 body=7e00219 -->
|
||||
public static TValue? TryGetAndReturn<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key)
|
||||
where TKey : notnull where TValue : class
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace adas_core.Domain.Utils;
|
||||
/// <summary>
|
||||
/// Provides static utility methods for working with <see cref="System.Enum"/> types.
|
||||
/// </summary>
|
||||
/// <!-- aidoc:v1 sig=429f818 -->
|
||||
public static class EnumUtils
|
||||
{
|
||||
/// <summary>
|
||||
@@ -14,6 +15,7 @@ public static class EnumUtils
|
||||
/// </summary>
|
||||
/// <param name="value">The enumeration value whose description should be obtained.</param>
|
||||
/// <returns>The description text from the <see cref="DescriptionAttribute"/> if present; otherwise, the string representation of the enum value.</returns>
|
||||
/// <!-- aidoc:v1 sig=48c6985 body=d45f10c -->
|
||||
public static string GetDescription(Enum value)
|
||||
{
|
||||
var enumMember = value.GetType().GetMember(value.ToString()).FirstOrDefault();
|
||||
|
||||
@@ -19,6 +19,7 @@ public sealed class EquatableDictionary<TKey, TValue>
|
||||
/// </summary>
|
||||
/// <param name="other">The dictionary to compare against this instance.</param>
|
||||
/// <returns><c>true</c> if both dictionaries contain the same keys with equal values; otherwise, <c>false</c>.</returns>
|
||||
/// <!-- aidoc:v1 sig=1b5e4bb body=d98d679 -->
|
||||
public bool Equals(ComparableDictionary<TKey, TValue>? other)
|
||||
{
|
||||
if (other is null) return false;
|
||||
@@ -38,6 +39,7 @@ public sealed class EquatableDictionary<TKey, TValue>
|
||||
/// </summary>
|
||||
/// <param name="other">The object to compare with the current instance.</param>
|
||||
/// <returns><c>true</c> if <paramref name="other"/> is a <see cref="ComparableDictionary{TKey, TValue}"/> and is equal to the current instance; otherwise, <c>false</c>.</returns>
|
||||
/// <!-- aidoc:v1 sig=a2c1185 body=4da7df8 -->
|
||||
public override bool Equals(object? other)
|
||||
{
|
||||
return Equals(other as ComparableDictionary<TKey, TValue>);
|
||||
@@ -48,6 +50,7 @@ public sealed class EquatableDictionary<TKey, TValue>
|
||||
/// Each pair contributes a hash derived from its key and value, and the per-pair hashes are combined using XOR.
|
||||
/// </summary>
|
||||
/// <returns>An integer hash code that represents the contents of the collection.</returns>
|
||||
/// <!-- aidoc:v1 sig=eb26c4a body=9b55f08 -->
|
||||
public override int GetHashCode()
|
||||
{
|
||||
var hash = 0;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
/// <summary>
|
||||
/// Provides static access to global application data and configuration values.
|
||||
/// </summary>
|
||||
/// <!-- aidoc:v1 sig=8205a2a -->
|
||||
public static class GlobalData
|
||||
{
|
||||
public static Dictionary<string, object> Data = new();
|
||||
@@ -12,6 +13,7 @@ public static class GlobalData
|
||||
/// </summary>
|
||||
/// <param name="key">The key used to identify the data entry in the store.</param>
|
||||
/// <param name="value">The value to associate with the specified key.</param>
|
||||
/// <!-- aidoc:v1 sig=844414c body=7ffcd39 -->
|
||||
public static void AddData(string key, object value)
|
||||
{
|
||||
var exists = Data.ContainsKey(key);
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace adas_core.Domain.Utils;
|
||||
/// <summary>
|
||||
/// Provides static utility methods for working with HL7 (Health Level 7) data formats and messages.
|
||||
/// </summary>
|
||||
/// <!-- aidoc:v1 sig=671835a -->
|
||||
public static class Hl7Utils
|
||||
{
|
||||
/// <summary>
|
||||
@@ -16,6 +17,7 @@ public static class Hl7Utils
|
||||
/// <param name="logger">Logger para registrar advertencias</param>
|
||||
/// <param name="type">Tipo de mensaje HL7 que se va a procesar su entrada</param>
|
||||
/// <returns>true si se permite; false en caso contrario.</returns>
|
||||
/// <!-- aidoc:v1 sig=32eaafb body=f8cff18 -->
|
||||
public static bool ManageAutoAdt(Unit? unitConfig, Unit? oldUnitConfig, ILogger logger, string type)
|
||||
{
|
||||
// Variables de estado:
|
||||
|
||||
@@ -8,6 +8,7 @@ public interface IMappingUtils
|
||||
/// <param name="code">The code used to look up the entity.</param>
|
||||
/// <param name="category">The category used to filter the search.</param>
|
||||
/// <returns>A nullable tuple containing the type, name, and group of the found entity, or <c>null</c> if no match is found.</returns>
|
||||
/// <!-- aidoc:v1 sig=b334b7d -->
|
||||
(string type, string name, string group)? SearchByCode(object code, string category);
|
||||
/// <summary>
|
||||
/// Retrieves the complexity value associated with the specified name, optionally applying a weight.
|
||||
@@ -15,6 +16,7 @@ public interface IMappingUtils
|
||||
/// <param name="name">The name used to look up the complexity value.</param>
|
||||
/// <param name="peso">An optional weight value to apply to the complexity calculation.</param>
|
||||
/// <returns>The complexity value as an integer.</returns>
|
||||
/// <!-- aidoc:v1 sig=a58a789 -->
|
||||
int GetComplexityValue(string name, double? peso = null);
|
||||
|
||||
// void ConvertStringToDoubleInMapping();
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace adas_core.Domain.Utils;
|
||||
/// <summary>
|
||||
/// Provides extension methods for JSON-related operations.
|
||||
/// </summary>
|
||||
/// <!-- aidoc:v1 sig=705e834 -->
|
||||
public static class JsonExtensions
|
||||
{
|
||||
/// <summary>
|
||||
@@ -15,6 +16,7 @@ public static class JsonExtensions
|
||||
/// <param name="inputPath">The path to the source JSON file to read from.</param>
|
||||
/// <param name="outputPath">The path to the destination BSON file to write to.</param>
|
||||
/// <param name="fileMode">The file mode used to open the output file. Defaults to <see cref="FileMode.CreateNew"/>.</param>
|
||||
/// <!-- aidoc:v1 sig=c16c55c body=99b3e3a -->
|
||||
public static void CopyToBson(string inputPath, string outputPath, FileMode fileMode = FileMode.CreateNew)
|
||||
{
|
||||
using var textReader = File.OpenText(inputPath);
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace adas_core.Domain.Utils;
|
||||
/// <remarks>
|
||||
/// This class is intended to be inherited by concrete implementations that define specific JWT processing behaviors.
|
||||
/// </remarks>
|
||||
/// <!-- aidoc:v1 sig=1fa4049 -->
|
||||
public abstract class JwtHelper
|
||||
{
|
||||
/// <summary>
|
||||
@@ -25,6 +26,7 @@ public abstract class JwtHelper
|
||||
/// <param name="expiration">The token lifetime in minutes, added to the current UTC time to compute the expiration date.</param>
|
||||
/// <param name="additionalClaims">Optional extra claims to merge into the token alongside the standard claims. If null, only the default claims are included.</param>
|
||||
/// <returns>A <see cref="JwtSecurityToken"/> signed with HMAC-SHA256 and configured with the supplied issuer, audience, expiration, and claims.</returns>
|
||||
/// <!-- aidoc:v1 sig=7df0b13 body=543eca7 -->
|
||||
public static JwtSecurityToken GetJwtToken(
|
||||
string username,
|
||||
string secret,
|
||||
@@ -70,6 +72,7 @@ public abstract class JwtHelper
|
||||
/// Generates a cryptographically secure refresh token by producing 64 random bytes using <see cref="RandomNumberGenerator"/> and returning the value as a Base64-encoded string.
|
||||
/// </summary>
|
||||
/// <returns>A Base64-encoded string representation of a 64-byte cryptographically random sequence suitable for use as a refresh token.</returns>
|
||||
/// <!-- aidoc:v1 sig=6a19dd4 body=ba66473 -->
|
||||
public static string GenerateRefreshToken()
|
||||
{
|
||||
var randomNumber = new byte[64];
|
||||
@@ -83,6 +86,7 @@ public abstract class JwtHelper
|
||||
/// </summary>
|
||||
/// <param name="principal"></param>
|
||||
/// <returns></returns>
|
||||
/// <!-- aidoc:v1 sig=df50964 body=4874c36 -->
|
||||
public static string? GetUsernameFromPrincipal(ClaimsPrincipal principal)
|
||||
{
|
||||
var nameClaim = principal.Claims.FirstOrDefault(c => c.Type.Equals(ClaimTypes.NameIdentifier));
|
||||
|
||||
@@ -43,6 +43,12 @@ public static class Mapper<T>
|
||||
/// <param name="destination">The target object that will receive the mapped property values.</param>
|
||||
/// <exception cref="ArgumentNullException">Thrown when <paramref name="source"/> or <paramref name="destination"/> is null.</exception>
|
||||
/// <exception cref="ArgumentException">Thrown when a source value is null but the corresponding destination property is a value type that is not <see cref="Nullable{T}"/>.</exception>
|
||||
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
|
||||
/// "The summary states null values are only assigned to reference types or Nullable<T> types, but the condition `propType is { IsByRef: false } && propType.Name != \"Nullable\\`1\"` is true for reference types as well, so the code throws ArgumentException for reference types too." -->
|
||||
/// <!-- aidoc-review:v1 severity=high kind=wrong_exception
|
||||
/// "The exception is documented as thrown only when the destination property is a non-nullable value type, but the condition matches any non-Nullable property type (including reference types), so the exception is also thrown for reference-type properties." -->
|
||||
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
|
||||
/// "The summary states that when source value type does not match the destination property type, the value is converted using Convert.ToDouble(object), but the unconditional `p.SetValue(destination, kv.Value, null)` after the else-if block overwrites the conversion, so the original (unconverted) value is always assigned." -->
|
||||
public static void Map(ExpandoObject source, T destination)
|
||||
{
|
||||
// Might as well take care of null references early.
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace adas_core.Domain.Utils;
|
||||
/// <summary>
|
||||
/// Provides a sealed implementation of mapping utilities, serving as the concrete type for the <see cref="IMappingUtils"/> contract.
|
||||
/// </summary>
|
||||
/// <!-- aidoc:v1 sig=3654eb4 -->
|
||||
public sealed class MappingUtils : IMappingUtils
|
||||
{
|
||||
private readonly List<MappingInterventions>? _cccData;
|
||||
@@ -139,6 +140,7 @@ public sealed class MappingUtils : IMappingUtils
|
||||
/// <param name="name">The name of the entry to look up in the CCC data.</param>
|
||||
/// <param name="peso">Optional weight used to select the matching range when multiple values are defined; when null, range-based lookup is skipped.</param>
|
||||
/// <returns>The matched initial value (for single-entry entries) or the contributed value (for range-based entries); returns 0 if the name is not found or no data is available.</returns>
|
||||
/// <!-- aidoc:v1 sig=ebd2665 body=cd6536d -->
|
||||
public int GetComplexityValue(string name, double? peso = null)
|
||||
{
|
||||
ConvertStringToDoubleInMapping();
|
||||
@@ -167,6 +169,7 @@ public sealed class MappingUtils : IMappingUtils
|
||||
/// <summary>
|
||||
/// Converts string representations of numeric values in the <c>_cccData</c> mapping to <see cref="double"/> using the invariant culture, ensuring the period (".") is recognized as the decimal separator. The method only runs when the data has not already been transformed (<c>_isTransformedValue</c> is false) and when <c>_cccData</c> is not null, iterating through each mapping's <c>Codes</c> and <c>Value</c> entries to parse and replace their <c>InitialValue</c> and <c>FinalValue</c> when they are strings. After processing, it marks the transformation as completed by setting <c>_isTransformedValue</c> to true.
|
||||
/// </summary>
|
||||
/// <!-- aidoc:v1 sig=c56c099 body=08add6b -->
|
||||
private void ConvertStringToDoubleInMapping()
|
||||
{
|
||||
// esto es para garantizar que el punto (".") sea reconocido como separador decimal
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace adas_core.Domain.Utils;
|
||||
/// <summary>
|
||||
/// Provides static utility methods for handling media-related operations.
|
||||
/// </summary>
|
||||
/// <!-- aidoc:v1 sig=448de2e -->
|
||||
public static class MediaUtils
|
||||
{
|
||||
public static readonly Dictionary<string, string> Mapping = new(StringComparer.InvariantCultureIgnoreCase)
|
||||
@@ -98,6 +99,7 @@ public static class MediaUtils
|
||||
/// </summary>
|
||||
/// <param name="filePath">The file path whose extension is used to resolve the MIME type.</param>
|
||||
/// <returns>The corresponding MIME type string if the extension is found in the mapping; otherwise, the default <c>application/octet-stream</c> value.</returns>
|
||||
/// <!-- aidoc:v1 sig=32736f8 body=5e920f2 -->
|
||||
public static string GetMimeType(string filePath)
|
||||
{
|
||||
var extension = Path.GetExtension(filePath).ToLowerInvariant();
|
||||
@@ -110,6 +112,7 @@ public static class MediaUtils
|
||||
/// </summary>
|
||||
/// <param name="filePath">The path of the file to evaluate.</param>
|
||||
/// <returns><c>true</c> if the file extension matches one of the supported video extensions; otherwise, <c>false</c>.</returns>
|
||||
/// <!-- aidoc:v1 sig=76fdeef body=e5c094c -->
|
||||
public static bool IsVideoFile(string filePath)
|
||||
{
|
||||
// Extensiones de video soportadas
|
||||
@@ -124,6 +127,7 @@ public static class MediaUtils
|
||||
/// </summary>
|
||||
/// <param name="videoPath">The file path of the video whose duration should be retrieved.</param>
|
||||
/// <returns>The video duration in milliseconds, or null if an error occurs while reading the file.</returns>
|
||||
/// <!-- aidoc:v1 sig=06def65 body=dc9235d -->
|
||||
public static long? GetVideoDuration(string videoPath)
|
||||
{
|
||||
try
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
/// <summary>
|
||||
/// Provides a collection of static utility methods for performing common numeric operations.
|
||||
/// </summary>
|
||||
/// <!-- aidoc:v1 sig=6831b9b -->
|
||||
public static class NumberUtils
|
||||
{
|
||||
/// <summary>
|
||||
@@ -10,6 +11,7 @@ public static class NumberUtils
|
||||
/// </summary>
|
||||
/// <param name="value">The object to evaluate.</param>
|
||||
/// <returns><c>true</c> if <paramref name="value"/> is one of the supported numeric types (sbyte, byte, short, ushort, int, uint, long, ulong, float, double, or decimal); otherwise, <c>false</c>.</returns>
|
||||
/// <!-- aidoc:v1 sig=1d802ac body=c01f438 -->
|
||||
public static bool IsNumber(this object value)
|
||||
{
|
||||
return value is sbyte
|
||||
@@ -30,6 +32,7 @@ public static class NumberUtils
|
||||
/// </summary>
|
||||
/// <param name="value">The object to convert to a <see cref="double"/>.</param>
|
||||
/// <returns>A <see cref="double"/> that represents the converted value.</returns>
|
||||
/// <!-- aidoc:v1 sig=0769d25 body=41720e3 -->
|
||||
public static double ToDouble(this object value)
|
||||
{
|
||||
return Convert.ToDouble(value);
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace adas_core.Domain.Utils;
|
||||
/// <remarks>
|
||||
/// Inherits from <see cref="JsonConverter"/> to customize JSON representation for the type it targets.
|
||||
/// </remarks>
|
||||
/// <!-- aidoc:v1 sig=f98482b -->
|
||||
public class ObjectIdConverter : JsonConverter
|
||||
{
|
||||
/// <summary>
|
||||
@@ -17,6 +18,7 @@ public class ObjectIdConverter : JsonConverter
|
||||
/// <param name="writer">The <see cref="JsonWriter"/> used to emit the JSON output.</param>
|
||||
/// <param name="value">The value to serialize, expected to be an <see cref="ObjectId"/> instance.</param>
|
||||
/// <param name="serializer">The <see cref="JsonSerializer"/> invoking this converter.</param>
|
||||
/// <!-- aidoc:v1 sig=0bafa81 body=beff169 -->
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||
{
|
||||
if (value is ObjectId objectId)
|
||||
@@ -34,6 +36,7 @@ public class ObjectIdConverter : JsonConverter
|
||||
/// <param name="existingValue">The existing value being populated, passed through from the deserializer.</param>
|
||||
/// <param name="serializer">The JSON serializer invoking this converter.</param>
|
||||
/// <returns>An <see cref="ObjectId"/> instance when the value can be parsed or when the target type is non-nullable; <c>null</c> when the target type is nullable and no valid value is found.</returns>
|
||||
/// <!-- aidoc:v1 sig=881b805 body=5a6faf1 -->
|
||||
public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue,
|
||||
JsonSerializer serializer)
|
||||
{
|
||||
@@ -59,6 +62,10 @@ public class ObjectIdConverter : JsonConverter
|
||||
/// </summary>
|
||||
/// <param name="objectType">The type to evaluate for compatibility with the converter.</param>
|
||||
/// <returns><see langword="true"/> if <paramref name="objectType"/> can be assigned from <see cref="ObjectId"/>; otherwise, <see langword="false"/>.</returns>
|
||||
/// <!-- aidoc-review:v1 severity=high kind=wrong_returns
|
||||
/// "The code `typeof(ObjectId).IsAssignableFrom(objectType)` returns true when objectType is assignable TO ObjectId (i.e., objectType is ObjectId or a derived type). The doc states the opposite: 'objectType can be assigned from ObjectId' would mean ObjectId is assignable to objectType." -->
|
||||
/// <!-- aidoc-review:v1 severity=high kind=wrong_summary
|
||||
/// "Summary says 'checking if the type is assignable from ObjectId', which implies ObjectId is assignable to the type. The code actually checks if the type is assignable to ObjectId." -->
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return typeof(ObjectId).IsAssignableFrom(objectType);
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace adas_core.Domain.Utils;
|
||||
/// <summary>
|
||||
/// Provides static utility methods for common object-related operations.
|
||||
/// </summary>
|
||||
/// <!-- aidoc:v1 sig=97753a4 -->
|
||||
public static class ObjectUtils
|
||||
{
|
||||
/// <summary>
|
||||
@@ -13,6 +14,8 @@ public static class ObjectUtils
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to convert to a string. Can be null.</param>
|
||||
/// <returns>A string containing the type name followed by the object's non-null property values and their names.</returns>
|
||||
/// <!-- aidoc-review:v1 severity=low kind=wrong_summary
|
||||
/// "The format example shows 'TypeName[Property1: Value1,Property2: Value2]' without a trailing comma, but the code always appends a comma after each property value, producing a trailing comma before the closing bracket (e.g., 'TypeName[Prop1: Value1,]')." -->
|
||||
public static string ToStr(this object? obj)
|
||||
{
|
||||
if (obj == null) return "[OBJ NULL]";
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace adas_core.Domain.Utils;
|
||||
/// <summary>
|
||||
/// Provides helper methods for relaying operations, data, or commands between components.
|
||||
/// </summary>
|
||||
/// <!-- aidoc:v1 sig=00f0997 -->
|
||||
public class RelayHelper
|
||||
{
|
||||
/// <summary>
|
||||
@@ -69,6 +70,7 @@ public class RelayHelper
|
||||
/// Powers on the specified relay by constructing a request to the local relay control endpoint at https://localhost:7186, where the relay is identified by its <see cref="Relay.RelayNumber"/> in the path.
|
||||
/// </summary>
|
||||
/// <param name="relay">The relay to power on.</param>
|
||||
/// <!-- aidoc:v1 sig=61b2177 body=b5539f2 -->
|
||||
public static void PowerOnRelay(Relay relay)
|
||||
{
|
||||
UriBuilder builder = new()
|
||||
@@ -87,6 +89,7 @@ public class RelayHelper
|
||||
/// using the relay's number as the path identifier, then forwarding the call to the underlying relay handler.
|
||||
/// </summary>
|
||||
/// <param name="relay">The relay to power off, identified by its <see cref="Relay.RelayNumber"/> which is used to construct the request path.</param>
|
||||
/// <!-- aidoc:v1 sig=3bafafd body=1a09ab5 -->
|
||||
public static void PowerOffRelay(Relay relay)
|
||||
{
|
||||
UriBuilder builder = new()
|
||||
@@ -140,6 +143,7 @@ public class RelayHelper
|
||||
/// </summary>
|
||||
/// <param name="relay">The relay whose status is being queried.</param>
|
||||
/// <returns><c>true</c> if the relay is active; otherwise, <c>false</c>.</returns>
|
||||
/// <!-- aidoc:v1 sig=d491189 body=90f8ab6 -->
|
||||
public static bool GetRelayStatus(Relay relay)
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
/// <summary>
|
||||
/// Provides static extension methods for the <see cref="string"/> type.
|
||||
/// </summary>
|
||||
/// <!-- aidoc:v1 sig=cc11c0a -->
|
||||
public static class StringEx
|
||||
{
|
||||
/// <summary>
|
||||
@@ -10,6 +11,7 @@ public static class StringEx
|
||||
/// </summary>
|
||||
/// <param name="source">The string to evaluate.</param>
|
||||
/// <returns><c>true</c> if <paramref name="source"/> is <c>null</c> or an empty string; otherwise, <c>false</c>.</returns>
|
||||
/// <!-- aidoc:v1 sig=6fb921b body=7fbbf9d -->
|
||||
public static bool IsEmpty(this string source)
|
||||
{
|
||||
return string.IsNullOrEmpty(source);
|
||||
@@ -20,6 +22,7 @@ public static class StringEx
|
||||
/// </summary>
|
||||
/// <param name="source">The string to evaluate.</param>
|
||||
/// <returns>true if the string is null, empty, or contains only white space; otherwise, false.</returns>
|
||||
/// <!-- aidoc:v1 sig=cec22b6 body=67e9275 -->
|
||||
public static bool IsEmptyOrWhiteSpace(this string source)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(source);
|
||||
@@ -31,6 +34,7 @@ public static class StringEx
|
||||
/// <param name="source">The string to search within.</param>
|
||||
/// <param name="value">The delimiter whose first occurrence marks the start of the returned substring.</param>
|
||||
/// <returns>The substring after the first occurrence of <paramref name="value"/>; otherwise, the original <paramref name="source"/>.</returns>
|
||||
/// <!-- aidoc:v1 sig=e1718c5 body=92784ed -->
|
||||
public static string SubstringAfter(this string source, string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(source) || string.IsNullOrEmpty(value)) return source;
|
||||
@@ -48,6 +52,7 @@ public static class StringEx
|
||||
/// <param name="source">The string to extract the substring from.</param>
|
||||
/// <param name="value">The delimiter whose first occurrence marks the end of the returned substring.</param>
|
||||
/// <returns>The substring of <paramref name="source"/> before the first occurrence of <paramref name="value"/>, or the original <paramref name="source"/> when no match is found or when either input is null or empty.</returns>
|
||||
/// <!-- aidoc:v1 sig=a2fe204 body=2083b5c -->
|
||||
public static string SubstringBefore(this string source, string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(source) || string.IsNullOrEmpty(value)) return source;
|
||||
|
||||
Reference in New Issue
Block a user