1229 lines
54 KiB
C#
1229 lines
54 KiB
C#
using System.Data;
|
|
using System.Globalization;
|
|
using System.Security.Cryptography;
|
|
using ApiDenuncias.Configuration;
|
|
using GestionaDenuncias.Shared.Models;
|
|
using Microsoft.Extensions.Options;
|
|
using MySqlConnector;
|
|
|
|
namespace ApiDenuncias.Services;
|
|
|
|
public sealed class MySqlDenunciaStore : IDenunciaStore
|
|
{
|
|
private static readonly (string Table, string Column, string Definition)[] SchemaColumnsToEnsure =
|
|
[
|
|
("complaints", "gestiona_file_code", "`gestiona_file_code` VARCHAR(128) NOT NULL DEFAULT ''"),
|
|
("complaints", "reporter_kind", "`reporter_kind` VARCHAR(128) NOT NULL DEFAULT ''"),
|
|
("complaints", "is_legal_entity", "`is_legal_entity` TINYINT(1) NOT NULL DEFAULT 0"),
|
|
("complaints", "reporter_first_surname", "`reporter_first_surname` VARCHAR(256) NOT NULL DEFAULT ''"),
|
|
("complaints", "reporter_second_surname", "`reporter_second_surname` VARCHAR(256) NOT NULL DEFAULT ''"),
|
|
("complaints", "reporter_business_name", "`reporter_business_name` VARCHAR(256) NOT NULL DEFAULT ''"),
|
|
("complaints", "reporter_document_type", "`reporter_document_type` VARCHAR(128) NOT NULL DEFAULT ''"),
|
|
("complaints", "reporter_origin_country", "`reporter_origin_country` VARCHAR(128) NOT NULL DEFAULT ''"),
|
|
("complaints", "accused_party_details", "`accused_party_details` VARCHAR(512) NOT NULL DEFAULT ''"),
|
|
("complaints", "reported_institution_details", "`reported_institution_details` VARCHAR(512) NOT NULL DEFAULT ''"),
|
|
("complaints", "requested_protection", "`requested_protection` VARCHAR(128) NOT NULL DEFAULT ''"),
|
|
("complaints", "requested_protection_details", "`requested_protection_details` VARCHAR(512) NOT NULL DEFAULT ''"),
|
|
("complaints", "forwarding_authorization", "`forwarding_authorization` VARCHAR(128) NOT NULL DEFAULT ''"),
|
|
("complaints", "forwarding_personal_data_preference", "`forwarding_personal_data_preference` VARCHAR(256) NOT NULL DEFAULT ''"),
|
|
("complaints", "online_tracking_preference", "`online_tracking_preference` VARCHAR(256) NOT NULL DEFAULT ''"),
|
|
("complaints", "postal_notification_preference", "`postal_notification_preference` VARCHAR(256) NOT NULL DEFAULT ''"),
|
|
("complaints", "address_road_type", "`address_road_type` VARCHAR(32) NOT NULL DEFAULT ''"),
|
|
("complaints", "address_extra", "`address_extra` VARCHAR(256) NOT NULL DEFAULT ''"),
|
|
("complaints", "form_fields_json", "`form_fields_json` LONGTEXT NULL"),
|
|
("complaints", "raw_report_text", "`raw_report_text` LONGTEXT NULL"),
|
|
("complaint_attachments", "content_sha256", "`content_sha256` CHAR(64) NOT NULL DEFAULT ''"),
|
|
];
|
|
|
|
private static readonly (string Table, string IndexName, string Definition)[] SchemaIndexesToEnsure =
|
|
[
|
|
("complaint_attachments", "ix_attachments_sha256", "INDEX `ix_attachments_sha256` (`content_sha256`)"),
|
|
];
|
|
|
|
private static readonly (string Table, string Definition)[] SchemaEncryptedColumnsToEnsure =
|
|
[
|
|
("complaints", "`gestiona_file_url` TEXT NOT NULL"),
|
|
("complaints", "`gestiona_file_code` TEXT NOT NULL"),
|
|
("complaints", "`tag` TEXT NOT NULL"),
|
|
("complaints", "`status_name` TEXT NOT NULL"),
|
|
("complaints", "`complaint_type` TEXT NOT NULL"),
|
|
("complaints", "`reporter_kind` TEXT NOT NULL"),
|
|
("complaints", "`reporter_first_name` TEXT NOT NULL"),
|
|
("complaints", "`reporter_first_surname` TEXT NOT NULL"),
|
|
("complaints", "`reporter_second_surname` TEXT NOT NULL"),
|
|
("complaints", "`reporter_last_name` TEXT NOT NULL"),
|
|
("complaints", "`reporter_business_name` TEXT NOT NULL"),
|
|
("complaints", "`reporter_gender` TEXT NOT NULL"),
|
|
("complaints", "`reporter_document_id` TEXT NOT NULL"),
|
|
("complaints", "`reporter_document_type` TEXT NOT NULL"),
|
|
("complaints", "`reporter_origin_country` TEXT NOT NULL"),
|
|
("complaints", "`subject` TEXT NOT NULL"),
|
|
("complaints", "`accused_party` TEXT NOT NULL"),
|
|
("complaints", "`accused_party_details` TEXT NOT NULL"),
|
|
("complaints", "`complaint_description` LONGTEXT NULL"),
|
|
("complaints", "`reported_to_institution` TEXT NOT NULL"),
|
|
("complaints", "`reported_institution_details` TEXT NOT NULL"),
|
|
("complaints", "`requested_protection` TEXT NOT NULL"),
|
|
("complaints", "`requested_protection_details` TEXT NOT NULL"),
|
|
("complaints", "`information_mode` TEXT NOT NULL"),
|
|
("complaints", "`facts_location` TEXT NOT NULL"),
|
|
("complaints", "`forwarding_authorization` TEXT NOT NULL"),
|
|
("complaints", "`forwarding_personal_data_preference` TEXT NOT NULL"),
|
|
("complaints", "`notification_preference` TEXT NOT NULL"),
|
|
("complaints", "`electronic_notification` TEXT NOT NULL"),
|
|
("complaints", "`online_tracking_preference` TEXT NOT NULL"),
|
|
("complaints", "`postal_notification_preference` TEXT NOT NULL"),
|
|
("complaints", "`email` TEXT NOT NULL"),
|
|
("complaints", "`sms_notification` TEXT NOT NULL"),
|
|
("complaints", "`comments` LONGTEXT NULL"),
|
|
("complaints", "`phone` TEXT NOT NULL"),
|
|
("complaints", "`address_line` TEXT NOT NULL"),
|
|
("complaints", "`address_road_type` TEXT NOT NULL"),
|
|
("complaints", "`address_number` TEXT NOT NULL"),
|
|
("complaints", "`address_floor` TEXT NOT NULL"),
|
|
("complaints", "`address_door` TEXT NOT NULL"),
|
|
("complaints", "`address_block` TEXT NOT NULL"),
|
|
("complaints", "`address_stair` TEXT NOT NULL"),
|
|
("complaints", "`address_extra` TEXT NOT NULL"),
|
|
("complaints", "`municipality` TEXT NOT NULL"),
|
|
("complaints", "`province` TEXT NOT NULL"),
|
|
("complaints", "`postal_code` TEXT NOT NULL"),
|
|
("complaints", "`country_code` TEXT NOT NULL"),
|
|
("complaints", "`form_fields_json` LONGTEXT NULL"),
|
|
("complaints", "`raw_report_text` LONGTEXT NULL"),
|
|
("complaints", "`display_name` TEXT NOT NULL"),
|
|
("complaints", "`workflow_status` TEXT NOT NULL"),
|
|
("complaints", "`selected_document_name` TEXT NULL"),
|
|
("complaint_attachments", "`description` TEXT NULL"),
|
|
("complaint_attachments", "`notes` TEXT NOT NULL"),
|
|
];
|
|
|
|
private readonly ComplaintStorageOptions _options;
|
|
private readonly IHostEnvironment _environment;
|
|
private readonly ILogger<MySqlDenunciaStore> _logger;
|
|
private static readonly SemaphoreSlim SchemaGate = new(1, 1);
|
|
private static volatile bool SchemaEnsured;
|
|
private readonly MySqlConnectionStringProvider _connectionStringProvider;
|
|
|
|
public MySqlDenunciaStore(
|
|
IOptions<ComplaintStorageOptions> options,
|
|
IHostEnvironment environment,
|
|
ILogger<MySqlDenunciaStore> logger,
|
|
MySqlConnectionStringProvider connectionStringProvider)
|
|
{
|
|
_options = options.Value;
|
|
_environment = environment;
|
|
_logger = logger;
|
|
_connectionStringProvider = connectionStringProvider;
|
|
}
|
|
|
|
public Task EnsureSchemaAsync(CancellationToken cancellationToken = default)
|
|
{
|
|
return EnsureSchemaReadyAsync(cancellationToken);
|
|
}
|
|
|
|
public async Task<List<DenunciasGestiona>> GetAllDenunciasAsync(CancellationToken cancellationToken = default)
|
|
{
|
|
await EnsureSchemaReadyAsync(cancellationToken);
|
|
|
|
const string sql = """
|
|
SELECT
|
|
external_registry_id,
|
|
external_report_id,
|
|
report_date_utc,
|
|
gestiona_file_url,
|
|
gestiona_file_code,
|
|
gestiona_person_id,
|
|
tag,
|
|
status_name,
|
|
complaint_type,
|
|
reporter_kind,
|
|
is_legal_entity,
|
|
reporter_first_name,
|
|
reporter_first_surname,
|
|
reporter_second_surname,
|
|
reporter_last_name,
|
|
reporter_business_name,
|
|
reporter_gender,
|
|
reporter_document_id,
|
|
reporter_document_type,
|
|
reporter_origin_country,
|
|
subject,
|
|
accused_party,
|
|
accused_party_details,
|
|
complaint_description,
|
|
reported_to_institution,
|
|
reported_institution_details,
|
|
requested_protection,
|
|
requested_protection_details,
|
|
information_mode,
|
|
facts_location,
|
|
facts_date_utc,
|
|
forwarding_authorization,
|
|
forwarding_personal_data_preference,
|
|
notification_preference,
|
|
electronic_notification,
|
|
online_tracking_preference,
|
|
postal_notification_preference,
|
|
email,
|
|
sms_notification,
|
|
accepted_terms,
|
|
comments,
|
|
phone,
|
|
address_line,
|
|
address_road_type,
|
|
address_number,
|
|
address_floor,
|
|
address_door,
|
|
address_block,
|
|
address_stair,
|
|
address_extra,
|
|
municipality,
|
|
province,
|
|
postal_code,
|
|
country_code,
|
|
form_fields_json,
|
|
raw_report_text,
|
|
is_confidential,
|
|
is_update,
|
|
gestiona_procedure_id,
|
|
gestiona_group_id,
|
|
display_name,
|
|
workflow_status,
|
|
selected_document_name,
|
|
gestiona_uploaded_at_utc,
|
|
is_in_gestiona,
|
|
is_rejected
|
|
FROM complaints
|
|
ORDER BY COALESCE(gestiona_uploaded_at_utc, report_date_utc) DESC, external_report_id DESC;
|
|
""";
|
|
|
|
await using var connection = await OpenConnectionAsync(cancellationToken);
|
|
await using var command = new MySqlCommand(sql, connection);
|
|
await using var reader = await command.ExecuteReaderAsync(cancellationToken);
|
|
|
|
var result = new List<DenunciasGestiona>();
|
|
while (await reader.ReadAsync(cancellationToken))
|
|
{
|
|
result.Add(MapComplaint(reader));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public async Task<List<FicherosDenuncias>> GetAllFicherosAsync(CancellationToken cancellationToken = default)
|
|
{
|
|
await EnsureSchemaReadyAsync(cancellationToken);
|
|
|
|
const string sql = """
|
|
SELECT
|
|
a.id,
|
|
a.attachment_type_id,
|
|
a.description,
|
|
a.attachment_date_utc,
|
|
a.notes,
|
|
c.external_report_id,
|
|
a.original_file_name,
|
|
a.content,
|
|
a.content_sha256,
|
|
a.uploaded_to_gestiona,
|
|
a.uploaded_at_utc
|
|
FROM complaint_attachments a
|
|
INNER JOIN complaints c ON c.id = a.complaint_id
|
|
ORDER BY c.external_report_id DESC, a.original_file_name ASC;
|
|
""";
|
|
|
|
await using var connection = await OpenConnectionAsync(cancellationToken);
|
|
await using var command = new MySqlCommand(sql, connection);
|
|
await using var reader = await command.ExecuteReaderAsync(cancellationToken);
|
|
|
|
var result = new List<FicherosDenuncias>();
|
|
while (await reader.ReadAsync(cancellationToken))
|
|
{
|
|
result.Add(MapAttachment(reader));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public async Task<List<FicherosDenuncias>> GetFicherosByDenunciaAsync(
|
|
int denunciaId,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
await EnsureSchemaReadyAsync(cancellationToken);
|
|
|
|
const string sql = """
|
|
SELECT
|
|
a.id,
|
|
a.attachment_type_id,
|
|
a.description,
|
|
a.attachment_date_utc,
|
|
a.notes,
|
|
c.external_report_id,
|
|
a.original_file_name,
|
|
a.content,
|
|
a.content_sha256,
|
|
a.uploaded_to_gestiona,
|
|
a.uploaded_at_utc
|
|
FROM complaint_attachments a
|
|
INNER JOIN complaints c ON c.id = a.complaint_id
|
|
WHERE c.external_report_id = @denunciaId
|
|
ORDER BY a.original_file_name ASC;
|
|
""";
|
|
|
|
await using var connection = await OpenConnectionAsync(cancellationToken);
|
|
await using var command = new MySqlCommand(sql, connection);
|
|
command.Parameters.AddWithValue("@denunciaId", denunciaId);
|
|
|
|
await using var reader = await command.ExecuteReaderAsync(cancellationToken);
|
|
var result = new List<FicherosDenuncias>();
|
|
while (await reader.ReadAsync(cancellationToken))
|
|
{
|
|
result.Add(MapAttachment(reader));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public async Task<DenunciasGestiona?> GetDenunciaByIdAsync(
|
|
int denunciaId,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
await EnsureSchemaReadyAsync(cancellationToken);
|
|
|
|
const string sql = """
|
|
SELECT
|
|
external_registry_id,
|
|
external_report_id,
|
|
report_date_utc,
|
|
gestiona_file_url,
|
|
gestiona_file_code,
|
|
gestiona_person_id,
|
|
tag,
|
|
status_name,
|
|
complaint_type,
|
|
reporter_kind,
|
|
is_legal_entity,
|
|
reporter_first_name,
|
|
reporter_first_surname,
|
|
reporter_second_surname,
|
|
reporter_last_name,
|
|
reporter_business_name,
|
|
reporter_gender,
|
|
reporter_document_id,
|
|
reporter_document_type,
|
|
reporter_origin_country,
|
|
subject,
|
|
accused_party,
|
|
accused_party_details,
|
|
complaint_description,
|
|
reported_to_institution,
|
|
reported_institution_details,
|
|
requested_protection,
|
|
requested_protection_details,
|
|
information_mode,
|
|
facts_location,
|
|
facts_date_utc,
|
|
forwarding_authorization,
|
|
forwarding_personal_data_preference,
|
|
notification_preference,
|
|
electronic_notification,
|
|
online_tracking_preference,
|
|
postal_notification_preference,
|
|
email,
|
|
sms_notification,
|
|
accepted_terms,
|
|
comments,
|
|
phone,
|
|
address_line,
|
|
address_road_type,
|
|
address_number,
|
|
address_floor,
|
|
address_door,
|
|
address_block,
|
|
address_stair,
|
|
address_extra,
|
|
municipality,
|
|
province,
|
|
postal_code,
|
|
country_code,
|
|
form_fields_json,
|
|
raw_report_text,
|
|
is_confidential,
|
|
is_update,
|
|
gestiona_procedure_id,
|
|
gestiona_group_id,
|
|
display_name,
|
|
workflow_status,
|
|
selected_document_name,
|
|
gestiona_uploaded_at_utc,
|
|
is_in_gestiona,
|
|
is_rejected
|
|
FROM complaints
|
|
WHERE external_report_id = @denunciaId
|
|
LIMIT 1;
|
|
""";
|
|
|
|
await using var connection = await OpenConnectionAsync(cancellationToken);
|
|
await using var command = new MySqlCommand(sql, connection);
|
|
command.Parameters.AddWithValue("@denunciaId", denunciaId);
|
|
|
|
await using var reader = await command.ExecuteReaderAsync(cancellationToken);
|
|
return await reader.ReadAsync(cancellationToken)
|
|
? MapComplaint(reader)
|
|
: null;
|
|
}
|
|
|
|
public async Task UpsertDenunciaAsync(DenunciasGestiona denuncia, CancellationToken cancellationToken = default)
|
|
{
|
|
await EnsureSchemaReadyAsync(cancellationToken);
|
|
|
|
const string sql = """
|
|
INSERT INTO complaints (
|
|
external_registry_id,
|
|
external_report_id,
|
|
report_date_utc,
|
|
gestiona_file_url,
|
|
gestiona_file_code,
|
|
gestiona_person_id,
|
|
tag,
|
|
status_name,
|
|
complaint_type,
|
|
reporter_kind,
|
|
is_legal_entity,
|
|
reporter_first_name,
|
|
reporter_first_surname,
|
|
reporter_second_surname,
|
|
reporter_last_name,
|
|
reporter_business_name,
|
|
reporter_gender,
|
|
reporter_document_id,
|
|
reporter_document_type,
|
|
reporter_origin_country,
|
|
subject,
|
|
accused_party,
|
|
accused_party_details,
|
|
complaint_description,
|
|
reported_to_institution,
|
|
reported_institution_details,
|
|
requested_protection,
|
|
requested_protection_details,
|
|
information_mode,
|
|
facts_location,
|
|
facts_date_utc,
|
|
forwarding_authorization,
|
|
forwarding_personal_data_preference,
|
|
notification_preference,
|
|
electronic_notification,
|
|
online_tracking_preference,
|
|
postal_notification_preference,
|
|
email,
|
|
sms_notification,
|
|
accepted_terms,
|
|
comments,
|
|
phone,
|
|
address_line,
|
|
address_road_type,
|
|
address_number,
|
|
address_floor,
|
|
address_door,
|
|
address_block,
|
|
address_stair,
|
|
address_extra,
|
|
municipality,
|
|
province,
|
|
postal_code,
|
|
country_code,
|
|
form_fields_json,
|
|
raw_report_text,
|
|
is_confidential,
|
|
is_update,
|
|
gestiona_procedure_id,
|
|
gestiona_group_id,
|
|
display_name,
|
|
workflow_status,
|
|
selected_document_name,
|
|
gestiona_uploaded_at_utc,
|
|
is_in_gestiona,
|
|
is_rejected
|
|
) VALUES (
|
|
@externalRegistryId,
|
|
@externalReportId,
|
|
@reportDateUtc,
|
|
@gestionaFileUrl,
|
|
@gestionaFileCode,
|
|
@gestionaPersonId,
|
|
@tag,
|
|
@statusName,
|
|
@complaintType,
|
|
@reporterKind,
|
|
@isLegalEntity,
|
|
@reporterFirstName,
|
|
@reporterFirstSurname,
|
|
@reporterSecondSurname,
|
|
@reporterLastName,
|
|
@reporterBusinessName,
|
|
@reporterGender,
|
|
@reporterDocumentId,
|
|
@reporterDocumentType,
|
|
@reporterOriginCountry,
|
|
@subject,
|
|
@accusedParty,
|
|
@accusedPartyDetails,
|
|
@complaintDescription,
|
|
@reportedToInstitution,
|
|
@reportedInstitutionDetails,
|
|
@requestedProtection,
|
|
@requestedProtectionDetails,
|
|
@informationMode,
|
|
@factsLocation,
|
|
@factsDateUtc,
|
|
@forwardingAuthorization,
|
|
@forwardingPersonalDataPreference,
|
|
@notificationPreference,
|
|
@electronicNotification,
|
|
@onlineTrackingPreference,
|
|
@postalNotificationPreference,
|
|
@email,
|
|
@smsNotification,
|
|
@acceptedTerms,
|
|
@comments,
|
|
@phone,
|
|
@addressLine,
|
|
@addressRoadType,
|
|
@addressNumber,
|
|
@addressFloor,
|
|
@addressDoor,
|
|
@addressBlock,
|
|
@addressStair,
|
|
@addressExtra,
|
|
@municipality,
|
|
@province,
|
|
@postalCode,
|
|
@countryCode,
|
|
@formFieldsJson,
|
|
@rawReportText,
|
|
@isConfidential,
|
|
@isUpdate,
|
|
@gestionaProcedureId,
|
|
@gestionaGroupId,
|
|
@displayName,
|
|
@workflowStatus,
|
|
@selectedDocumentName,
|
|
@gestionaUploadedAtUtc,
|
|
@isInGestiona,
|
|
@isRejected
|
|
)
|
|
ON DUPLICATE KEY UPDATE
|
|
external_registry_id = VALUES(external_registry_id),
|
|
report_date_utc = VALUES(report_date_utc),
|
|
gestiona_file_url = VALUES(gestiona_file_url),
|
|
gestiona_file_code = VALUES(gestiona_file_code),
|
|
gestiona_person_id = VALUES(gestiona_person_id),
|
|
tag = VALUES(tag),
|
|
status_name = VALUES(status_name),
|
|
complaint_type = VALUES(complaint_type),
|
|
reporter_kind = VALUES(reporter_kind),
|
|
is_legal_entity = VALUES(is_legal_entity),
|
|
reporter_first_name = VALUES(reporter_first_name),
|
|
reporter_first_surname = VALUES(reporter_first_surname),
|
|
reporter_second_surname = VALUES(reporter_second_surname),
|
|
reporter_last_name = VALUES(reporter_last_name),
|
|
reporter_business_name = VALUES(reporter_business_name),
|
|
reporter_gender = VALUES(reporter_gender),
|
|
reporter_document_id = VALUES(reporter_document_id),
|
|
reporter_document_type = VALUES(reporter_document_type),
|
|
reporter_origin_country = VALUES(reporter_origin_country),
|
|
subject = VALUES(subject),
|
|
accused_party = VALUES(accused_party),
|
|
accused_party_details = VALUES(accused_party_details),
|
|
complaint_description = VALUES(complaint_description),
|
|
reported_to_institution = VALUES(reported_to_institution),
|
|
reported_institution_details = VALUES(reported_institution_details),
|
|
requested_protection = VALUES(requested_protection),
|
|
requested_protection_details = VALUES(requested_protection_details),
|
|
information_mode = VALUES(information_mode),
|
|
facts_location = VALUES(facts_location),
|
|
facts_date_utc = VALUES(facts_date_utc),
|
|
forwarding_authorization = VALUES(forwarding_authorization),
|
|
forwarding_personal_data_preference = VALUES(forwarding_personal_data_preference),
|
|
notification_preference = VALUES(notification_preference),
|
|
electronic_notification = VALUES(electronic_notification),
|
|
online_tracking_preference = VALUES(online_tracking_preference),
|
|
postal_notification_preference = VALUES(postal_notification_preference),
|
|
email = VALUES(email),
|
|
sms_notification = VALUES(sms_notification),
|
|
accepted_terms = VALUES(accepted_terms),
|
|
comments = VALUES(comments),
|
|
phone = VALUES(phone),
|
|
address_line = VALUES(address_line),
|
|
address_road_type = VALUES(address_road_type),
|
|
address_number = VALUES(address_number),
|
|
address_floor = VALUES(address_floor),
|
|
address_door = VALUES(address_door),
|
|
address_block = VALUES(address_block),
|
|
address_stair = VALUES(address_stair),
|
|
address_extra = VALUES(address_extra),
|
|
municipality = VALUES(municipality),
|
|
province = VALUES(province),
|
|
postal_code = VALUES(postal_code),
|
|
country_code = VALUES(country_code),
|
|
form_fields_json = VALUES(form_fields_json),
|
|
raw_report_text = VALUES(raw_report_text),
|
|
is_confidential = VALUES(is_confidential),
|
|
is_update = VALUES(is_update),
|
|
gestiona_procedure_id = VALUES(gestiona_procedure_id),
|
|
gestiona_group_id = VALUES(gestiona_group_id),
|
|
display_name = VALUES(display_name),
|
|
workflow_status = VALUES(workflow_status),
|
|
selected_document_name = VALUES(selected_document_name),
|
|
gestiona_uploaded_at_utc = VALUES(gestiona_uploaded_at_utc),
|
|
is_in_gestiona = VALUES(is_in_gestiona),
|
|
is_rejected = VALUES(is_rejected),
|
|
updated_at_utc = UTC_TIMESTAMP(6);
|
|
""";
|
|
|
|
await using var connection = await OpenConnectionAsync(cancellationToken);
|
|
await using var command = new MySqlCommand(sql, connection);
|
|
|
|
command.Parameters.AddWithValue("@externalRegistryId", denuncia.Id_RegistroDenuncia);
|
|
command.Parameters.AddWithValue("@externalReportId", denuncia.Id_Denuncia);
|
|
command.Parameters.AddWithValue("@reportDateUtc", ToDbDate(denuncia.Fecha));
|
|
command.Parameters.AddWithValue("@gestionaFileUrl", denuncia.Expediente_Gestiona ?? string.Empty);
|
|
command.Parameters.AddWithValue("@gestionaFileCode", denuncia.CodigoExpedienteGestiona ?? string.Empty);
|
|
command.Parameters.AddWithValue("@gestionaPersonId", denuncia.Id_Persona_Gestiona);
|
|
command.Parameters.AddWithValue("@tag", denuncia.Etiqueta ?? string.Empty);
|
|
command.Parameters.AddWithValue("@statusName", denuncia.Estado ?? string.Empty);
|
|
command.Parameters.AddWithValue("@complaintType", denuncia.Tipo_Denuncia ?? string.Empty);
|
|
command.Parameters.AddWithValue("@reporterKind", denuncia.TipoDenunciante ?? string.Empty);
|
|
command.Parameters.AddWithValue("@isLegalEntity", denuncia.EsPersonaJuridica);
|
|
command.Parameters.AddWithValue("@reporterFirstName", denuncia.Nombre ?? string.Empty);
|
|
command.Parameters.AddWithValue("@reporterFirstSurname", denuncia.PrimerApellido ?? string.Empty);
|
|
command.Parameters.AddWithValue("@reporterSecondSurname", denuncia.SegundoApellido ?? string.Empty);
|
|
command.Parameters.AddWithValue("@reporterLastName", denuncia.Apellidos ?? string.Empty);
|
|
command.Parameters.AddWithValue("@reporterBusinessName", denuncia.RazonSocial ?? string.Empty);
|
|
command.Parameters.AddWithValue("@reporterGender", denuncia.Sexo ?? string.Empty);
|
|
command.Parameters.AddWithValue("@reporterDocumentId", denuncia.Dni ?? string.Empty);
|
|
command.Parameters.AddWithValue("@reporterDocumentType", denuncia.TipoDocumentoIdentificativo ?? string.Empty);
|
|
command.Parameters.AddWithValue("@reporterOriginCountry", denuncia.PaisOrigen ?? string.Empty);
|
|
command.Parameters.AddWithValue("@subject", denuncia.Asunto ?? string.Empty);
|
|
command.Parameters.AddWithValue("@accusedParty", denuncia.A_Quien_Denuncia ?? string.Empty);
|
|
command.Parameters.AddWithValue("@accusedPartyDetails", denuncia.DenunciadoDetalle ?? string.Empty);
|
|
command.Parameters.AddWithValue("@complaintDescription", ToDbStringOrNull(denuncia.Descripcion_Denuncia));
|
|
command.Parameters.AddWithValue("@reportedToInstitution", denuncia.Denunciado_Ante_Inst ?? string.Empty);
|
|
command.Parameters.AddWithValue("@reportedInstitutionDetails", denuncia.OrganismoDenunciado ?? string.Empty);
|
|
command.Parameters.AddWithValue("@requestedProtection", denuncia.SolicitaProteccion ?? string.Empty);
|
|
command.Parameters.AddWithValue("@requestedProtectionDetails", denuncia.MedidasProteccionSolicitadas ?? string.Empty);
|
|
command.Parameters.AddWithValue("@informationMode", denuncia.Modalidad_Informacion ?? string.Empty);
|
|
command.Parameters.AddWithValue("@factsLocation", denuncia.Lugar_Hechos ?? string.Empty);
|
|
command.Parameters.AddWithValue("@factsDateUtc", ToDbDate(denuncia.Fecha_Hechos));
|
|
command.Parameters.AddWithValue("@forwardingAuthorization", denuncia.AutorizaRemision ?? string.Empty);
|
|
command.Parameters.AddWithValue("@forwardingPersonalDataPreference", denuncia.PreferenciaRemision ?? string.Empty);
|
|
command.Parameters.AddWithValue("@notificationPreference", denuncia.Notificacion_Preferencia ?? string.Empty);
|
|
command.Parameters.AddWithValue("@electronicNotification", denuncia.Notificacion_Electronica ?? string.Empty);
|
|
command.Parameters.AddWithValue("@onlineTrackingPreference", denuncia.SeguimientoOnline ?? string.Empty);
|
|
command.Parameters.AddWithValue("@postalNotificationPreference", denuncia.NotificacionPostal ?? string.Empty);
|
|
command.Parameters.AddWithValue("@email", denuncia.Correo_Electronico ?? string.Empty);
|
|
command.Parameters.AddWithValue("@smsNotification", denuncia.Notificacion_Sms ?? string.Empty);
|
|
command.Parameters.AddWithValue("@acceptedTerms", denuncia.Condiciones);
|
|
command.Parameters.AddWithValue("@comments", ToDbStringOrNull(denuncia.Comments));
|
|
command.Parameters.AddWithValue("@phone", denuncia.Telefono ?? string.Empty);
|
|
command.Parameters.AddWithValue("@addressLine", denuncia.Direccion ?? string.Empty);
|
|
command.Parameters.AddWithValue("@addressRoadType", denuncia.DireccionTipoVia ?? string.Empty);
|
|
command.Parameters.AddWithValue("@addressNumber", denuncia.DireccionNumero ?? string.Empty);
|
|
command.Parameters.AddWithValue("@addressFloor", denuncia.DireccionPiso ?? string.Empty);
|
|
command.Parameters.AddWithValue("@addressDoor", denuncia.DireccionPuerta ?? string.Empty);
|
|
command.Parameters.AddWithValue("@addressBlock", denuncia.DireccionBloque ?? string.Empty);
|
|
command.Parameters.AddWithValue("@addressStair", denuncia.DireccionEscalera ?? string.Empty);
|
|
command.Parameters.AddWithValue("@addressExtra", denuncia.DireccionExtra ?? string.Empty);
|
|
command.Parameters.AddWithValue("@municipality", denuncia.Municipio ?? string.Empty);
|
|
command.Parameters.AddWithValue("@province", denuncia.Provincia ?? string.Empty);
|
|
command.Parameters.AddWithValue("@postalCode", denuncia.CodigoPostal ?? string.Empty);
|
|
command.Parameters.AddWithValue("@countryCode", denuncia.Pais ?? string.Empty);
|
|
command.Parameters.AddWithValue("@formFieldsJson", ToDbStringOrNull(denuncia.CamposFormularioJson));
|
|
command.Parameters.AddWithValue("@rawReportText", ToDbStringOrNull(denuncia.TextoOriginalReport));
|
|
command.Parameters.AddWithValue("@isConfidential", denuncia.Confidencial);
|
|
command.Parameters.AddWithValue("@isUpdate", denuncia.EsActualizacion);
|
|
command.Parameters.AddWithValue("@gestionaProcedureId", ToDbGuid(denuncia.ProcedureId));
|
|
command.Parameters.AddWithValue("@gestionaGroupId", ToDbGuid(denuncia.GroupId));
|
|
command.Parameters.AddWithValue("@displayName", denuncia.NombreDenuncia ?? string.Empty);
|
|
command.Parameters.AddWithValue("@workflowStatus", denuncia.EstadoDenuncia ?? string.Empty);
|
|
command.Parameters.AddWithValue("@selectedDocumentName", ToDbStringOrNull(denuncia.ArchivoElegido));
|
|
command.Parameters.AddWithValue("@gestionaUploadedAtUtc", ToDbDate(denuncia.FechaSubidaAGestiona));
|
|
command.Parameters.AddWithValue("@isInGestiona", denuncia.EnGestiona);
|
|
command.Parameters.AddWithValue("@isRejected", denuncia.EnRechazada);
|
|
|
|
await command.ExecuteNonQueryAsync(cancellationToken);
|
|
}
|
|
|
|
public async Task UpsertFicherosAsync(
|
|
IEnumerable<FicherosDenuncias> ficheros,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
await EnsureSchemaReadyAsync(cancellationToken);
|
|
|
|
var attachments = ficheros.ToList();
|
|
if (attachments.Count == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
const string sql = """
|
|
INSERT INTO complaint_attachments (
|
|
complaint_id,
|
|
attachment_type_id,
|
|
description,
|
|
attachment_date_utc,
|
|
notes,
|
|
original_file_name,
|
|
content,
|
|
content_mime_type,
|
|
content_sha256,
|
|
uploaded_to_gestiona,
|
|
uploaded_at_utc
|
|
) VALUES (
|
|
(
|
|
SELECT c.id
|
|
FROM complaints c
|
|
WHERE c.external_report_id = @externalReportId
|
|
LIMIT 1
|
|
),
|
|
@attachmentTypeId,
|
|
@description,
|
|
@attachmentDateUtc,
|
|
@notes,
|
|
@originalFileName,
|
|
@content,
|
|
@contentMimeType,
|
|
@contentSha256,
|
|
@uploadedToGestiona,
|
|
@uploadedAtUtc
|
|
)
|
|
ON DUPLICATE KEY UPDATE
|
|
attachment_type_id = @attachmentTypeId,
|
|
description = @description,
|
|
attachment_date_utc = @attachmentDateUtc,
|
|
notes = @notes,
|
|
content = @content,
|
|
content_mime_type = @contentMimeType,
|
|
content_sha256 = @contentSha256,
|
|
uploaded_to_gestiona = CASE
|
|
WHEN LOWER(@originalFileName) = 'report.txt' OR LOWER(@originalFileName) = 'report.pdf' THEN @uploadedToGestiona
|
|
WHEN complaint_attachments.content_sha256 = @contentSha256 THEN complaint_attachments.uploaded_to_gestiona
|
|
ELSE @uploadedToGestiona
|
|
END,
|
|
uploaded_at_utc = CASE
|
|
WHEN LOWER(@originalFileName) = 'report.txt' OR LOWER(@originalFileName) = 'report.pdf' THEN @uploadedAtUtc
|
|
WHEN complaint_attachments.content_sha256 = @contentSha256 THEN complaint_attachments.uploaded_at_utc
|
|
ELSE @uploadedAtUtc
|
|
END,
|
|
updated_at_utc = CURRENT_TIMESTAMP(6);
|
|
""";
|
|
|
|
await using var connection = await OpenConnectionAsync(cancellationToken);
|
|
await using var transaction = await connection.BeginTransactionAsync(cancellationToken);
|
|
|
|
try
|
|
{
|
|
foreach (var fichero in attachments)
|
|
{
|
|
await using var command = new MySqlCommand(sql, connection, (MySqlTransaction)transaction);
|
|
var content = fichero.Fichero ?? [];
|
|
var sha256 = string.IsNullOrWhiteSpace(fichero.ContentSha256)
|
|
? ComputeSha256Hex(content)
|
|
: fichero.ContentSha256.Trim().ToLowerInvariant();
|
|
|
|
command.Parameters.AddWithValue("@attachmentTypeId", fichero.Id_Tipo);
|
|
command.Parameters.AddWithValue("@description", ToDbStringOrNull(fichero.Descripcion));
|
|
command.Parameters.AddWithValue("@attachmentDateUtc", ToDbDate(fichero.Fecha));
|
|
command.Parameters.AddWithValue("@notes", fichero.Observaciones ?? string.Empty);
|
|
command.Parameters.AddWithValue("@originalFileName", fichero.NombreFichero ?? string.Empty);
|
|
command.Parameters.AddWithValue("@content", content);
|
|
command.Parameters.AddWithValue("@contentMimeType", DetectMimeType(fichero.NombreFichero));
|
|
command.Parameters.AddWithValue("@contentSha256", sha256);
|
|
command.Parameters.AddWithValue("@uploadedToGestiona", fichero.Subido);
|
|
command.Parameters.AddWithValue("@uploadedAtUtc", ToDbDate(fichero.FechaSubida));
|
|
command.Parameters.AddWithValue("@externalReportId", fichero.Id_Denuncia);
|
|
|
|
await command.ExecuteNonQueryAsync(cancellationToken);
|
|
}
|
|
|
|
await transaction.CommitAsync(cancellationToken);
|
|
}
|
|
catch
|
|
{
|
|
await transaction.RollbackAsync(cancellationToken);
|
|
throw;
|
|
}
|
|
}
|
|
|
|
public async Task MarkFicherosAsUploadedAsync(
|
|
int denunciaId,
|
|
IEnumerable<string> fileNames,
|
|
DateTime uploadedAtUtc,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
await EnsureSchemaReadyAsync(cancellationToken);
|
|
|
|
var names = fileNames
|
|
.Where(name => !string.IsNullOrWhiteSpace(name))
|
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
|
.ToList();
|
|
|
|
if (names.Count == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var parameterNames = new List<string>(names.Count);
|
|
await using var connection = await OpenConnectionAsync(cancellationToken);
|
|
await using var command = connection.CreateCommand();
|
|
|
|
for (var i = 0; i < names.Count; i++)
|
|
{
|
|
var parameterName = $"@name{i}";
|
|
parameterNames.Add(parameterName);
|
|
command.Parameters.AddWithValue(parameterName, names[i]);
|
|
}
|
|
|
|
command.Parameters.AddWithValue("@denunciaId", denunciaId);
|
|
command.Parameters.AddWithValue("@uploadedAtUtc", uploadedAtUtc);
|
|
command.CommandText = $"""
|
|
UPDATE complaint_attachments a
|
|
INNER JOIN complaints c ON c.id = a.complaint_id
|
|
SET
|
|
a.uploaded_to_gestiona = 1,
|
|
a.uploaded_at_utc = @uploadedAtUtc,
|
|
a.updated_at_utc = UTC_TIMESTAMP(6)
|
|
WHERE c.external_report_id = @denunciaId
|
|
AND a.original_file_name IN ({string.Join(", ", parameterNames)});
|
|
""";
|
|
|
|
await command.ExecuteNonQueryAsync(cancellationToken);
|
|
}
|
|
|
|
private async Task EnsureSchemaReadyAsync(CancellationToken cancellationToken)
|
|
{
|
|
if (SchemaEnsured)
|
|
{
|
|
return;
|
|
}
|
|
|
|
await SchemaGate.WaitAsync(cancellationToken);
|
|
try
|
|
{
|
|
if (SchemaEnsured)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (_options.AutoCreateSchema)
|
|
{
|
|
var sqlPath = ResolveSchemaPath();
|
|
if (!File.Exists(sqlPath))
|
|
{
|
|
throw new FileNotFoundException($"No se encuentra el script de esquema: {sqlPath}");
|
|
}
|
|
|
|
var sql = await File.ReadAllTextAsync(sqlPath, cancellationToken);
|
|
var commands = sql
|
|
.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
|
.Where(command => !string.IsNullOrWhiteSpace(command))
|
|
.ToList();
|
|
|
|
await using var connection = await OpenConnectionAsync(cancellationToken);
|
|
foreach (var commandText in commands)
|
|
{
|
|
await using var command = new MySqlCommand(commandText, connection);
|
|
await command.ExecuteNonQueryAsync(cancellationToken);
|
|
}
|
|
|
|
await EnsureCompatibleSchemaAsync(connection, cancellationToken);
|
|
|
|
_logger.LogInformation("Esquema de denuncias verificado/creado en MySQL.");
|
|
}
|
|
|
|
SchemaEnsured = true;
|
|
}
|
|
finally
|
|
{
|
|
SchemaGate.Release();
|
|
}
|
|
}
|
|
|
|
private async Task<MySqlConnection> OpenConnectionAsync(CancellationToken cancellationToken)
|
|
{
|
|
var connectionString = await _connectionStringProvider.GetConnectionStringAsync(cancellationToken);
|
|
var connection = new MySqlConnection(connectionString);
|
|
await connection.OpenAsync(cancellationToken);
|
|
|
|
await using var timeZoneCommand = new MySqlCommand("SET time_zone = '+00:00';", connection);
|
|
await timeZoneCommand.ExecuteNonQueryAsync(cancellationToken);
|
|
|
|
return connection;
|
|
}
|
|
|
|
private static async Task EnsureCompatibleSchemaAsync(
|
|
MySqlConnection connection,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
foreach (var (table, column, definition) in SchemaColumnsToEnsure)
|
|
{
|
|
if (!await ColumnExistsAsync(connection, table, column, cancellationToken))
|
|
{
|
|
await using var alterCommand = connection.CreateCommand();
|
|
alterCommand.CommandText = $"ALTER TABLE `{table}` ADD COLUMN {definition};";
|
|
await alterCommand.ExecuteNonQueryAsync(cancellationToken);
|
|
}
|
|
}
|
|
|
|
foreach (var (table, indexName, definition) in SchemaIndexesToEnsure)
|
|
{
|
|
if (!await IndexExistsAsync(connection, table, indexName, cancellationToken))
|
|
{
|
|
await using var alterCommand = connection.CreateCommand();
|
|
alterCommand.CommandText = $"ALTER TABLE `{table}` ADD {definition};";
|
|
await alterCommand.ExecuteNonQueryAsync(cancellationToken);
|
|
}
|
|
}
|
|
|
|
foreach (var (table, definition) in SchemaEncryptedColumnsToEnsure)
|
|
{
|
|
var column = ExtractColumnName(definition);
|
|
if (!await ColumnDataTypeIsCompatibleAsync(connection, table, column, definition, cancellationToken))
|
|
{
|
|
await using var alterCommand = connection.CreateCommand();
|
|
alterCommand.CommandText = $"ALTER TABLE `{table}` MODIFY COLUMN {definition};";
|
|
await alterCommand.ExecuteNonQueryAsync(cancellationToken);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static string ExtractColumnName(string definition)
|
|
{
|
|
var first = definition.IndexOf('`');
|
|
var second = first >= 0 ? definition.IndexOf('`', first + 1) : -1;
|
|
return first >= 0 && second > first
|
|
? definition[(first + 1)..second]
|
|
: definition.Split(' ', StringSplitOptions.RemoveEmptyEntries)[0].Trim('`');
|
|
}
|
|
|
|
private static async Task<bool> ColumnDataTypeIsCompatibleAsync(
|
|
MySqlConnection connection,
|
|
string table,
|
|
string column,
|
|
string definition,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
const string sql = """
|
|
SELECT DATA_TYPE
|
|
FROM information_schema.COLUMNS
|
|
WHERE TABLE_SCHEMA = DATABASE()
|
|
AND TABLE_NAME = @table
|
|
AND COLUMN_NAME = @column
|
|
LIMIT 1;
|
|
""";
|
|
|
|
await using var command = connection.CreateCommand();
|
|
command.CommandText = sql;
|
|
command.Parameters.AddWithValue("@table", table);
|
|
command.Parameters.AddWithValue("@column", column);
|
|
|
|
var current = (await command.ExecuteScalarAsync(cancellationToken))?.ToString();
|
|
if (string.IsNullOrWhiteSpace(current))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var expected = definition.ToUpperInvariant();
|
|
if (expected.Contains("LONGTEXT", StringComparison.Ordinal))
|
|
{
|
|
return string.Equals(current, "longtext", StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
if (expected.Contains("TEXT", StringComparison.Ordinal))
|
|
{
|
|
return current.Equals("text", StringComparison.OrdinalIgnoreCase) ||
|
|
current.Equals("mediumtext", StringComparison.OrdinalIgnoreCase) ||
|
|
current.Equals("longtext", StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private static async Task<bool> ColumnExistsAsync(
|
|
MySqlConnection connection,
|
|
string table,
|
|
string column,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
const string sql = """
|
|
SELECT COUNT(*)
|
|
FROM information_schema.COLUMNS
|
|
WHERE TABLE_SCHEMA = DATABASE()
|
|
AND TABLE_NAME = @table
|
|
AND COLUMN_NAME = @column;
|
|
""";
|
|
|
|
await using var command = connection.CreateCommand();
|
|
command.CommandText = sql;
|
|
command.Parameters.AddWithValue("@table", table);
|
|
command.Parameters.AddWithValue("@column", column);
|
|
|
|
var result = await command.ExecuteScalarAsync(cancellationToken);
|
|
return Convert.ToInt32(result, CultureInfo.InvariantCulture) > 0;
|
|
}
|
|
|
|
private static async Task<bool> IndexExistsAsync(
|
|
MySqlConnection connection,
|
|
string table,
|
|
string indexName,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
const string sql = """
|
|
SELECT COUNT(*)
|
|
FROM information_schema.STATISTICS
|
|
WHERE TABLE_SCHEMA = DATABASE()
|
|
AND TABLE_NAME = @table
|
|
AND INDEX_NAME = @indexName;
|
|
""";
|
|
|
|
await using var command = connection.CreateCommand();
|
|
command.CommandText = sql;
|
|
command.Parameters.AddWithValue("@table", table);
|
|
command.Parameters.AddWithValue("@indexName", indexName);
|
|
|
|
var result = await command.ExecuteScalarAsync(cancellationToken);
|
|
return Convert.ToInt32(result, CultureInfo.InvariantCulture) > 0;
|
|
}
|
|
|
|
private string ResolveSchemaPath()
|
|
{
|
|
var contentRootPath = Path.Combine(_environment.ContentRootPath, "Scripts", "gestiondenuncias_schema.sql");
|
|
if (File.Exists(contentRootPath))
|
|
{
|
|
return contentRootPath;
|
|
}
|
|
|
|
return Path.Combine(AppContext.BaseDirectory, "Scripts", "gestiondenuncias_schema.sql");
|
|
}
|
|
|
|
private static DenunciasGestiona MapComplaint(IDataRecord record)
|
|
{
|
|
return new DenunciasGestiona
|
|
{
|
|
Id_RegistroDenuncia = GetInt32(record, "external_registry_id"),
|
|
Id_Denuncia = GetInt32(record, "external_report_id"),
|
|
Fecha = GetDateTime(record, "report_date_utc"),
|
|
Expediente_Gestiona = GetString(record, "gestiona_file_url"),
|
|
CodigoExpedienteGestiona = GetString(record, "gestiona_file_code"),
|
|
Id_Persona_Gestiona = GetInt32(record, "gestiona_person_id"),
|
|
Etiqueta = GetString(record, "tag"),
|
|
Estado = GetString(record, "status_name"),
|
|
Tipo_Denuncia = GetString(record, "complaint_type"),
|
|
TipoDenunciante = GetString(record, "reporter_kind"),
|
|
EsPersonaJuridica = GetBoolean(record, "is_legal_entity"),
|
|
Nombre = GetString(record, "reporter_first_name"),
|
|
PrimerApellido = GetString(record, "reporter_first_surname"),
|
|
SegundoApellido = GetString(record, "reporter_second_surname"),
|
|
Apellidos = GetString(record, "reporter_last_name"),
|
|
RazonSocial = GetString(record, "reporter_business_name"),
|
|
Sexo = GetString(record, "reporter_gender"),
|
|
Dni = GetString(record, "reporter_document_id"),
|
|
TipoDocumentoIdentificativo = GetString(record, "reporter_document_type"),
|
|
PaisOrigen = GetString(record, "reporter_origin_country"),
|
|
Asunto = GetString(record, "subject"),
|
|
A_Quien_Denuncia = GetString(record, "accused_party"),
|
|
DenunciadoDetalle = GetString(record, "accused_party_details"),
|
|
Descripcion_Denuncia = GetString(record, "complaint_description"),
|
|
Denunciado_Ante_Inst = GetString(record, "reported_to_institution"),
|
|
OrganismoDenunciado = GetString(record, "reported_institution_details"),
|
|
SolicitaProteccion = GetString(record, "requested_protection"),
|
|
MedidasProteccionSolicitadas = GetString(record, "requested_protection_details"),
|
|
Modalidad_Informacion = GetString(record, "information_mode"),
|
|
Lugar_Hechos = GetString(record, "facts_location"),
|
|
Fecha_Hechos = GetDateTime(record, "facts_date_utc"),
|
|
AutorizaRemision = GetString(record, "forwarding_authorization"),
|
|
PreferenciaRemision = GetString(record, "forwarding_personal_data_preference"),
|
|
Notificacion_Preferencia = GetString(record, "notification_preference"),
|
|
Notificacion_Electronica = GetString(record, "electronic_notification"),
|
|
SeguimientoOnline = GetString(record, "online_tracking_preference"),
|
|
NotificacionPostal = GetString(record, "postal_notification_preference"),
|
|
Correo_Electronico = GetString(record, "email"),
|
|
Notificacion_Sms = GetString(record, "sms_notification"),
|
|
Condiciones = GetBoolean(record, "accepted_terms"),
|
|
Comments = GetString(record, "comments"),
|
|
Telefono = GetString(record, "phone"),
|
|
Direccion = GetString(record, "address_line"),
|
|
DireccionTipoVia = GetString(record, "address_road_type"),
|
|
DireccionNumero = GetString(record, "address_number"),
|
|
DireccionPiso = GetString(record, "address_floor"),
|
|
DireccionPuerta = GetString(record, "address_door"),
|
|
DireccionBloque = GetString(record, "address_block"),
|
|
DireccionEscalera = GetString(record, "address_stair"),
|
|
DireccionExtra = GetString(record, "address_extra"),
|
|
Municipio = GetString(record, "municipality"),
|
|
Provincia = GetString(record, "province"),
|
|
CodigoPostal = GetString(record, "postal_code"),
|
|
Pais = GetString(record, "country_code"),
|
|
CamposFormularioJson = GetString(record, "form_fields_json"),
|
|
TextoOriginalReport = GetString(record, "raw_report_text"),
|
|
Confidencial = GetBoolean(record, "is_confidential"),
|
|
EsActualizacion = GetBoolean(record, "is_update"),
|
|
ProcedureId = GetGuid(record, "gestiona_procedure_id"),
|
|
GroupId = GetGuid(record, "gestiona_group_id"),
|
|
NombreDenuncia = GetString(record, "display_name"),
|
|
EstadoDenuncia = GetString(record, "workflow_status"),
|
|
ArchivoElegido = GetString(record, "selected_document_name"),
|
|
FechaSubidaAGestiona = GetDateTime(record, "gestiona_uploaded_at_utc"),
|
|
EnGestiona = GetBoolean(record, "is_in_gestiona"),
|
|
EnRechazada = GetBoolean(record, "is_rejected"),
|
|
};
|
|
}
|
|
|
|
private static FicherosDenuncias MapAttachment(IDataRecord record)
|
|
{
|
|
return new FicherosDenuncias
|
|
{
|
|
Id_Fichero = Convert.ToInt32(record["id"]),
|
|
Id_Tipo = GetInt32(record, "attachment_type_id"),
|
|
Descripcion = GetNullableString(record, "description"),
|
|
Fecha = GetDateTime(record, "attachment_date_utc"),
|
|
Observaciones = GetString(record, "notes"),
|
|
Id_Denuncia = GetInt32(record, "external_report_id"),
|
|
NombreFichero = GetString(record, "original_file_name"),
|
|
Fichero = GetBytes(record, "content"),
|
|
ContentSha256 = GetString(record, "content_sha256"),
|
|
Subido = GetBoolean(record, "uploaded_to_gestiona"),
|
|
FechaSubida = GetNullableDateTime(record, "uploaded_at_utc"),
|
|
};
|
|
}
|
|
|
|
private static object ToDbDate(DateTime value)
|
|
{
|
|
return value == DateTime.MinValue ? DBNull.Value : value;
|
|
}
|
|
|
|
private static object ToDbDate(DateTime? value)
|
|
{
|
|
return value is null || value == DateTime.MinValue ? DBNull.Value : value.Value;
|
|
}
|
|
|
|
private static object ToDbGuid(Guid value)
|
|
{
|
|
return value == Guid.Empty ? DBNull.Value : value.ToString();
|
|
}
|
|
|
|
private static object ToDbStringOrNull(string? value)
|
|
{
|
|
return string.IsNullOrWhiteSpace(value) ? DBNull.Value : value;
|
|
}
|
|
|
|
private static string GetString(IDataRecord record, string columnName)
|
|
{
|
|
var ordinal = record.GetOrdinal(columnName);
|
|
if (record.IsDBNull(ordinal))
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
return ConvertRecordValueToString(record.GetValue(ordinal)) ?? string.Empty;
|
|
}
|
|
|
|
private static string? GetNullableString(IDataRecord record, string columnName)
|
|
{
|
|
var ordinal = record.GetOrdinal(columnName);
|
|
return record.IsDBNull(ordinal) ? null : ConvertRecordValueToString(record.GetValue(ordinal));
|
|
}
|
|
|
|
private static int GetInt32(IDataRecord record, string columnName)
|
|
{
|
|
var ordinal = record.GetOrdinal(columnName);
|
|
return record.IsDBNull(ordinal) ? 0 : record.GetInt32(ordinal);
|
|
}
|
|
|
|
private static bool GetBoolean(IDataRecord record, string columnName)
|
|
{
|
|
var ordinal = record.GetOrdinal(columnName);
|
|
return !record.IsDBNull(ordinal) && record.GetBoolean(ordinal);
|
|
}
|
|
|
|
private static DateTime GetDateTime(IDataRecord record, string columnName)
|
|
{
|
|
var ordinal = record.GetOrdinal(columnName);
|
|
return record.IsDBNull(ordinal) ? DateTime.MinValue : record.GetDateTime(ordinal);
|
|
}
|
|
|
|
private static DateTime? GetNullableDateTime(IDataRecord record, string columnName)
|
|
{
|
|
var ordinal = record.GetOrdinal(columnName);
|
|
return record.IsDBNull(ordinal) ? null : record.GetDateTime(ordinal);
|
|
}
|
|
|
|
private static Guid GetGuid(IDataRecord record, string columnName)
|
|
{
|
|
var ordinal = record.GetOrdinal(columnName);
|
|
if (record.IsDBNull(ordinal))
|
|
{
|
|
return Guid.Empty;
|
|
}
|
|
|
|
var value = record.GetValue(ordinal);
|
|
return value switch
|
|
{
|
|
Guid guid => guid,
|
|
byte[] bytes when bytes.Length == 16 => new Guid(bytes),
|
|
_ when Guid.TryParse(ConvertRecordValueToString(value), out var result) => result,
|
|
_ => Guid.Empty
|
|
};
|
|
}
|
|
|
|
private static byte[] GetBytes(IDataRecord record, string columnName)
|
|
{
|
|
var ordinal = record.GetOrdinal(columnName);
|
|
if (record.IsDBNull(ordinal))
|
|
{
|
|
return [];
|
|
}
|
|
|
|
return (byte[])record.GetValue(ordinal);
|
|
}
|
|
|
|
private static string DetectMimeType(string? fileName)
|
|
{
|
|
var extension = Path.GetExtension(fileName ?? string.Empty).ToLowerInvariant();
|
|
return extension switch
|
|
{
|
|
".pdf" => "application/pdf",
|
|
".txt" => "text/plain",
|
|
".jpg" or ".jpeg" => "image/jpeg",
|
|
".png" => "image/png",
|
|
".gif" => "image/gif",
|
|
".doc" => "application/msword",
|
|
".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
".xls" => "application/vnd.ms-excel",
|
|
".xlsx" => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
_ => "application/octet-stream",
|
|
};
|
|
}
|
|
|
|
private static string ComputeSha256Hex(byte[] content)
|
|
{
|
|
var hash = SHA256.HashData(content);
|
|
return Convert.ToHexString(hash).ToLowerInvariant();
|
|
}
|
|
|
|
private static string? ConvertRecordValueToString(object? value)
|
|
{
|
|
return value switch
|
|
{
|
|
null or DBNull => null,
|
|
string text => text,
|
|
Guid guid => guid.ToString(),
|
|
byte[] bytes when bytes.Length == 16 => new Guid(bytes).ToString(),
|
|
IFormattable formattable => formattable.ToString(null, CultureInfo.InvariantCulture),
|
|
_ => value.ToString()
|
|
};
|
|
}
|
|
}
|