Conflicto de fusión en adas-core.LdapLogin/LdapLoginService.cs

This commit is contained in:
jrojas
2026-07-06 14:30:23 +02:00
2810 changed files with 1927407 additions and 25397 deletions
+3
View File
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Enums;
/// <summary>
/// Provides a static container for defining and accessing available action definitions or constants.
/// </summary>
public static class ActionsEnum
{
public enum Actions
+6
View File
@@ -2,6 +2,12 @@
namespace adas_core.Domain.Enums;
/// <summary>
/// Provides static members related to alarm enumeration values or alarm-related operations.
/// </summary>
/// <remarks>
/// This class is declared as static and cannot be instantiated; all members are accessed via the type name.
/// </remarks>
public static class AlarmEnum
{
public enum AudioAlarmType
+3
View File
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Enums;
/// <summary>
/// Provides static utility methods for caching and managing enumeration values.
/// </summary>
public static class CacheEnum
{
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Enums;
/// <summary>
/// Provides a static collection of display-related configuration enumerations.
/// </summary>
public static class DisplayConfigEnums
{
public enum AxisPosition
+6
View File
@@ -1,5 +1,11 @@
namespace adas_core.Domain.Enums;
/// <summary>
/// Provides a static utility class for file enumeration operations.
/// </summary>
/// <remarks>
/// This class serves as a container for static members related to file enumeration functionality.
/// </remarks>
public static class FileEnum
{
public enum AssetTheme
@@ -1,5 +1,11 @@
namespace adas_core.Domain.Enums;
/// <summary>
/// Represents an enumeration that defines grouped categories of observations.
/// </summary>
/// <remarks>
/// This type is intended to provide a structured way to classify or organize observation values into distinct groups.
/// </remarks>
public class GroupedObservationEnum
{
public enum Regularity
+3
View File
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Enums;
/// <summary>
/// Provides a static container for HTTP-related enumerations and associated helper members.
/// </summary>
public static class HttpEnum
{
/// <summary>
+3
View File
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Enums;
/// <summary>
/// Provides a static container for medicine-related enumeration values or constants.
/// </summary>
public static class MedicineEnum
{
public enum Group
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Enums;
/// <summary>
/// Provides a static container for observation-related enumeration members.
/// </summary>
public static class ObservationEnum
{
/**
+3
View File
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Enums;
/// <summary>
/// Provides a static container for patient-related enumeration values or constants used throughout the application.
/// </summary>
public static class PatientEnum
{
public enum Gender
+3
View File
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Enums;
/// <summary>
/// Represents a set of permission values used to define access rights or authorization levels within the system.
/// </summary>
public class PermissionEnum
{
public enum PermissionTypesEnum
+4
View File
@@ -1,5 +1,9 @@
namespace adas_core.Domain.Enums;
/// <summary>
/// Provides static utility members related to the Pump enumeration.
/// </summary>
/// <remarks>This class cannot be instantiated and serves as a container for helpers associated with the Pump enum.</remarks>
public static class PumpEnum
{
public enum PumpMessageType
+3
View File
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Enums;
/// <summary>
/// Provides static utility methods for working with enum types, serving as a relay or helper layer for enum-related operations.
/// </summary>
public static class RelayEnum
{
public enum Mode
+6
View File
@@ -1,5 +1,11 @@
namespace adas_core.Domain.Enums;
/// <summary>
/// Provides a static container for status-related constants and values, typically used in place of a traditional status enumeration.
/// </summary>
/// <remarks>
/// This class is declared as static and cannot be instantiated. It is intended to group status values in a centralized, type-safe manner.
/// </remarks>
public static class StatusEnum
{
public enum Discharge
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Enums;
/// <summary>
/// Provides a static container for subscription-related enumeration values.
/// </summary>
public static class SubscriptionEnum
{
public enum Type
+3
View File
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Enums;
/// <summary>
/// Provides a static container for user-related enumeration values.
/// </summary>
public static class UserEnum
{
public enum LoginMethod
@@ -1,3 +1,6 @@
namespace adas_core.Domain.Exceptions;
/// <summary>
/// Represents an exception that is thrown when an error occurs within the ADAS (Advanced Driver Assistance Systems) module, providing a prefixed message for easier identification.
/// </summary>
public class AdasException(string message) : Exception($"ADAS Exception: {message}");
@@ -2,6 +2,9 @@
namespace adas_core.Domain.Exceptions;
/// <summary>
/// Represents an exception that aggregates one or more errors related to business logic or domain rule violations.
/// </summary>
public class BusinessException : AggregateException
{
public BusinessException(HttpStatusCode status, string message) : base($"{status}: {message}")
@@ -2,6 +2,13 @@
namespace adas_core.Domain.Exceptions;
/// <summary>
/// Represents an exception that is thrown when an error occurs within the login services layer.
/// </summary>
/// <remarks>
/// This exception extends <see cref="BusinessException"/> to signal business-level failures
/// specific to authentication and login operations.
/// </remarks>
public class LoginServicesException : BusinessException
{
public LoginServicesException(string message) :
@@ -2,6 +2,12 @@
namespace adas_core.Domain.Exceptions;
/// <summary>
/// Represents a business exception that is thrown when a requested user cannot be found.
/// </summary>
/// <remarks>
/// Inherits from <see cref="BusinessException"/> to signal user lookup failures within the business domain.
/// </remarks>
public class UserNotFoundException : BusinessException
{
public UserNotFoundException(string username) :
+78
View File
@@ -6,13 +6,45 @@ namespace adas_core.Domain;
public interface IDefaultRepository<T, in TS> where T : class
{
/// <summary>
/// Returns the <see cref="DbSet{T}"/> for entity type <typeparamref name="T"/>, enabling querying and persistence operations against the corresponding table.
/// </summary>
/// <returns>A <see cref="DbSet{T}"/> instance for the entity type <typeparamref name="T"/>.</returns>
DbSet<T> GetSet();
/// <summary>
/// Gets an <see cref="IQueryable{T}"/> representing the queryable source of items, allowing callers to compose additional query operations.
/// </summary>
/// <returns>An <see cref="IQueryable{T}"/> that can be used to build and execute queries against the underlying data source.</returns>
IQueryable<T> Query();
/// <summary>
/// Returns a queryable collection of <typeparamref name="T"/> items, optionally applying the specified pagination filter to control paging behavior.
/// </summary>
/// <param name="filter">The pagination filter that controls paging of the returned items, or <c>null</c> to omit pagination.</param>
/// <returns>An <see cref="IQueryable{T}"/> that can be used to enumerate the items with the applied filter.</returns>
IQueryable<T> Query(PaginationFilter? filter);
/// <summary>
/// Returns a paginated queryable sequence of items based on the specified page and page size.
/// </summary>
/// <param name="currentPage">The current page number; when null, pagination may be ignored or handled accordingly.</param>
/// <param name="pageSize">The number of items per page; when null, a default page size may be used.</param>
/// <returns>An <see cref="IQueryable{T}"/> representing the requested page of items.</returns>
IQueryable<T> Query(int? currentPage, int? pageSize = null);
/// <summary>
/// Retrieves an entity of type <typeparamref name="T"/> by its identifier, optionally eager-loading related entities via the provided include expressions.
/// </summary>
/// <param name="id">The identifier of the entity to look up.</param>
/// <param name="includeExpressions">Expressions that specify related entities to include in the returned result.</param>
/// <returns>The entity matching the supplied identifier, or <c>null</c> if no entity is found.</returns>
T? GetById(TS id, params Expression<Func<T, object>>[] includeExpressions);
/// <summary>
/// Retrieves an entity of type <typeparamref name="T"/> by its identifier, returning <c>null</c> when no matching record is found.
/// The lookup is performed using the provided <see cref="QueryCustomizer{T}"/> to allow caller-specific query adjustments such as includes, filters, or tracking settings.
/// </summary>
/// <param name="id">The identifier of type <typeparamref name="TS"/> used to locate the entity.</param>
/// <param name="queryCustomizer">A customizer that controls how the underlying query is constructed and executed.</param>
/// <returns>The matching entity of type <typeparamref name="T"/>, or <c>null</c> if no entity with the given <paramref name="id"/> is found.</returns>
T? GetById(TS id, QueryCustomizer<T> queryCustomizer);
/*[Obsolete("Use GetById(<S> id) instead")]
@@ -20,14 +52,60 @@ public interface IDefaultRepository<T, in TS> where T : class
[Obsolete("Use GetById(<S> id) instead")]
T? GetById(long id);
//T? GetById(string id);*/
/// <summary>
/// Retrieves an entity of type <typeparamref name="T"/> by its composite key values, returning <c>null</c> if no matching entity is found.
/// </summary>
/// <param name="keyValues">The values that compose the primary key of the entity to retrieve.</param>
/// <returns>The matching entity of type <typeparamref name="T"/>, or <c>null</c> if no entity is found.</returns>
T? GetByIds(params object[] keyValues);
/// <summary>
/// Creates a new instance of type T based on the specified source object.
/// </summary>
/// <param name="obj">The source object used to create the new instance.</param>
/// <returns>A new instance of type T created from the specified object.</returns>
T Create(T obj);
/// <summary>
/// Creates a list of objects based on the provided collection of input items.
/// </summary>
/// <param name="objs">The list of input objects to be created.</param>
/// <returns>A list of created objects of type <typeparamref name="T"/>.</returns>
List<T> Create(List<T> objs);
/// <summary>
/// Deletes the specified object from the underlying data source and returns the result.
/// </summary>
/// <param name="obj">The object of type <typeparamref name="T"/> to be deleted.</param>
/// <returns>The object of type <typeparamref name="T"/> representing the result of the delete operation.</returns>
T Delete(T obj);
/// <summary>
/// Deletes the specified collection of objects.
/// </summary>
/// <param name="objs">The collection of objects to delete.</param>
/// <returns>A list of the deleted objects.</returns>
List<T> Delete(ICollection<T> objs);
/// <summary>
/// Deletes all records or entries managed by the associated repository or service.
/// </summary>
void DeleteAll();
/// <summary>
/// Updates the specified entity in the underlying store and returns the updated instance.
/// </summary>
/// <param name="obj">The entity instance containing the updated values to persist.</param>
/// <returns>The updated entity of type <typeparamref name="T"/> as returned by the operation.</returns>
T Update(T obj);
/// <summary>
/// Gets the total number of items in the collection.
/// </summary>
/// <returns>The total count of items.</returns>
int Count();
/// <summary>
/// Returns the number of items that match the specified status.
/// </summary>
/// <param name="status">The status value used to filter the items being counted.</param>
/// <returns>The total count of items matching the specified status.</returns>
int Count(string status);
/// <summary>
/// Retrieves all entities of type <typeparamref name="T"/> and returns them as a list.
/// </summary>
/// <returns>A <see cref="List{T}"/> containing all entities of type <typeparamref name="T"/>; an empty list if none are found.</returns>
List<T> FindAll();
}
+16 -8
View File
@@ -5,6 +5,9 @@ using Newtonsoft.Json;
namespace adas_core.Domain.Models;
/// <summary>
/// Represents a request payload for the administrative panel operations.
/// </summary>
public class AdmPanelRequest
{
public string? Type { get; set; }
@@ -61,15 +64,20 @@ public class AdmPanelRequest
public Dictionary<string, object>? SectionItems { get; set; }
/// <summary>
/// Returns a JSON representation of the current object using <see cref="JsonConvert.SerializeObject(object, Formatting)"/> with no formatting.
/// If serialization fails, falls back to the base <see cref="object.ToString"/> implementation.
/// </summary>
/// <returns>A JSON-serialized string of the object, or the result of <c>base.ToString()</c> if serialization throws an exception.</returns>
public override string? ToString()
{
try
{
return JsonConvert.SerializeObject(this, Formatting.None);
try
{
return JsonConvert.SerializeObject(this, Formatting.None);
}
catch
{
return base.ToString();
}
}
catch
{
return base.ToString();
}
}
}
+16 -8
View File
@@ -6,6 +6,9 @@ using Newtonsoft.Json;
namespace adas_core.Domain.Models;
/// <summary>
/// Represents an API request, encapsulating the data and configuration needed to invoke a remote or web service endpoint.
/// </summary>
public class ApiRequest
{
// SIU
@@ -104,15 +107,20 @@ public class ApiRequest
public bool RequestFromPanel { get; set; }
/// <summary>
/// Returns a JSON string representation of the current object using <see cref="JsonConvert.SerializeObject(object, Formatting)"/> with no formatting.
/// If serialization fails, falls back to the result of <see cref="object.ToString()"/>.
/// </summary>
/// <returns>A JSON string representation of the object, or the base <see cref="object.ToString()"/> result if serialization throws an exception.</returns>
public override string? ToString()
{
try
{
return JsonConvert.SerializeObject(this, Formatting.None);
try
{
return JsonConvert.SerializeObject(this, Formatting.None);
}
catch
{
return base.ToString();
}
}
catch
{
return base.ToString();
}
}
}
@@ -3,6 +3,9 @@ using adas_core.Domain.Enums;
namespace adas_core.Domain.Models.AppSettings;
/// <summary>
/// Represents configuration settings for an API, such as base URL, authentication credentials, and timeout values.
/// </summary>
public class ApiSettings
{
public const string Api = "ApiSettings";
@@ -208,6 +211,9 @@ public class ApiSettings
public string? NoCalculateStatusWithCodingSystem { get; set; }
}
/// <summary>
/// Represents archived data related to a nurse, providing storage or transfer of historical nursing records.
/// </summary>
public class ArchiveNurseData
{
public bool Active { get; set; } = false;
@@ -217,12 +223,18 @@ public class ArchiveNurseData
public int IntervalMinutes { get; set; } = 15;
}
/// <summary>
/// Represents the configuration settings used to control the archiving process for nurse-related data.
/// </summary>
public class ArchiveNurseDataConfig
{
public bool Active { get; set; } = false;
public int EndDateAfterMinutes { get; set; } = 60;
}
/// <summary>
/// Represents a mapping configuration for point of care data, defining relationships between source and target structures.
/// </summary>
public class PointOfCareMapping
{
public string? Key { get; set; }
@@ -230,6 +242,9 @@ public class PointOfCareMapping
public int? Refresh { get; set; } = 600; //10min
}
/// <summary>
/// Represents configuration settings that govern how observations are captured, processed, or reported.
/// </summary>
public class ConfigObservationSettings
{
public bool IgnoreUnknownObservation { get; set; }
@@ -239,6 +254,9 @@ public class ConfigObservationSettings
#region CCC mapping config
/// <summary>
/// Represents a collection or registry of intervention codes used to identify or categorize specific interventions.
/// </summary>
public class InterventionsCodes
{
private object? _finalValue;
@@ -366,6 +384,9 @@ public class InterventionsCodes
}
}
/// <summary>
/// Represents a collection or container of values related to interventions.
/// </summary>
public class InterventionsValues
{
private object? _finalValue;
@@ -476,6 +497,9 @@ public class InterventionsValues
public int ValueContributed { get; set; } = 0;
}
/// <summary>
/// Represents a collection or configuration for mapping interventions, providing the means to associate intervention data with corresponding target structures or actions.
/// </summary>
public class MappingInterventions
{
public string? Type { get; set; }
@@ -2,6 +2,9 @@ using adas_core.Domain.Models.MongoModels;
namespace adas_core.Domain.Models.AppSettings;
/// <summary>
/// Represents a set of configuration settings used to control authentication behavior.
/// </summary>
public class AuthSettings
{
public JwtConfig? JwtConfig { get; set; }
@@ -9,6 +12,12 @@ public class AuthSettings
public List<string> LoginMethods { get; set; } = [];
}
/// <summary>
/// Represents a JWT configuration class that extends <see cref="JwtExtConfig"/>, providing additional or specialized settings for JSON Web Token processing.
/// </summary>
/// <remarks>
/// This class derives from <see cref="JwtExtConfig"/> and inherits its configuration properties, allowing it to serve as a more specific or customized JWT configuration type.
/// </remarks>
public class JwtConfig : JwtExtConfig
{
public string? Issuer { get; set; }
@@ -20,6 +29,9 @@ public class JwtConfig : JwtExtConfig
public Dictionary<string, JwtExtConfig>? ExternalProviders { get; set; } = null;
}
/// <summary>
/// Represents a configuration class for JWT (JSON Web Token) extension settings.
/// </summary>
public class JwtExtConfig
{
public string? Key { get; set; }
@@ -27,20 +39,48 @@ public class JwtExtConfig
public bool ValidateAudience { get; set; } = true;
}
/// <summary>
/// Represents a configuration collection that defines a whitelist of users, stored as a list of string identifiers.
/// </summary>
/// <remarks>
/// Inherits from a generic list of strings, exposing standard collection semantics for the whitelisted user entries.
/// </remarks>
public class UsersWhiteListConfig : List<string>
{
/// <summary>
/// Determines whether the collection contains a username matching the specified user's username, using a case-insensitive comparison.
/// </summary>
/// <param name="user">The user whose username will be checked against the collection.</param>
/// <returns><c>true</c> if a matching username is found; otherwise, <c>false</c>.</returns>
public bool IsValid(User user)
{
return this.Any(username => username.ToLowerInvariant().Equals(user.UserName.ToLowerInvariant()));
}
{
return this.Any(username => username.ToLowerInvariant().Equals(user.UserName.ToLowerInvariant()));
}
}
/// <summary>
/// Represents a configuration collection of <see cref="ValidGroup"/> instances, exposing them as a strongly-typed list.
/// </summary>
/// <remarks>
/// This type inherits from <see cref="List{T}"/> where T is <see cref="ValidGroup"/>, providing standard list operations for managing the configured valid groups.
/// </remarks>
/// <summary>
/// Represents a validation group used to organize or aggregate related validation rules.
/// </summary>
/// <remarks>
/// This type serves as a container or marker for grouping validation logic within a broader validation framework.
/// </remarks>
public class ValidGroupsConfig : List<ValidGroup>
{
/// <summary>
/// Determines whether the specified user is considered valid by checking that it is not null.
/// </summary>
/// <param name="user">The user instance to validate.</param>
/// <returns><see langword="true"/> if <paramref name="user"/> is not null; otherwise, <see langword="false"/>.</returns>
public bool IsValid(User? user)
{
return user != null;
}
{
return user != null;
}
}
public class ValidGroup
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Models.AppSettings;
/// <summary>
/// Represents the configuration settings for automatic recording functionality.
/// </summary>
public class AutoRecordingSettings
{
public AutoStart? AutoStart { get; set; }
@@ -7,6 +10,9 @@ public class AutoRecordingSettings
public MustSendAlert? MustSendAlert { get; set; }
}
/// <summary>
/// Represents functionality related to automatic startup of a process or service.
/// </summary>
public class AutoStart
{
public int BlueCode { get; set; }
@@ -14,6 +20,9 @@ public class AutoStart
public int RespirationAlert { get; set; }
}
/// <summary>
/// Represents an automatic stop mechanism that handles stopping operations or processes automatically.
/// </summary>
public class AutoStop
{
public int BlueCode { get; set; }
@@ -21,6 +30,9 @@ public class AutoStop
public int RespirationAlert { get; set; }
}
/// <summary>
/// Represents a condition or requirement that indicates an alert must be sent.
/// </summary>
public class MustSendAlert
{
public bool BlueCode { get; set; }
@@ -2,6 +2,9 @@ using adas_core.Domain.Enums;
namespace adas_core.Domain.Models.AppSettings;
/// <summary>
/// Represents configuration settings for a caching mechanism.
/// </summary>
public class CacheSettings
{
@@ -39,6 +42,10 @@ public class CacheSettings
// -------------------- InMemory Cache --------------------
/// <summary>
/// Represents an in-memory implementation for managing application settings.
/// Provides storage and retrieval of configuration values without persisting them to an external source.
/// </summary>
public class InMemorySettings
{
public TtlSettings Ttl { get; set; } = new();
@@ -48,6 +55,9 @@ public class InMemorySettings
// -------------------- TTL por entidad --------------------
/// <summary>
/// Represents configuration settings related to Time-To-Live (TTL) behavior.
/// </summary>
public class TtlSettings
{
public int? GlobalSeconds { get; set; }
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Models.AppSettings;
/// <summary>
/// Represents a set of configuration settings used to establish and manage database connections.
/// </summary>
public class DatabaseSettings
{
public const string Database = "DatabaseSettings";
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Models.AppSettings;
/// <summary>
/// Represents configuration or display settings for a list.
/// </summary>
public class ListSettings
{
public ListSettingItem AltableOptionList { get; set; } = new()
@@ -134,6 +137,9 @@ public class ListSettings
};
}
/// <summary>
/// Represents a single item within a list-based setting configuration.
/// </summary>
public class ListSettingItem
{
public string? ManualObservationName { get; set; }
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Models.AppSettings;
/// <summary>
/// Represents the configuration settings related to permissions.
/// </summary>
public class PermissionSettings
{
public SourcePermissions Admin { get; set; } = new(
@@ -329,6 +332,12 @@ public class PanelPermissionTypes(
public bool UseDemoMode { get; set; } = useDemoMode;
}
/// <summary>
/// Represents a set of user permissions indicating whether the user is allowed to create, update, delete, read, or execute specific operations.
/// </summary>
/// <remarks>
/// This type captures granular action-level authorization flags, allowing the application to enforce and check individual user capabilities across supported operations.
/// </remarks>
public class UserActions(bool create, bool update, bool delete, bool read, bool execute)
{
public bool Create { get; set; } = create;
@@ -1,5 +1,11 @@
namespace adas_core.Domain.Models.AppSettings;
/// <summary>
/// Represents configuration settings for connecting to and interacting with a RabbitMQ message broker.
/// </summary>
/// <remarks>
/// This class is intended to hold RabbitMQ-related configuration values, such as connection details and broker options, that can be bound from application configuration sources.
/// </remarks>
public class RabbitMqSettings
{
public string ConnectionString { get; set; } = string.Empty;
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Models.AppSettings;
/// <summary>
/// Represents configuration settings used to control recording behavior.
/// </summary>
public class RecordingSettings
{
public const string Recording = "RecordingSettings";
@@ -27,6 +27,9 @@ namespace adas_core.Domain.Models.AppSettings
public TtlSettings Ttl { get; set; } = new();
// Submodelos
/// <summary>
/// Represents a Redis server endpoint, typically used to encapsulate connection details such as host, port, and credentials required to connect to a Redis instance.
/// </summary>
public class RedisEndpoint
{
public string Host { get; set; } = null!;
@@ -36,48 +39,122 @@ namespace adas_core.Domain.Models.AppSettings
// CacheKeys: claves estandarizadas y unificadas para todas las entidades
// Estas claves son fundamentales para:
/// <summary>
/// Provides static cache key constants used throughout the application to ensure consistent key naming when storing and retrieving cached data.
/// </summary>
public static class CacheKeys
{
// ----------------- Patients -----------------
/// <summary>
/// Builds a formatted patient identifier by prefixing the provided patient ID with "patients:".
/// </summary>
/// <param name="patientId">The unique identifier of the patient to be included in the formatted string.</param>
/// <returns>A string in the format "patients:{patientId}" representing the patient resource key.</returns>
public static string Patient(string patientId)
=> $"patients:{patientId}";
=> $"patients:{patientId}";
// ----------------- ConfigDisplays -----------------
/// <summary>
/// Builds a configuration key for a config display by combining the <c>configDisplays</c> namespace with the specified identifier.
/// </summary>
/// <param name="id">The unique identifier of the config display to include in the key.</param>
/// <returns>A formatted key string in the form <c>configDisplays:{id}</c> suitable for lookup or caching.</returns>
public static string ConfigDisplay(string id)
=> $"configDisplays:{id}";
=> $"configDisplays:{id}";
/// <summary>
/// Returns the configuration key representing the "all displays" setting, typically used to request or identify the display configuration for all available displays.
/// </summary>
/// <returns>The string identifier "configDisplays:all" used to reference the all-displays configuration.</returns>
public static string ConfigDisplaysAll()
=> "configDisplays:all";
=> "configDisplays:all";
// ----------------- PumpObservations -----------------
/// <summary>
/// Formats the specified observation identifier as a pump observation reference string by prefixing it with "pumpObs:".
/// </summary>
/// <param name="obsId">The observation identifier to include in the formatted result.</param>
/// <returns>A formatted string in the form "pumpObs:{obsId}".</returns>
public static string PumpObservation(string obsId)
=> $"pumpObs:{obsId}";
=> $"pumpObs:{obsId}";
/// <summary>
/// Builds a daily pump observation identifier by composing a prefixed key with the pump identifier and the date in <c>yyyyMMdd</c> format.
/// </summary>
/// <param name="pumpId">The unique identifier of the pump used in the composed key.</param>
/// <param name="date">The observation date whose year, month, and day are formatted into the key.</param>
/// <returns>A string in the form <c>pumpObs:pump:{pumpId}:{yyyyMMdd}</c> representing the daily pump observation key.</returns>
public static string PumpDaily(string pumpId, DateTime date)
=> $"pumpObs:pump:{pumpId}:{date:yyyyMMdd}";
=> $"pumpObs:pump:{pumpId}:{date:yyyyMMdd}";
// ----------------- Appointments -----------------
/// <summary>
/// Builds an appointment resource identifier by combining the "appointments" prefix with the specified appointment ID.
/// </summary>
/// <param name="apptId">The unique identifier of the appointment.</param>
/// <returns>A formatted string in the form "appointments:{apptId}".</returns>
public static string Appointment(string apptId)
=> $"appointments:{apptId}";
=> $"appointments:{apptId}";
/// <summary>
/// Builds a cache key for retrieving a patient's appointments for a specific calendar day.
/// The key is composed of the patient identifier and the date formatted as <c>yyyyMMdd</c>.
/// </summary>
/// <param name="patientId">The unique identifier of the patient whose appointments are being addressed.</param>
/// <param name="date">The date for which the appointments are being requested.</param>
/// <returns>A formatted cache key string combining the patient identifier and the day in <c>yyyyMMdd</c> format.</returns>
public static string AppointmentsByPatientDay(string patientId, DateTime date)
=> $"appointments:patient:{patientId}:{date:yyyyMMdd}";
=> $"appointments:patient:{patientId}:{date:yyyyMMdd}";
/// <summary>
/// Builds a deterministic cache key used to look up a patient's appointments for the month of the supplied date.
/// The key is composed of the patient identifier and the date formatted as <c>yyyyMM</c>.
/// </summary>
/// <param name="patientId">The identifier of the patient whose appointments are being queried.</param>
/// <param name="date">The date whose year and month determine the appointment period encoded in the key.</param>
/// <returns>A formatted string in the form <c>appointments:patient:{patientId}:{yyyyMM}</c> suitable for use as a cache key.</returns>
public static string AppointmentsByPatientMonth(string patientId, DateTime date)
=> $"appointments:patient:{patientId}:{date:yyyyMM}";
=> $"appointments:patient:{patientId}:{date:yyyyMM}";
// ----------------- GroupedObservations -----------------
/// <summary>
/// Builds a formatted identifier string for grouped observations associated with a specific patient, typically used as a cache key or lookup token.
/// </summary>
/// <param name="patientId">The unique identifier of the patient whose observations are being referenced.</param>
/// <param name="groupedField">The optional field used to group the observations; may be null.</param>
/// <returns>A formatted string in the pattern "groupedObs:{groupedField}:patient:{patientId}".</returns>
public static string GroupedObservationsByPatient(string patientId, string? groupedField)
=> $"groupedObs:{groupedField}:patient:{patientId}";
=> $"groupedObs:{groupedField}:patient:{patientId}";
/// <summary>
/// Generates a formatted cache key for grouped observations scoped to a specific patient and day.
/// </summary>
/// <param name="patientId">The unique identifier of the patient.</param>
/// <param name="groupedField">The field name used to group the observations.</param>
/// <param name="date">The observation date, formatted as <c>yyyyMMdd</c> in the generated key.</param>
/// <returns>A cache key string in the format <c>groupedObs:{groupedField}:patient:{patientId}:{yyyyMMdd}</c>.</returns>
public static string GroupedObservationsByPatientDay(string patientId, string groupedField, DateTime date)
=> $"groupedObs:{groupedField}:patient:{patientId}:{date:yyyyMMdd}";
=> $"groupedObs:{groupedField}:patient:{patientId}:{date:yyyyMMdd}";
/// <summary>
/// Builds a cache key for grouped observations scoped to a specific patient and month, combining the grouping field, patient identifier, and the year-month portion of the provided date.
/// </summary>
/// <param name="patientId">The identifier of the patient whose observations are being grouped.</param>
/// <param name="groupedField">The observation field used as the grouping criterion.</param>
/// <param name="date">The date used to derive the month bucket (formatted as yyyyMM) for the cache key.</param>
/// <returns>A formatted cache key string in the form <c>groupedObs:{groupedField}:patient:{patientId}:{yyyyMM}</c>.</returns>
public static string GroupedObservationsByPatientMonth(string patientId, string groupedField, DateTime date)
=> $"groupedObs:{groupedField}:patient:{patientId}:{date:yyyyMM}";
=> $"groupedObs:{groupedField}:patient:{patientId}:{date:yyyyMM}";
/// <summary>
/// Generates a cache key for retrieving the most recent grouped observations for a specific patient.
/// </summary>
/// <param name="patientId">The unique identifier of the patient whose observations are being queried.</param>
/// <param name="groupedField">The field used to group the observations.</param>
/// <param name="take">The maximum number of latest observations to include in the cache key.</param>
/// <returns>A formatted cache key string identifying the patient's latest grouped observations.</returns>
public static string GroupedObservationsLatest(string patientId, string groupedField, int take)
=> $"groupedObs:{groupedField}:patient:{patientId}:latest:{take}";
=> $"groupedObs:{groupedField}:patient:{patientId}:latest:{take}";
}
}
}
@@ -5,6 +5,12 @@ using Newtonsoft.Json.Linq;
namespace adas_core.Domain.Models;
/// <summary>
/// Serves as a base class for JSON converters that handle patient observation data, providing shared conversion behavior derived from <see cref="JsonConverter"/>.
/// </summary>
/// <remarks>
/// This type is intended to be subclassed by concrete converters that implement specific serialization and deserialization logic for patient observation types.
/// </remarks>
public class BasePatientObservation : JsonConverter
{
public ObjectId Id { get; set; }
@@ -39,76 +45,113 @@ public class BasePatientObservation : JsonConverter
public List<ConfigObservation>? CreateObservation { get; set; }
/// <summary>
/// Serializes the current object to a JSON string representation.
/// Falls back to the base <see cref="object.ToString"/> implementation if JSON serialization fails.
/// </summary>
/// <returns>A JSON-formatted string of the object, or the result of <c>base.ToString()</c> if serialization throws an exception; may be <see langword="null"/> only if the underlying <c>ToString()</c> returns <see langword="null"/>.</returns>
public string? ToJsonString()
{
try
{
return JsonConvert.SerializeObject(this, Formatting.None);
try
{
return JsonConvert.SerializeObject(this, Formatting.None);
}
catch
{
return base.ToString();
}
}
catch
{
return base.ToString();
}
}
/// <summary>
/// Returns a string representation of the patient observation, including its identifier, patient identifier, timestamp, and conditionally included optional fields (such as system identifier, code, coding system, end time, name, and units) when they have values. Any child creation observations are also appended to the output.
/// </summary>
/// <returns>A formatted string that lists the patient observation properties prefixed with <c>BasePatientObservation[</c> and suffixed with <c>]</c>.</returns>
public override string ToString()
{
List<string> items =
[
$"id: {Id}",
$"patientid: {PatientId}"
];
if (!string.IsNullOrEmpty(SystemId)) items.Add($", systemId: {SystemId}");
if (!string.IsNullOrEmpty(Code)) items.Add($"code: {Code}");
if (!string.IsNullOrEmpty(CodingSystem)) items.Add($"codingSystem: {CodingSystem}");
items.Add($"time: {Time}");
if (EndTime.HasValue) items.Add($"endTime: {EndTime.Value}");
if (!string.IsNullOrEmpty(Name)) items.Add($"name: {Name}");
if (!string.IsNullOrEmpty(Units)) items.Add($"unit: {Units}");
items.Add($"checkObservations: {CheckObservations}");
CreateObservation?.ForEach(o => items.Add(o.ToString()));
return "BasePatientObservation[" + string.Join(", ", items) + "]";
}
{
List<string> items =
[
$"id: {Id}",
$"patientid: {PatientId}"
];
if (!string.IsNullOrEmpty(SystemId)) items.Add($", systemId: {SystemId}");
if (!string.IsNullOrEmpty(Code)) items.Add($"code: {Code}");
if (!string.IsNullOrEmpty(CodingSystem)) items.Add($"codingSystem: {CodingSystem}");
items.Add($"time: {Time}");
if (EndTime.HasValue) items.Add($"endTime: {EndTime.Value}");
if (!string.IsNullOrEmpty(Name)) items.Add($"name: {Name}");
if (!string.IsNullOrEmpty(Units)) items.Add($"unit: {Units}");
items.Add($"checkObservations: {CheckObservations}");
CreateObservation?.ForEach(o => items.Add(o.ToString()));
return "BasePatientObservation[" + string.Join(", ", items) + "]";
}
/// <summary>
/// Converts the current object's properties into a list of formatted key-value strings, including core identifiers and timestamp, and conditionally appending optional fields only when they contain values.
/// </summary>
/// <returns>A list of strings where each entry is formatted as "key: value" representing the object's properties.</returns>
public List<string> ToListString()
{
List<string> items =
[
$"id: {Id}",
$"patientid: {PatientId}"
];
if (!string.IsNullOrEmpty(SystemId)) items.Add($"systemId: {SystemId}");
if (!string.IsNullOrEmpty(Code)) items.Add($"code: {Code}");
if (!string.IsNullOrEmpty(CodingSystem)) items.Add($"codingSystem: {CodingSystem}");
items.Add($"time: {Time}");
if (!string.IsNullOrEmpty(Name)) items.Add($"name: {Name}");
return items;
}
{
List<string> items =
[
$"id: {Id}",
$"patientid: {PatientId}"
];
if (!string.IsNullOrEmpty(SystemId)) items.Add($"systemId: {SystemId}");
if (!string.IsNullOrEmpty(Code)) items.Add($"code: {Code}");
if (!string.IsNullOrEmpty(CodingSystem)) items.Add($"codingSystem: {CodingSystem}");
items.Add($"time: {Time}");
if (!string.IsNullOrEmpty(Name)) items.Add($"name: {Name}");
return items;
}
/// <summary>
/// Determines whether the converter can handle the specified type by checking if it matches <see cref="BasePatientObservation"/>.
/// </summary>
/// <param name="objectType">The type to evaluate for conversion support.</param>
/// <returns><c>true</c> if <paramref name="objectType"/> is <see cref="BasePatientObservation"/>; otherwise, <c>false</c>.</returns>
public override bool CanConvert(Type objectType)
{
return objectType == typeof(BasePatientObservation);
}
{
return objectType == typeof(BasePatientObservation);
}
/// <summary>
/// Serializes the specified object to JSON, excluding the <c>Id</c> and <c>Patient</c> properties from the output. If the value is <see langword="null"/>, the method returns without writing anything.
/// </summary>
/// <param name="writer">The <see cref="JsonWriter"/> to which the filtered JSON will be written.</param>
/// <param name="value">The object to serialize. If <see langword="null"/>, nothing is written.</param>
/// <param name="serializer">The <see cref="JsonSerializer"/> used during the conversion process.</param>
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
if (value == null) return;
var jo = JObject.FromObject(value);
jo.Property("Id")?.Remove();
jo.Property("Patient")?.Remove();
jo.WriteTo(writer);
}
{
if (value == null) return;
var jo = JObject.FromObject(value);
jo.Property("Id")?.Remove();
jo.Property("Patient")?.Remove();
jo.WriteTo(writer);
}
/// <summary>
/// Reads the JSON representation of an object. The current implementation is not provided and will always throw a <see cref="NotImplementedException"/>.
/// </summary>
/// <param name="reader">The reader used to parse the JSON content.</param>
/// <param name="objectType">The type of the object to deserialize.</param>
/// <param name="existingValue">The existing value of the object being deserialized.</param>
/// <param name="serializer">The serializer instance performing the deserialization.</param>
/// <returns>An object instance built from the JSON data.</returns>
/// <exception cref="NotImplementedException">Always thrown because the method has not been implemented.</exception>
public override object ReadJson(JsonReader reader, Type objectType, object? existingValue,
JsonSerializer serializer)
{
throw new NotImplementedException();
}
JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
/// <summary>
/// Represents a parent data class that serves as a base container for shared data members and functionality.
/// Provides a foundational structure intended to be inherited by more specific data classes.
/// </summary>
public class ParentDataClass
{
public string? Code { get; set; }
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Models;
/// <summary>
/// Serves as an abstract base class for patient observation values, extending <see cref="BasePatientObservation"/> to provide common functionality for representing measured or recorded clinical data associated with a patient observation.
/// </summary>
public abstract class BasePatientObservationValue : BasePatientObservation
{
public object Value { get; set; } = new();
@@ -7,267 +7,301 @@ using Newtonsoft.Json.Linq;
namespace adas_core.Domain.Models.BsonConverters;
/// <summary>
/// A BSON converter responsible for serializing and deserializing
/// <see cref="Dictionary{TKey, TValue}"/> instances with string keys and object values,
/// extending the base serializer infrastructure to support BSON format conversion.
/// </summary>
/// <remarks>
/// This type specializes the generic base serializer for the specific dictionary shape
/// <c>Dictionary&lt;string, object&gt;</c>, providing a focused implementation for
/// BSON-based persistence and data interchange scenarios.
/// </remarks>
public class DictionaryBsonConverter : SerializerBase<Dictionary<string, object>>
{
/// <summary>
/// Deserializes a BSON document into a dictionary where each top-level field name is mapped to its corresponding value.
/// Recognized keys (<c>STEPS</c>, <c>BEACONS</c>, <c>CAMERAS</c>, <c>RELAY</c>) are deserialized into their strongly-typed collections or objects, while unknown keys are deserialized based on the current BSON type (numeric values, strings, booleans, arrays of mixed primitive types, or generic BSON documents).
/// If the current BSON value is not a document, an empty dictionary is returned.
/// </summary>
/// <param name="context">The BSON deserialization context providing the reader used to traverse the BSON payload.</param>
/// <param name="args">The BSON deserialization arguments carrying additional configuration for the deserialization process.</param>
/// <returns>A dictionary containing the deserialized key/value pairs extracted from the BSON document.</returns>
public override Dictionary<string, object> Deserialize(BsonDeserializationContext context,
BsonDeserializationArgs args)
{
var reader = context.Reader;
var stepsDictionary = new Dictionary<string, object>();
if (reader.CurrentBsonType == BsonType.Document)
BsonDeserializationArgs args)
{
reader.ReadStartDocument();
while (reader.ReadBsonType() != BsonType.EndOfDocument)
var reader = context.Reader;
var stepsDictionary = new Dictionary<string, object>();
if (reader.CurrentBsonType == BsonType.Document)
{
var key = reader.ReadName();
switch (key.ToUpper())
reader.ReadStartDocument();
while (reader.ReadBsonType() != BsonType.EndOfDocument)
{
case "STEPS":
var stepList = BsonSerializer.Deserialize<List<Step>>(reader);
stepsDictionary[key] = stepList;
break;
case "BEACONS":
var beaconList = BsonSerializer.Deserialize<List<LightBeacon>>(reader);
stepsDictionary[key] = beaconList;
break;
case "CAMERAS":
var cameraList = BsonSerializer.Deserialize<List<Camera>>(reader);
stepsDictionary[key] = cameraList;
break;
case "RELAY":
var relayList = BsonSerializer.Deserialize<Relay>(reader);
stepsDictionary[key] = relayList;
break;
var key = reader.ReadName();
switch (key.ToUpper())
{
case "STEPS":
var stepList = BsonSerializer.Deserialize<List<Step>>(reader);
stepsDictionary[key] = stepList;
break;
case "BEACONS":
var beaconList = BsonSerializer.Deserialize<List<LightBeacon>>(reader);
stepsDictionary[key] = beaconList;
break;
case "CAMERAS":
var cameraList = BsonSerializer.Deserialize<List<Camera>>(reader);
stepsDictionary[key] = cameraList;
break;
case "RELAY":
var relayList = BsonSerializer.Deserialize<Relay>(reader);
stepsDictionary[key] = relayList;
break;
default:
switch (reader.CurrentBsonType)
{
case BsonType.Int32:
case BsonType.Int64:
stepsDictionary[key] = BsonSerializer.Deserialize<long>(reader);
break;
case BsonType.Double:
stepsDictionary[key] = BsonSerializer.Deserialize<double>(reader);
break;
case BsonType.String:
stepsDictionary[key] = BsonSerializer.Deserialize<string>(reader);
break;
case BsonType.Boolean:
stepsDictionary[key] = BsonSerializer.Deserialize<bool>(reader);
break;
case BsonType.Array:
reader.ReadStartArray();
var arrayItems = new List<object>();
while (reader.ReadBsonType() != BsonType.EndOfDocument)
switch (reader.CurrentBsonType)
{
case BsonType.String:
arrayItems.Add(BsonSerializer.Deserialize<string>(reader));
break;
case BsonType.Int32:
arrayItems.Add(BsonSerializer.Deserialize<int>(reader));
break;
case BsonType.Int64:
arrayItems.Add(BsonSerializer.Deserialize<long>(reader));
break;
case BsonType.Boolean:
arrayItems.Add(BsonSerializer.Deserialize<bool>(reader));
break;
case BsonType.Double:
arrayItems.Add(BsonSerializer.Deserialize<double>(reader));
break;
case BsonType.ObjectId:
arrayItems.Add(BsonSerializer.Deserialize<ObjectId>(reader));
break;
case BsonType.DateTime:
arrayItems.Add(BsonSerializer.Deserialize<DateTime>(reader));
break;
default:
reader.SkipValue();
break;
}
reader.ReadEndArray();
stepsDictionary[key] = arrayItems;
break;
default:
var bsonDoc = BsonSerializer.Deserialize<BsonDocument>(reader);
stepsDictionary[key] = bsonDoc.ToDictionary();
break;
}
break;
}
}
reader.ReadEndDocument();
}
return stepsDictionary;
}
default:
switch (reader.CurrentBsonType)
/// <summary>
/// Serializes a dictionary of string keys and object values into a BSON document. When a value's
/// type cannot be handled by the underlying key/value serializer, the corresponding key is written
/// with a null value as a fallback to preserve all dictionary entries.
/// </summary>
/// <param name="context">The BSON serialization context that provides the writer used to emit the document.</param>
/// <param name="args">The BSON serialization arguments associated with the current operation.</param>
/// <param name="value">The dictionary whose entries are written as fields of the BSON document.</param>
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args,
Dictionary<string, object> value)
{
var writer = context.Writer;
writer.WriteStartDocument();
foreach (var item in value)
{
if (TrySerializeKeyValuePair(item, writer)) continue;
// Si llegamos a este punto, encontramos un tipo no soportado.
writer.WriteName(item.Key);
writer.WriteNull(); // Escribe un valor null si el tipo no es soportado.
}
writer.WriteEndDocument();
}
/// <summary>
/// Attempts to serialize a key-value pair to BSON format using the provided writer. Handles specific well-known keys (<c>steps</c>, <c>beacons</c>, <c>cameras</c>, <c>relay</c>, and <c>uiFontProperties</c>) with their strongly-typed models, and falls back to serializing nested dictionaries, JArrays, or primitive BSON values for any other key. Returns <c>false</c> when the value cannot be converted to a BSON value or when no matching case applies.
/// </summary>
/// <param name="item">The key-value pair to serialize, where the key determines the serialization strategy and the value holds the data to write.</param>
/// <param name="writer">The BSON writer used to emit the serialized output for the key-value pair.</param>
/// <returns><c>true</c> if the key-value pair was successfully serialized; otherwise, <c>false</c>.</returns>
/// <exception cref="BsonSerializationException">Thrown when a BSON array contains an element whose BSON type is not supported.</exception>
/// <exception cref="NotSupportedException">Thrown when the default branch encounters a BSON value type that is not supported.</exception>
private static bool TrySerializeKeyValuePair(KeyValuePair<string, object> item, IBsonWriter writer)
{
writer.WriteName(item.Key);
switch (item.Key)
{
case "steps":
if (item.Value is JArray jSteps)
{
var steps = jSteps.ToObject<List<Step>>();
BsonSerializer.Serialize(writer, typeof(List<Step>), steps);
return true;
}
break;
case "beacons":
if (item.Value is JArray jBeaconConfigs)
{
var beaconConfigs = jBeaconConfigs.ToObject<List<LightBeacon>>();
BsonSerializer.Serialize(writer, typeof(List<LightBeacon>), beaconConfigs);
return true;
}
break;
case "cameras":
if (item.Value is JArray jCamerasConfigs)
{
var cameraConfigs = jCamerasConfigs.ToObject<List<Camera>>();
BsonSerializer.Serialize(writer, typeof(List<Camera>), cameraConfigs);
return true;
}
break;
case "relay":
if (item.Value is JObject jRelayConfigs)
{
var relayConfigs = jRelayConfigs.ToObject<Relay>();
BsonSerializer.Serialize(writer, relayConfigs);
return true;
}
break;
case "uiFontProperties":
{
if (item.Value is JObject jUiFontData)
{
var uiFontData = jUiFontData.ToObject<UiFontData>();
BsonSerializer.Serialize(writer, uiFontData);
return true;
}
}
break;
default:
if (item.Value is Dictionary<string, object> nestedDictionary)
{
var bsonDoc = new BsonDocument(nestedDictionary);
BsonSerializer.Serialize(writer, bsonDoc);
return true;
}
if (item.Value is JArray jArray)
{
var listObjects = jArray.ToObject<List<object>>();
BsonSerializer.Serialize(writer, listObjects);
return true;
}
// Para otros tipos primitivos, utilizamos BsonValue.Create
try
{
var bsonValue = BsonValue.Create(item.Value);
switch (bsonValue.BsonType)
{
case BsonType.Int32:
case BsonType.Int64:
stepsDictionary[key] = BsonSerializer.Deserialize<long>(reader);
break;
case BsonType.Double:
stepsDictionary[key] = BsonSerializer.Deserialize<double>(reader);
break;
case BsonType.String:
stepsDictionary[key] = BsonSerializer.Deserialize<string>(reader);
writer.WriteString(bsonValue.AsString);
break;
case BsonType.Int32:
writer.WriteInt32(bsonValue.AsInt32);
break;
case BsonType.Int64:
writer.WriteInt64(bsonValue.AsInt64);
break;
case BsonType.Double:
writer.WriteDouble(bsonValue.AsDouble);
break;
case BsonType.Boolean:
stepsDictionary[key] = BsonSerializer.Deserialize<bool>(reader);
writer.WriteBoolean(bsonValue.AsBoolean);
break;
case BsonType.Array:
reader.ReadStartArray();
var arrayItems = new List<object>();
while (reader.ReadBsonType() != BsonType.EndOfDocument)
switch (reader.CurrentBsonType)
writer.WriteStartArray();
foreach (var arrayValue in bsonValue.AsBsonArray)
switch (arrayValue.BsonType)
{
case BsonType.String:
arrayItems.Add(BsonSerializer.Deserialize<string>(reader));
writer.WriteString(arrayValue.AsString);
break;
case BsonType.Int32:
arrayItems.Add(BsonSerializer.Deserialize<int>(reader));
writer.WriteInt32(arrayValue.AsInt32);
break;
case BsonType.Int64:
arrayItems.Add(BsonSerializer.Deserialize<long>(reader));
break;
case BsonType.Boolean:
arrayItems.Add(BsonSerializer.Deserialize<bool>(reader));
writer.WriteInt64(arrayValue.AsInt64);
break;
case BsonType.Double:
arrayItems.Add(BsonSerializer.Deserialize<double>(reader));
writer.WriteDouble(arrayValue.AsDouble);
break;
case BsonType.ObjectId:
arrayItems.Add(BsonSerializer.Deserialize<ObjectId>(reader));
case BsonType.Boolean:
writer.WriteBoolean(arrayValue.AsBoolean);
break;
case BsonType.DateTime:
arrayItems.Add(BsonSerializer.Deserialize<DateTime>(reader));
break;
default:
reader.SkipValue();
break;
throw new BsonSerializationException(
$"No se puede serializar el tipo Bson en el array: {arrayValue.BsonType}");
}
reader.ReadEndArray();
stepsDictionary[key] = arrayItems;
writer.WriteEndArray();
break;
default:
var bsonDoc = BsonSerializer.Deserialize<BsonDocument>(reader);
stepsDictionary[key] = bsonDoc.ToDictionary();
break;
throw new NotSupportedException($"BsonType {bsonValue.BsonType} no es compatible.");
}
break;
}
}
reader.ReadEndDocument();
}
return stepsDictionary;
}
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args,
Dictionary<string, object> value)
{
var writer = context.Writer;
writer.WriteStartDocument();
foreach (var item in value)
{
if (TrySerializeKeyValuePair(item, writer)) continue;
// Si llegamos a este punto, encontramos un tipo no soportado.
writer.WriteName(item.Key);
writer.WriteNull(); // Escribe un valor null si el tipo no es soportado.
}
writer.WriteEndDocument();
}
private static bool TrySerializeKeyValuePair(KeyValuePair<string, object> item, IBsonWriter writer)
{
writer.WriteName(item.Key);
switch (item.Key)
{
case "steps":
if (item.Value is JArray jSteps)
{
var steps = jSteps.ToObject<List<Step>>();
BsonSerializer.Serialize(writer, typeof(List<Step>), steps);
return true;
}
break;
case "beacons":
if (item.Value is JArray jBeaconConfigs)
{
var beaconConfigs = jBeaconConfigs.ToObject<List<LightBeacon>>();
BsonSerializer.Serialize(writer, typeof(List<LightBeacon>), beaconConfigs);
return true;
}
break;
case "cameras":
if (item.Value is JArray jCamerasConfigs)
{
var cameraConfigs = jCamerasConfigs.ToObject<List<Camera>>();
BsonSerializer.Serialize(writer, typeof(List<Camera>), cameraConfigs);
return true;
}
break;
case "relay":
if (item.Value is JObject jRelayConfigs)
{
var relayConfigs = jRelayConfigs.ToObject<Relay>();
BsonSerializer.Serialize(writer, relayConfigs);
return true;
}
break;
case "uiFontProperties":
{
if (item.Value is JObject jUiFontData)
{
var uiFontData = jUiFontData.ToObject<UiFontData>();
BsonSerializer.Serialize(writer, uiFontData);
return true;
}
}
break;
default:
if (item.Value is Dictionary<string, object> nestedDictionary)
{
var bsonDoc = new BsonDocument(nestedDictionary);
BsonSerializer.Serialize(writer, bsonDoc);
return true;
}
if (item.Value is JArray jArray)
{
var listObjects = jArray.ToObject<List<object>>();
BsonSerializer.Serialize(writer, listObjects);
return true;
}
// Para otros tipos primitivos, utilizamos BsonValue.Create
try
{
var bsonValue = BsonValue.Create(item.Value);
switch (bsonValue.BsonType)
{
case BsonType.String:
writer.WriteString(bsonValue.AsString);
break;
case BsonType.Int32:
writer.WriteInt32(bsonValue.AsInt32);
break;
case BsonType.Int64:
writer.WriteInt64(bsonValue.AsInt64);
break;
case BsonType.Double:
writer.WriteDouble(bsonValue.AsDouble);
break;
case BsonType.Boolean:
writer.WriteBoolean(bsonValue.AsBoolean);
break;
case BsonType.Array:
writer.WriteStartArray();
foreach (var arrayValue in bsonValue.AsBsonArray)
switch (arrayValue.BsonType)
{
case BsonType.String:
writer.WriteString(arrayValue.AsString);
break;
case BsonType.Int32:
writer.WriteInt32(arrayValue.AsInt32);
break;
case BsonType.Int64:
writer.WriteInt64(arrayValue.AsInt64);
break;
case BsonType.Double:
writer.WriteDouble(arrayValue.AsDouble);
break;
case BsonType.Boolean:
writer.WriteBoolean(arrayValue.AsBoolean);
break;
default:
throw new BsonSerializationException(
$"No se puede serializar el tipo Bson en el array: {arrayValue.BsonType}");
}
writer.WriteEndArray();
break;
default:
throw new NotSupportedException($"BsonType {bsonValue.BsonType} no es compatible.");
return true;
}
return true;
}
catch (ArgumentException)
{
return false;
}
catch (ArgumentException)
{
return false;
}
}
return false;
}
return false;
}
}
@@ -4,58 +4,84 @@ using Newtonsoft.Json.Linq;
namespace adas_core.Domain.Models.BsonConverters;
/// <summary>
/// Represents a JSON converter that handles serialization and deserialization of dictionary types.
/// </summary>
/// <remarks>
/// Inherits from <see cref="JsonConverter"/> to provide custom conversion logic for dictionary-shaped data.
/// </remarks>
public class DictionaryConverter : JsonConverter
{
/// <summary>
/// Determines whether the converter can handle the specified type.
/// Returns <c>true</c> only when <paramref name="objectType"/> is exactly <see cref="Dictionary{TKey, TValue}"/> with string keys and object values.
/// </summary>
/// <param name="objectType">The type to evaluate for converter compatibility.</param>
/// <returns><c>true</c> if the type is <see cref="Dictionary{TKey, TValue}"/> of string and object; otherwise, <c>false</c>.</returns>
public override bool CanConvert(Type objectType)
{
return objectType == typeof(Dictionary<string, object>);
}
public override object ReadJson(JsonReader reader, Type objectType, object? existingValue,
JsonSerializer serializer)
{
var jo = JObject.Load(reader);
Dictionary<string, object> stepsDictionary = new();
foreach (var item in jo)
{
var key = item.Key;
switch (item.Key)
{
case "Steps":
var valueStep = item.Value?.ToObject<List<Step>>(serializer);
stepsDictionary.Add(key, valueStep ?? []);
break;
case "beacons":
var valueBeacon = item.Value?.ToObject<List<LightBeacon>>(serializer);
stepsDictionary.Add(key, valueBeacon ?? []);
break;
case "relay":
var valueRelay = item.Value?.ToObject<Relay>(serializer);
stepsDictionary.Add(key, valueRelay ?? new Relay());
break;
case "cameras":
var valueCameras = item.Value?.ToObject<List<Camera>>(serializer);
stepsDictionary.Add(key, valueCameras ?? []);
break;
default:
var valueDefault = item.Value?.ToObject<object>(serializer);
stepsDictionary.Add(key, valueDefault ?? new object());
break;
}
return objectType == typeof(Dictionary<string, object>);
}
return stepsDictionary;
}
/// <summary>
/// Deserializes a JSON object into a dictionary where each key maps to a strongly-typed value based on the property name. Handles "Steps" and "beacons" as lists of <see cref="Step"/> and <see cref="LightBeacon"/> respectively, "cameras" as a list of <see cref="Camera"/>, "relay" as a <see cref="Relay"/> instance, and stores any other properties as generic objects, using empty collections or default instances when the source value is null.
/// </summary>
/// <param name="reader">The JSON reader used to read the input token.</param>
/// <param name="objectType">The type of the object being deserialized.</param>
/// <param name="existingValue">The existing value of the object being read.</param>
/// <param name="serializer">The JSON serializer used to deserialize nested values.</param>
/// <returns>A dictionary containing the JSON properties mapped to their deserialized values.</returns>
public override object ReadJson(JsonReader reader, Type objectType, object? existingValue,
JsonSerializer serializer)
{
var jo = JObject.Load(reader);
Dictionary<string, object> stepsDictionary = new();
foreach (var item in jo)
{
var key = item.Key;
switch (item.Key)
{
case "Steps":
var valueStep = item.Value?.ToObject<List<Step>>(serializer);
stepsDictionary.Add(key, valueStep ?? []);
break;
case "beacons":
var valueBeacon = item.Value?.ToObject<List<LightBeacon>>(serializer);
stepsDictionary.Add(key, valueBeacon ?? []);
break;
case "relay":
var valueRelay = item.Value?.ToObject<Relay>(serializer);
stepsDictionary.Add(key, valueRelay ?? new Relay());
break;
case "cameras":
var valueCameras = item.Value?.ToObject<List<Camera>>(serializer);
stepsDictionary.Add(key, valueCameras ?? []);
break;
default:
var valueDefault = item.Value?.ToObject<object>(serializer);
stepsDictionary.Add(key, valueDefault ?? new object());
break;
}
}
return stepsDictionary;
}
/// <summary>
/// Serializes a dictionary of entries to JSON, writing each key-value pair as a JSON property using the provided serializer. Returns immediately when the value is null, leaving the writer untouched.
/// </summary>
/// <param name="writer">The JSON writer that receives the serialized output.</param>
/// <param name="value">The dictionary to serialize; if null, nothing is written.</param>
/// <param name="serializer">The serializer used to convert each dictionary value into a JSON token.</param>
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
if (value == null)
return;
var stepsDictionary = (Dictionary<string, object>)value;
var jo = new JObject();
foreach (var item in stepsDictionary) jo.Add(item.Key, JToken.FromObject(item.Value, serializer));
jo.WriteTo(writer);
}
{
if (value == null)
return;
var stepsDictionary = (Dictionary<string, object>)value;
var jo = new JObject();
foreach (var item in stepsDictionary) jo.Add(item.Key, JToken.FromObject(item.Value, serializer));
jo.WriteTo(writer);
}
}
+4
View File
@@ -1,5 +1,9 @@
namespace adas_core.Domain.Models;
/// <summary>
/// Represents a value used in a chart, typically encapsulating a data point or measurement
/// that can be plotted or rendered as part of a chart visualization.
/// </summary>
public class ChartValue
{
public List<string> Labels { get; set; } = [];
+3
View File
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Models;
/// <summary>
/// Represents a chat message, typically used to encapsulate the content and metadata exchanged in a chat conversation.
/// </summary>
public class ChatMessage
{
public PatientLocation? LocationFrom { get; set; }
+3
View File
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Models;
/// <summary>
/// Represents a code entity, serving as a base type for code-related constructs.
/// </summary>
public class Code
{
public string Identifier { get; set; } = string.Empty;
+39 -24
View File
@@ -3,36 +3,51 @@ using adas_core.Domain.Utils;
namespace adas_core.Domain.Models;
/// <summary>
/// Represents a code action that encapsulates an operation or transformation to be performed on code.
/// </summary>
public class CodeAction
{
public ActionsEnum.ResourceAction Action { get; set; }
public required Code Code { get; set; }
/// <summary>
/// Applies a list of <see cref="CodeAction"/> items and returns the resulting <see cref="Code"/> list, using the default (null) context by delegating to the contextual overload.
/// </summary>
/// <param name="actions">The list of code actions to apply.</param>
/// <returns>A <see cref="List{Code}"/> with the applied changes, or <c>null</c> if no codes are produced.</returns>
public static List<Code>? Apply(List<CodeAction> actions)
{
return Apply(null, actions);
}
public static List<Code>? Apply(List<Code>? source, List<CodeAction>? actions)
{
source ??= [];
(actions ?? []).ForEach(s =>
{
switch (s.Action)
{
case ActionsEnum.ResourceAction.Add:
if (!source.Contains(s.Code)) source.Add(s.Code);
break;
case ActionsEnum.ResourceAction.Delete:
if (source.Contains(s.Code)) source.Remove(s.Code);
break;
return Apply(null, actions);
}
case ActionsEnum.ResourceAction.Update:
if (source.Contains(s.Code)) source[source.IndexOf(s.Code)] = s.Code;
else source.Add(s.Code);
break;
}
});
return CollectionsUtils.NullIfEmpty(source);
}
/// <summary>
/// Applies a list of code actions to the source list, handling addition, deletion, and update operations while avoiding duplicates.
/// Returns null if the resulting source list is empty.
/// </summary>
/// <param name="source">The list of codes to modify. If null, an empty list is used as the starting point.</param>
/// <param name="actions">The list of code actions to apply. If null, the source list is returned unchanged.</param>
/// <returns>The modified list of codes, or null if the list is empty after applying the actions.</returns>
public static List<Code>? Apply(List<Code>? source, List<CodeAction>? actions)
{
source ??= [];
(actions ?? []).ForEach(s =>
{
switch (s.Action)
{
case ActionsEnum.ResourceAction.Add:
if (!source.Contains(s.Code)) source.Add(s.Code);
break;
case ActionsEnum.ResourceAction.Delete:
if (source.Contains(s.Code)) source.Remove(s.Code);
break;
case ActionsEnum.ResourceAction.Update:
if (source.Contains(s.Code)) source[source.IndexOf(s.Code)] = s.Code;
else source.Add(s.Code);
break;
}
});
return CollectionsUtils.NullIfEmpty(source);
}
}
+3
View File
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Models;
/// <summary>
/// Represents the status of a code-related operation or entity.
/// </summary>
public class CodeStatus
{
public Code? Code { get; set; }
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Models.DTO;
/// <summary>
/// Represents a data transfer object for transferring appointment information between application layers or services.
/// </summary>
public class AppointmentDto
{
public string PatientNumber { get; set; } = string.Empty;
+3
View File
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Models.DTO;
/// <summary>
/// Represents a data transfer object for conveying asset information between application layers or services.
/// </summary>
public class AssetDto
{
public string? Name { get; set; }
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Models.DTO;
/// <summary>
/// Represents a data transfer object used to convey configuration observation information between application layers.
/// </summary>
public class ConfigObservationDto
{
public string Id { get; set; } = string.Empty;
@@ -2,6 +2,9 @@
namespace adas_core.Domain.Models.DTO;
/// <summary>
/// Represents a data transfer object used to create a user along with authentication details.
/// </summary>
public class CreateUserWithAuthDto
{
public User User { get; set; } = new();
+9
View File
@@ -4,6 +4,9 @@ using MongoDB.Bson;
namespace adas_core.Domain.Models.DTO;
/// <summary>
/// Represents a data transfer object (DTO) used to encapsulate and transfer device-related information between application layers or services.
/// </summary>
public class DeviceDto
{
public DeviceEvent? Event { get; set; }
@@ -22,6 +25,12 @@ public class DeviceDto
public List<ObjectId>? PointOfCareIds { get; set; } = new();
public DeviceSettings? Settings { get; set; }
}
/// <summary>
/// Represents an event associated with a device, encapsulating information about a device-related occurrence or state change.
/// </summary>
/// <remarks>
/// This class is intended to be used as a data carrier for device event notifications or processing.
/// </remarks>
public class DeviceEvent
{
public ClickType? ClickType { get; set; }
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Models.DTO;
/// <summary>
/// Represents a data transfer object (DTO) for conveying diagnosis information between application layers or services.
/// </summary>
public class DiagnosisDto
{
public string PatientNumber { get; set; } = string.Empty;
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Models.DTO.Display;
/// <summary>
/// Represents a data transfer object (DTO) that encapsulates color configuration settings for transferring color-related data between application layers or systems.
/// </summary>
public class ColorConfigDto
{
public LevelColors? Level { get; set; }
@@ -12,6 +15,9 @@ public class ColorConfigDto
public TestColors? Test { get; set; }
public ProcedureColors? Procedure { get; set; }
/// <summary>
/// Represents configuration settings that define the visual appearance, such as colors, themes, or styling preferences.
/// </summary>
public class AppearanceSettings
{
public string? TextColor { get; set; }
@@ -24,6 +30,12 @@ public class ColorConfigDto
public double? IconInvertColor { get; set; }
}
/// <summary>
/// Represents the color settings used for rendering numeric values within a status box.
/// </summary>
/// <remarks>
/// This type is intended to encapsulate the visual color configuration associated with the numeric portion of a status box display.
/// </remarks>
public class StatusBoxNumberColors
{
public AppearanceSettings? Reserved { get; set; }
@@ -35,6 +47,9 @@ public class ColorConfigDto
public AppearanceSettings? Altable { get; set; }
}
/// <summary>
/// Provides a centralized set of color values used throughout the therapy-related user interface or visual components.
/// </summary>
public class TherapyColors
{
public AppearanceSettings? Default { get; set; }
@@ -43,6 +58,9 @@ public class ColorConfigDto
public AppearanceSettings? InProgress { get; set; }
}
/// <summary>
/// Provides a collection of color values intended for use in test scenarios.
/// </summary>
public class TestColors
{
public AppearanceSettings? Default { get; set; }
@@ -51,6 +69,9 @@ public class ColorConfigDto
public AppearanceSettings? Expired { get; set; }
}
/// <summary>
/// Represents a collection of color definitions used to visually represent procedures.
/// </summary>
public class ProcedureColors
{
public AppearanceSettings? Default { get; set; }
@@ -59,6 +80,12 @@ public class ColorConfigDto
public AppearanceSettings? Expired { get; set; }
}
/// <summary>
/// Represents a set of colors associated with level rendering or visual state.
/// </summary>
/// <remarks>
/// Used to centralize color definitions related to level display, allowing consistent theming across level-related UI elements.
/// </remarks>
public class LevelColors
{
public string? Level1 { get; set; }
@@ -68,6 +95,9 @@ public class ColorConfigDto
public string? Level5 { get; set; }
}
/// <summary>
/// Represents a collection of predefined text color values or definitions for styling text output.
/// </summary>
public class TextColors
{
public string? Normal { get; set; }
@@ -77,6 +107,9 @@ public class ColorConfigDto
public string? Expired { get; set; }
}
/// <summary>
/// Provides a set of predefined color values used for rendering arrows in charts or visualizations.
/// </summary>
public class ArrowColors
{
public string? Normal { get; set; }
@@ -85,6 +118,9 @@ public class ColorConfigDto
public string? Improve { get; set; }
}
/// <summary>
/// Represents a collection or definition of colors used to visually style an indicator.
/// </summary>
public class IndicatorColors
{
public string? Empty { get; set; }
@@ -95,6 +131,9 @@ public class ColorConfigDto
public string? EmptyBackground { get; set; }
}
/// <summary>
/// Represents a collection or definition of colors used for rendering graphs and chart elements.
/// </summary>
public class GraphColors
{
public string? Normal { get; set; }
@@ -4,6 +4,9 @@ using MongoDB.Bson;
namespace adas_core.Domain.Models.DTO.Display;
/// <summary>
/// Represents a data transfer object used to create a new display configuration.
/// </summary>
public class CreateDisplayConfigDto
{
public DisplayConfigEnums.DisplayType Type { get; set; } =
@@ -14,6 +17,9 @@ public class CreateDisplayConfigDto
public string? DisplayConfigIdTemplate { get; set; }
}
/// <summary>
/// Represents a data transfer object used to create a display configuration card.
/// </summary>
public class CreateDisplayConfigCardDto
{
public CardConfig? CardConfig { get; set; }
@@ -5,6 +5,9 @@ using MongoDB.Bson;
namespace adas_core.Domain.Models.DTO.Display;
/// <summary>
/// Represents a data transfer object for display configuration settings.
/// </summary>
public class DisplayConfigDto
{
public ObjectId Id { get; set; }
@@ -1,5 +1,11 @@
namespace adas_core.Domain.Models.DTO.Display;
/// <summary>
/// Represents a data transfer object that encapsulates display configuration and location information.
/// </summary>
/// <remarks>
/// This DTO is used to transfer display configuration settings along with their associated location data between application layers.
/// </remarks>
public class DisplayConfigLocationDto
{
public string? DisplayName { get; set; }
@@ -3,6 +3,9 @@ using MongoDB.Bson;
namespace adas_core.Domain.Models.DTO.Display;
/// <summary>
/// Represents a summary of display configuration settings, providing a consolidated view of display-related parameters.
/// </summary>
public class DisplayConfigSummary
{
public ObjectId Id { get; set; }
@@ -3,6 +3,9 @@ using MongoDB.Bson;
namespace adas_core.Domain.Models.DTO.Display;
/// <summary>
/// Represents a minimal data transfer object that encapsulates a subset of fields from a <see cref="MongoModels.Display"/> model for lightweight serialization or transfer.
/// </summary>
public class DisplayMinimalDto(MongoModels.Display display)
{
public ObjectId Id { get; set; } = display.Id;
@@ -2,6 +2,9 @@
namespace adas_core.Domain.Models.DTO.Display;
/// <summary>
/// Represents a data transfer object used for displaying nurse information, extending the base display configuration functionality provided by <see cref="DisplayConfigDto"/>.
/// </summary>
public class DisplayNurseDto : DisplayConfigDto
{
public List<BannerItem>? HomeBanner { get; set; }
@@ -2,6 +2,12 @@
namespace adas_core.Domain.Models.DTO.Display;
/// <summary>
/// Represents a data transfer object that combines display-related information with associated permissions.
/// </summary>
/// <remarks>
/// This DTO is intended for transferring presentation data together with the permissions required to view or interact with it.
/// </remarks>
public class DisplayWithPermissionsDto
{
public DisplayPermissionTypes? Permissions { get; set; }
@@ -2,6 +2,9 @@ using adas_core.Domain.Models.MongoModels;
namespace adas_core.Domain.Models.DTO.Display;
/// <summary>
/// Represents a data transfer object that provides a minimal representation of a display list for transfer between application layers.
/// </summary>
public class MinimalDisplayListDto
{
public List<MinimalDisplaySection> DisplayNurse { get; set; } = [];
@@ -3,6 +3,9 @@ using adas_core.Domain.Models.MongoModels;
namespace adas_core.Domain.Models.DTO.Display;
/// <summary>
/// Represents a data transfer object for a smart display configuration, extending the base display configuration with additional smart display properties.
/// </summary>
public class SmartDisplayDto : DisplayConfigDto
{
public bool? HasCameras { get; set; }
@@ -1,5 +1,11 @@
namespace adas_core.Domain.Models.DTO.Display;
/// <summary>
/// Represents a data transfer object used to update the name of a display configuration.
/// </summary>
/// <remarks>
/// This DTO is intended to carry the necessary information to modify the name of an existing display configuration entity.
/// </remarks>
public class UpdateDisplayConfigNameDto
{
public string DisplayName { get; set; } = string.Empty;
@@ -3,6 +3,9 @@ using MongoDB.Bson;
namespace adas_core.Domain.Models.DTO;
/// <summary>
/// Represents a data transfer object for a master list, used to transfer collection data between application layers.
/// </summary>
public class MasterListDto
{
public ObjectId Id { get; set; }
@@ -4,6 +4,12 @@ using MongoDB.Bson;
namespace adas_core.Domain.Models.DTO;
/// <summary>
/// Represents a data transfer object that combines a master list with pagination options and a collection of unit information items.
/// </summary>
/// <remarks>
/// This DTO packages a <see cref="MasterList"/> together with the configured <c>pageSize</c> and a list of <see cref="UnitInfoDto"/> entries for transport across application boundaries.
/// </remarks>
public class MasterListWithPaginatedOptionsDto(MasterList masterList, int pageSize, List<UnitInfoDto> units)
{
public ObjectId Id { get; set; } = masterList.Id;
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Models.DTO;
/// <summary>
/// Represents a data transfer object for an observation alarm, used to encapsulate and transfer alarm-related information between application layers.
/// </summary>
public class ObservationAlarmDto
{
public string? PatientNumber { get; set; }
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Models.DTO;
/// <summary>
/// Represents a data transfer object for an observation, used to transfer observation data between application layers or services.
/// </summary>
public class ObservationDto
{
public string PatientNumber { get; set; } = string.Empty;
@@ -2,6 +2,12 @@
namespace adas_core.Domain.Models.DTO;
/// <summary>
/// Represents a data transfer object (DTO) that encapsulates a pair of pagination-related values for transport between layers or services.
/// </summary>
/// <remarks>
/// Typically used to convey paired pagination metadata, such as a page number together with a page size or total count, in request or response payloads.
/// </remarks>
public class PaginationPairDto
{
public PaginationFilter ListFilter { get; set; } = new();
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Models.DTO;
/// <summary>
/// Represents a data transfer object used to encapsulate and transfer patient information between application layers or services.
/// </summary>
public class PatientDto
{
public string PatientNumber { get; set; } = string.Empty;
@@ -2,11 +2,17 @@
namespace adas_core.Domain.Models.DTO;
/// <summary>
/// Represents a data transfer object that encapsulates point of contact and unit information for transfer between application layers or systems.
/// </summary>
public class PocAndUnitDto
{
public List<MinimalPocAndUnitDto> PocList { get; set; } = [];
}
/// <summary>
/// Represents a minimal data transfer object encapsulating point of consumption and unit information.
/// </summary>
public class MinimalPocAndUnitDto
{
public string? PocName { get; set; }
@@ -5,6 +5,9 @@ using LightBeacon = adas_core.Domain.Models.MongoModels.LightBeacon;
namespace adas_core.Domain.Models.DTO;
/// <summary>
/// Represents a data transfer object for point-of-care information, used to transfer point-of-care data between application layers or services.
/// </summary>
public class PointOfCareDto
{
@@ -32,6 +35,9 @@ public class PointOfCareDto
#endregion
}
/// <summary>
/// Represents a data transfer object (DTO) for point-of-care configuration settings, used to transfer configuration data between layers or systems.
/// </summary>
public class PointOfCareConfigurationDto
{
public List<LightBeacon> BeaconList { get; set; } = [];
+3
View File
@@ -2,6 +2,9 @@
namespace adas_core.Domain.Models.DTO;
/// <summary>
/// Represents a data transfer object for conveying pump-related information between application layers.
/// </summary>
public class PumpDto
{
public string PatientNumber { get; set; } = string.Empty;
@@ -2,6 +2,9 @@
namespace adas_core.Domain.Models.DTO;
/// <summary>
/// Represents a data transfer object used to convey information about a recording alert between application layers or services.
/// </summary>
public class RecordingAlertDto
{
public string? PatientNumber { get; set; }
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Models.DTO;
/// <summary>
/// Represents a data transfer object for conveying treatment information between application layers.
/// </summary>
public class TreatmentDto
{
public string PatientNumber { get; set; } = string.Empty;
@@ -4,6 +4,9 @@ using MongoDB.Bson;
namespace adas_core.Domain.Models.DTO;
/// <summary>
/// Represents a data transfer object that encapsulates information about a unit.
/// </summary>
public class UnitInfoDto
{
[JsonConstructor]
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Models.DTO;
/// <summary>
/// Represents a data transfer object used to update the name and description of a list.
/// </summary>
public class UpdateListNameAndDescriptionDto
{
public string? Name { get; set; }
@@ -2,6 +2,9 @@ using adas_core.Domain.Models.Masters;
namespace adas_core.Domain.Models.DTO;
/// <summary>
/// Represents a data transfer object used to transfer updated master list details between application layers.
/// </summary>
public class UpdateMasterListDetailsDto
{
public bool? CanAddElement { get; set; }
@@ -2,6 +2,9 @@
namespace adas_core.Domain.Models.DTO;
/// <summary>
/// Represents a data transfer object used to update an existing observation.
/// </summary>
public class UpdateObservationDto
{
public ConfigObservation? OldConfigObservationItem { get; set; }
@@ -2,6 +2,9 @@ using adas_core.Domain.Models.Masters;
namespace adas_core.Domain.Models.DTO;
/// <summary>
/// Represents a data transfer object used to update an option master list.
/// </summary>
public class UpdateOptionMasterListDto
{
public OptionList? UpdatedOption { get; set; }
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Models.DTO;
/// <summary>
/// Represents a data transfer object used to encapsulate the information required to update a user's password.
/// </summary>
public class UpdatePasswordDto
{
public string OldPassword { get; set; } = string.Empty;
@@ -3,36 +3,51 @@ using MongoDB.Bson;
namespace adas_core.Domain.Models.DTO;
/// <summary>
/// Represents a data transfer object used to update a list of unit identifiers.
/// </summary>
public class UpdateUnitIdListDto
{
public ObjectId UnitId { get; set; }
public List<MasterListData> MasterListData { get; set; } = [];
/// <summary>
/// Returns a string representation of the <see cref="UpdateUnitIdListDto"/> instance, including the formatted entries of its <c>MasterListData</c> collection.
/// </summary>
/// <returns>A string in the format <c>UpdateUnitIdListDto[...</c> containing the concatenated <c>MasterListData</c> values.</returns>
public override string ToString()
{
List<string> items = [];
items.AddRange(MasterListData.Select(masterListData => $", MasterListData: {masterListData}"));
return "UpdateUnitIdListDto[" + string.Join(", ", items) + "]";
}
{
List<string> items = [];
items.AddRange(MasterListData.Select(masterListData => $", MasterListData: {masterListData}"));
return "UpdateUnitIdListDto[" + string.Join(", ", items) + "]";
}
}
/// <summary>
/// Represents a data container for a master list, serving as a centralized collection of items used for reference or aggregation purposes.
/// </summary>
public class MasterListData
{
public ObjectId? MasterListId { get; set; }
public MasterListType? MasterListType { get; set; }
/// <summary>
/// Returns a string representation of the master list, formatted with its identifier and type enclosed in square brackets.
/// Handles null values for <c>MasterListId</c> and <c>MasterListType</c> by displaying them as "Null" and "null" respectively.
/// </summary>
/// <returns>A formatted string containing the identifier and type of the master list.</returns>
public override string ToString()
{
List<string> items =
[
MasterListId != null ? $"identifier: {MasterListId.ToString()}" : "identifier: Null",
MasterListType != null ? $"type: {MasterListType.ToString()}" : "type: null"
];
return "[" + string.Join(", ", items) + "]";
}
{
List<string> items =
[
MasterListId != null ? $"identifier: {MasterListId.ToString()}" : "identifier: Null",
MasterListType != null ? $"type: {MasterListType.ToString()}" : "type: null"
];
return "[" + string.Join(", ", items) + "]";
}
}
@@ -2,6 +2,12 @@
namespace adas_core.Domain.Models.DTO;
/// <summary>
/// Represents a data transfer object used to update a user along with their authentication details.
/// </summary>
/// <remarks>
/// This DTO is typically used to transfer user account and authentication information in update operations.
/// </remarks>
public class UpdateUserWithAuthDto
{
public User User { get; set; } = new();
+6
View File
@@ -1,5 +1,11 @@
namespace adas_core.Domain.Models;
/// <summary>
/// Represents a general-purpose entity within the application domain.
/// </summary>
/// <remarks>
/// Serves as a foundational or domain-level type that can be extended or composed to model real-world concepts.
/// </remarks>
public class Entity
{
public string? EntityIdentifier { get; set; }
@@ -2,6 +2,9 @@
namespace adas_core.Domain.Models.Filter;
/// <summary>
/// Represents an individual element within a filter option list, encapsulating a selectable filter value and its associated metadata.
/// </summary>
public class FilterOptionListElement
{
public string? OptionType { get; set; }
@@ -2,6 +2,12 @@
namespace adas_core.Domain.Models.Filter;
/// <summary>
/// Represents a request that has been filtered or contains filtering criteria.
/// </summary>
/// <remarks>
/// This type serves as a container for request data that has been narrowed or constrained by a filtering process.
/// </remarks>
public class FilteredRequest
{
#region Common region
@@ -17,25 +17,38 @@ public record PaginationFilter
public int PageSize { get; set; } = 100;
public FilteredRequest? FilteredRequest { get; set; }
/// <summary>
/// Determines whether the pagination state is considered empty by checking if both <c>PageNumber</c> and <c>PageSize</c> are less than or equal to zero.
/// </summary>
/// <returns><c>true</c> if both <c>PageNumber</c> and <c>PageSize</c> are less than or equal to zero; otherwise, <c>false</c>.</returns>
public bool IsEmpty()
{
return PageNumber <= 0 && PageSize <= 0;
}
{
return PageNumber <= 0 && PageSize <= 0;
}
}
/// <summary>
/// Provides static extension methods for working with pagination filter objects.
/// </summary>
public static class PaginationFilterExtensions
{
/// <summary>
/// Applies pagination to the source queryable using the provided <see cref="PaginationFilter"/>, skipping the appropriate number of records and taking the requested page size. If the filter is <c>null</c> or contains an invalid page number (less than 0) or page size (not greater than 0), the original queryable is returned unchanged.
/// </summary>
/// <param name="queryable">The source <see cref="IQueryable{T}"/> to paginate.</param>
/// <param name="filter">The pagination settings containing the page number and page size. If <c>null</c> or invalid, no pagination is applied.</param>
/// <returns>The paginated <see cref="IQueryable{T}"/>, or the original queryable when the filter is <c>null</c> or contains invalid values.</returns>
public static IQueryable<T> ApplyPagination<T>(this IQueryable<T> queryable, PaginationFilter? filter)
{
var modifQueryable = queryable;
if (filter is not { PageNumber: >= 0, PageSize: > 0 }) return modifQueryable;
var pageNumber = filter.PageNumber;
var pageSize = filter.PageSize;
modifQueryable = modifQueryable
.Skip((pageNumber - 1) * pageSize)
.Take(pageSize)
;
return modifQueryable;
}
{
var modifQueryable = queryable;
if (filter is not { PageNumber: >= 0, PageSize: > 0 }) return modifQueryable;
var pageNumber = filter.PageNumber;
var pageSize = filter.PageSize;
modifQueryable = modifQueryable
.Skip((pageNumber - 1) * pageSize)
.Take(pageSize)
;
return modifQueryable;
}
}
+51 -30
View File
@@ -3,6 +3,9 @@ using MongoDB.Bson;
namespace adas_core.Domain.Models;
/// <summary>
/// Represents an observation that belongs to or has been categorized within a logical group.
/// </summary>
public class GroupedObservation
{
public ObjectId PatientId { get; set; }
@@ -13,16 +16,23 @@ public class GroupedObservation
public List<GroupedObservationObs> Observations { get; set; } = [];
/// <summary>
/// Returns a string representation of the PatientObservation, including the patient's name and observations in a formatted output.
/// </summary>
/// <returns>A formatted string in the form "PatientObservation[name: ..., observations: ...]".</returns>
public override string ToString()
{
List<string> items =
[
$"name: {Name}",
$"observations: {Observations} "
];
return "PatientObservation[" + string.Join(", ", items) + "]";
}
{
List<string> items =
[
$"name: {Name}",
$"observations: {Observations} "
];
return "PatientObservation[" + string.Join(", ", items) + "]";
}
/// <summary>
/// Represents a grouped collection of observations.
/// </summary>
public class GroupedObservationObs
{
public string Name { get; set; } = string.Empty;
@@ -57,28 +67,35 @@ public class GroupedObservation
public bool IsFilled { get; set; }
/// <summary>
/// Returns a string representation of the GroupedObservationObs, including the name and any non-null statistical properties (first, last, min, max, average, sum, count, half-hour, min alert, max alert), along with the time, shift date, and optional shift.
/// </summary>
/// <returns>A formatted string in the form "GroupedObservationObs[name: ..., ...]" summarizing the object's relevant properties.</returns>
public override string ToString()
{
List<string> items = [$"name: {Name}"];
if (First != null) items.Add($"first; {First}");
if (Last != null) items.Add($"last; {Last}");
if (Min != null) items.Add($"min; {Min}");
if (Max != null) items.Add($"max; {Max}");
if (Average != null) items.Add($"average; {Average}");
if (Sum != null) items.Add($"sum; {Sum}");
if (Count != null) items.Add($"count; {Count}");
if (HalfHour != null) items.Add($"halfhour; {HalfHour}");
if (MinAlert != null) items.Add($"minAlert; {MinAlert}");
if (MaxAlert != null) items.Add($"maxAlert; {MaxAlert}");
items.Add($"time; {Time}");
items.Add($"shiftDate; {ShiftDate}");
if (Shift != null) items.Add($"shift; {Shift}");
return "GroupedObservationObs[" + string.Join(", ", items) + "]";
}
{
List<string> items = [$"name: {Name}"];
if (First != null) items.Add($"first; {First}");
if (Last != null) items.Add($"last; {Last}");
if (Min != null) items.Add($"min; {Min}");
if (Max != null) items.Add($"max; {Max}");
if (Average != null) items.Add($"average; {Average}");
if (Sum != null) items.Add($"sum; {Sum}");
if (Count != null) items.Add($"count; {Count}");
if (HalfHour != null) items.Add($"halfhour; {HalfHour}");
if (MinAlert != null) items.Add($"minAlert; {MinAlert}");
if (MaxAlert != null) items.Add($"maxAlert; {MaxAlert}");
items.Add($"time; {Time}");
items.Add($"shiftDate; {ShiftDate}");
if (Shift != null) items.Add($"shift; {Shift}");
return "GroupedObservationObs[" + string.Join(", ", items) + "]";
}
}
/// <summary>
/// Represents an observed value within a grouped observation, pairing a value with an optional timestamp and status type.
/// </summary>
public class GroupedObservationObsValue(object value, DateTime? time, StatusEnum.Type type = StatusEnum.Type.Ok)
{
public StatusEnum.Type Type { get; set; } = type;
@@ -88,9 +105,13 @@ public class GroupedObservation
public DateTime? Time { get; set; } = time;
/// <summary>
/// Returns a formatted string representation of the object, including its value, time, and type/status fields.
/// </summary>
/// <returns>A string containing the value, time, and type of the object.</returns>
public override string ToString()
{
return $"value: {Value}, time: {Time}, status: {Type}";
}
{
return $"value: {Value}, time: {Time}, status: {Type}";
}
}
}
@@ -1,5 +1,11 @@
namespace adas_core.Domain.Models.GroupedObservations;
/// <summary>
/// Represents a field, typically used to encapsulate data or a value within a larger structure or system.
/// </summary>
/// <remarks>
/// As a public class, it is accessible from any other code that can reference its containing namespace or assembly.
/// </remarks>
public class Field
{
public string? Name { get; set; }
@@ -2,6 +2,12 @@
namespace adas_core.Domain.Models.GroupedObservations;
/// <summary>
/// Represents a field that belongs to a logical grouping, encapsulating the concept of a field within a grouped structure.
/// </summary>
/// <remarks>
/// This type is intended to model fields that are organized together as part of a group, allowing related field metadata or behavior to be handled collectively.
/// </remarks>
public class GroupedField
{
public GroupedField()
@@ -48,18 +54,33 @@ public class GroupedField
public List<string>? LabelList { get; init; }
/// <summary>
/// Retrieves the list of names stored in the current instance.
/// </summary>
/// <returns>A <see cref="List{String}"/> containing the names; returns the underlying field directly without copying or filtering.</returns>
public List<string> GetNames()
{
return Names;
}
{
return Names;
}
/// <summary>
/// Determines whether the specified object is equal to the current <see cref="GroupedField"/> by comparing their <c>Group</c> property values.
/// Returns <c>true</c> only when <paramref name="obj"/> is a <see cref="GroupedField"/> instance with a matching <c>Group</c>; otherwise returns <c>false</c> (including for <c>null</c> or non-matching types).
/// </summary>
/// <param name="obj">The object to compare with the current instance.</param>
/// <returns><c>true</c> if the specified object is a <see cref="GroupedField"/> with the same <c>Group</c>; otherwise, <c>false</c>.</returns>
public override bool Equals(object? obj)
{
return obj is GroupedField field && Group == field.Group;
}
{
return obj is GroupedField field && Group == field.Group;
}
/// <summary>
/// Computes a hash code for the current instance by combining the values of its key properties: Name, Group, Max, Regularity, and Result.
/// This override ensures consistent hash-based behavior for equality comparisons and use in hash-based collections.
/// </summary>
/// <returns>An integer hash code derived from the object's key properties.</returns>
public override int GetHashCode()
{
return HashCode.Combine(Name, Group, Max, Regularity, Result);
}
{
return HashCode.Combine(Name, Group, Max, Regularity, Result);
}
}
+32 -5
View File
@@ -1,5 +1,11 @@
namespace adas_core.Domain.Models;
/// <summary>
/// Represents a historical location and provides type-safe equality comparison between instances of <see cref="HistoricalLocation"/>.
/// </summary>
/// <remarks>
/// Implements <see cref="IEquatable{T}"/> of <see cref="HistoricalLocation"/> to allow instances to be compared for value equality without relying on object identity.
/// </remarks>
public class HistoricalLocation : IEquatable<HistoricalLocation>
{
// Propiedades con get y set para que MongoDB pueda escribir en ellas
@@ -7,6 +13,9 @@ public class HistoricalLocation : IEquatable<HistoricalLocation>
public PatientLocation? PatientLocation { get; set; }
// Constructor vacío necesario para la deserialización de MongoDB
/// <summary>
/// Initializes a new instance of the <see cref="HistoricalLocation"/> class, which represents a historical record of a location.
/// </summary>
public HistoricalLocation() { }
// Tu constructor actual
@@ -16,16 +25,34 @@ public class HistoricalLocation : IEquatable<HistoricalLocation>
PatientLocation = patientLocation ?? throw new ArgumentNullException(nameof(patientLocation));
}
/// <summary>
/// Determines whether the current <see cref="HistoricalLocation"/> instance is equal to another instance,
/// based on the admission time and the patient location (when present, with null locations treated as equal).
/// </summary>
/// <param name="other">The other <see cref="HistoricalLocation"/> instance to compare with this one.</param>
/// <returns><c>true</c> if both the admission time and patient location match; otherwise, <c>false</c>.</returns>
public bool Equals(HistoricalLocation? other)
{
if (other == null) return false;
return AdmTime == other.AdmTime &&
(PatientLocation?.Equals(other.PatientLocation) ?? other.PatientLocation == null);
}
{
if (other == null) return false;
return AdmTime == other.AdmTime &&
(PatientLocation?.Equals(other.PatientLocation) ?? other.PatientLocation == null);
}
/// <summary>
/// Determines whether this instance is considered empty by verifying that no admission time is set and that the patient location is either null or empty.
/// </summary>
/// <returns><see langword="true"/> when <c>AdmTime</c> has no value and <c>PatientLocation</c> is <see langword="null"/> or empty; otherwise, <see langword="false"/>.</returns>
public bool IsEmpty() => !AdmTime.HasValue && (PatientLocation == null || PatientLocation.IsEmpty());
/// <summary>
/// Determines whether the instance is in a full state by verifying that an admission time has been set, a patient location is assigned, and the assigned location is not full or empty.
/// </summary>
/// <returns><c>true</c> when <see cref="AdmTime"/> has a value, <see cref="PatientLocation"/> is not null, and the location is not full or empty; otherwise, <c>false</c>.</returns>
public bool IsFull() => AdmTime.HasValue && PatientLocation != null && !PatientLocation.IsFullEmpty();
/// <summary>
/// Returns a string representation of the HistoricalLocation, including the admission time and patient location.
/// </summary>
/// <returns>A formatted string with the values of <c>AdmTime</c> and <c>PatientLocation</c>.</returns>
public override string ToString() => $"HistoricalLocation[AdmTime: {AdmTime}, PatientLocation: {PatientLocation}]";
}
@@ -1,5 +1,8 @@
namespace adas_core.Domain.Models;
/// <summary>
/// Represents a manual recording entity, typically used to capture or track recording operations initiated explicitly by a user or system.
/// </summary>
public class ManualRecording
{
//[JsonProperty("patientId")]
@@ -11,6 +14,12 @@ public class ManualRecording
public MRecording? Recording { get; set; }
}
/// <summary>
/// Represents a recording entity, likely encapsulating data and behavior related to media or event capture and playback.
/// </summary>
/// <remarks>
/// This class serves as a model or container for recording-related operations within the application.
/// </remarks>
public class MRecording
{
public DateTime? StartRecordingTime { get; set; }
@@ -1,3 +1,9 @@
namespace adas_core.Domain.Models.Masters;
/// <summary>
/// Represents an access control list, derived from <see cref="MasterList"/>, used to organize and manage a collection of access control entries or permissions.
/// </summary>
/// <remarks>
/// As a subclass of <see cref="MasterList"/>, it inherits the core list management capabilities while specializing them for access control scenarios.
/// </remarks>
public class AccessControlList : MasterList;
@@ -1,3 +1,9 @@
namespace adas_core.Domain.Models.Masters;
/// <summary>
/// Represents a list of allergy entries, inheriting common list behavior from the MasterList base class.
/// </summary>
/// <remarks>
/// Provides a domain-specific list type dedicated to managing and organizing allergy records.
/// </remarks>
public class AllergyList : MasterList;
@@ -1,3 +1,6 @@
namespace adas_core.Domain.Models.Masters;
/// <summary>
/// Represents a list of alterable options, inheriting core list functionality from the <see cref="MasterList"/> base class.
/// </summary>
public class AltableOptionList : MasterList;
@@ -1,3 +1,9 @@
namespace adas_core.Domain.Models.Masters;
/// <summary>
/// Represents a list of destinations, deriving its base functionality from the <see cref="MasterList"/> class.
/// </summary>
/// <remarks>
/// Serves as a concrete list type within the master list hierarchy, specifically tailored for destination-related collections.
/// </remarks>
public class DestinationList : MasterList;
@@ -1,3 +1,6 @@
namespace adas_core.Domain.Models.Masters;
/// <summary>
/// Represents a specialized list of diagnosis entries, extending the base <see cref="MasterList"/> functionality.
/// </summary>
public class DiagnosisList : MasterList;
@@ -1,3 +1,6 @@
namespace adas_core.Domain.Models.Masters;
/// <summary>
/// Represents a typed master list of discharge statuses, deriving from the base <see cref="MasterList"/> class.
/// </summary>
public class DischargeStatusList : MasterList;
@@ -1,3 +1,9 @@
namespace adas_core.Domain.Models.Masters;
/// <summary>
/// Represents a collection of doctor entries, deriving its core list functionality from the <see cref="MasterList"/> base class.
/// </summary>
/// <remarks>
/// Serves as a specialized list type for doctor-related data, extending the shared behavior provided by <see cref="MasterList"/>.
/// </remarks>
public class DoctorList : MasterList;
@@ -1,3 +1,9 @@
namespace adas_core.Domain.Models.Masters;
/// <summary>
/// Represents a master list of doctor types, extending the base <see cref="MasterList"/> class.
/// </summary>
/// <remarks>
/// This class serves as a specialized collection that inherits the core list behavior from <see cref="MasterList"/>, tailored for managing doctor type entries.
/// </remarks>
public class DoctorTypeList : MasterList;
@@ -1,3 +1,6 @@
namespace adas_core.Domain.Models.Masters;
/// <summary>
/// Represents a generic list type that derives from <see cref="MasterList"/>, extending the base master list functionality.
/// </summary>
public class GenericList : MasterList;
@@ -1,3 +1,7 @@
namespace adas_core.Domain.Models.Masters;
/// <summary>
/// Represents a specialized list that manages insulation-related entries within the system.
/// Inherits from <see cref="MasterList"/>, providing a dedicated collection for organizing and handling insulation data.
/// </summary>
public class InsulationList : MasterList;
@@ -1,3 +1,9 @@
namespace adas_core.Domain.Models.Masters;
/// <summary>
/// Represents an internal list of destinations, derived from the base <see cref="MasterList"/> class.
/// </summary>
/// <remarks>
/// This type specializes the <see cref="MasterList"/> behavior for internal destination handling within the containing system.
/// </remarks>
public class InternalDestinationList : MasterList;
@@ -1,3 +1,9 @@
namespace adas_core.Domain.Models.Masters;
/// <summary>
/// Represents a specialized master list that manages entries related to language barriers.
/// </summary>
/// <remarks>
/// Inherits from <see cref="MasterList"/>, extending its functionality for handling language barrier data.
/// </remarks>
public class LanguageBarrierList : MasterList;
@@ -3,6 +3,12 @@ using MongoDB.Bson;
namespace adas_core.Domain.Models.Masters;
/// <summary>
/// Represents a master list, serving as a centralized collection for managing a comprehensive set of items.
/// </summary>
/// <remarks>
/// This class provides a foundational structure for organizing and accessing a primary list of entries.
/// </remarks>
public class MasterList
{
public ObjectId Id { get; set; }
@@ -81,6 +87,12 @@ public class MasterList
}
}
/// <summary>
/// Represents a container that holds detailed information about a list of options.
/// </summary>
/// <remarks>
/// This type is intended to encapsulate the metadata or structure associated with an option list, allowing consumers to access its detailed content in a structured manner.
/// </remarks>
public class OptionListDetails
{
public Element? OptionType { get; set; }
@@ -93,6 +105,9 @@ public class OptionListDetails
public Element? Description { get; set; }
}
/// <summary>
/// Represents a generic element within the system, serving as a foundational type that can be extended or composed to model domain-specific entities or structures.
/// </summary>
public class Element
{
public string Title { get; set; } = string.Empty;

Some files were not shown because too many files have changed in this diff Show More