904 lines
32 KiB
C#
904 lines
32 KiB
C#
using System.Globalization;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using ApiDenuncias.Services;
|
|
using GestionaDenuncias.Shared.Models;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
|
|
namespace ApiDenuncias.Controllers;
|
|
|
|
[ApiController]
|
|
[Authorize]
|
|
[Route("api/denuncias")]
|
|
public sealed class DenunciasController : ControllerBase
|
|
{
|
|
private readonly IDenunciaStore _denunciaStore;
|
|
private readonly IFilteredDenunciaStore _filteredDenunciaStore;
|
|
private readonly UserComplaintAccessService _accessService;
|
|
private readonly IInboxTrackingService _trackingService;
|
|
private readonly ILogger<DenunciasController> _logger;
|
|
|
|
public DenunciasController(
|
|
IDenunciaStore denunciaStore,
|
|
IFilteredDenunciaStore filteredDenunciaStore,
|
|
UserComplaintAccessService accessService,
|
|
IInboxTrackingService trackingService,
|
|
ILogger<DenunciasController> logger)
|
|
{
|
|
_denunciaStore = denunciaStore;
|
|
_filteredDenunciaStore = filteredDenunciaStore;
|
|
_accessService = accessService;
|
|
_trackingService = trackingService;
|
|
_logger = logger;
|
|
}
|
|
|
|
[HttpPost("schema/ensure")]
|
|
public async Task<IActionResult> EnsureSchema(CancellationToken cancellationToken)
|
|
{
|
|
await _denunciaStore.EnsureSchemaAsync(cancellationToken);
|
|
return Ok(new { ok = true });
|
|
}
|
|
|
|
[HttpGet]
|
|
public async Task<ActionResult<List<DenunciasGestiona>>> GetAll(
|
|
[FromQuery] DenunciaListScope scope,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
await _denunciaStore.EnsureSchemaAsync(cancellationToken);
|
|
var access = await _accessService.GetComplaintAccessAsync(
|
|
GetUsername(),
|
|
null,
|
|
cancellationToken);
|
|
if (access.Count == 0)
|
|
{
|
|
return Ok(new List<DenunciasGestiona>());
|
|
}
|
|
|
|
var complaints = await _filteredDenunciaStore.GetDenunciasByIdsAsync(
|
|
access.Keys.ToArray(),
|
|
scope,
|
|
cancellationToken);
|
|
ApplyAccessMetadata(complaints, access);
|
|
return Ok(complaints);
|
|
}
|
|
|
|
[HttpGet("{denunciaId:int}")]
|
|
public async Task<ActionResult<DenunciasGestiona?>> GetById(int denunciaId, CancellationToken cancellationToken)
|
|
{
|
|
if (!await CanAccessAsync(denunciaId, cancellationToken))
|
|
{
|
|
return NotFound();
|
|
}
|
|
|
|
var complaint = await _denunciaStore.GetDenunciaByIdAsync(denunciaId, cancellationToken);
|
|
if (complaint is null)
|
|
{
|
|
return Ok(null);
|
|
}
|
|
|
|
var access = await _accessService.GetComplaintAccessAsync(
|
|
GetUsername(),
|
|
[denunciaId],
|
|
cancellationToken);
|
|
ApplyAccessMetadata([complaint], access);
|
|
return Ok(complaint);
|
|
}
|
|
|
|
[AllowAnonymous]
|
|
[HttpGet("{denunciaId:int}/gestiona-fields")]
|
|
public async Task<ActionResult<GestionaExternalFieldsResponse>> GetGestionaFields(
|
|
int denunciaId,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
if (denunciaId <= 0)
|
|
{
|
|
return BadRequest(new ApiError("Debes indicar un numero de denuncia valido."));
|
|
}
|
|
|
|
var denuncia = await _denunciaStore.GetDenunciaByIdAsync(denunciaId, cancellationToken);
|
|
if (denuncia is null)
|
|
{
|
|
return NotFound(new ApiError("No se ha encontrado la denuncia solicitada."));
|
|
}
|
|
|
|
return BuildGestionaFieldsResponse(denuncia);
|
|
}
|
|
|
|
[AllowAnonymous]
|
|
[HttpGet("{numeroExpediente:int}/{anioExpediente:int}/gestiona-fields")]
|
|
public async Task<ActionResult<GestionaExternalFieldsResponse>> GetGestionaFieldsByExpediente(
|
|
int numeroExpediente,
|
|
int anioExpediente,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
if (numeroExpediente <= 0 || anioExpediente <= 0)
|
|
{
|
|
return BadRequest(new ApiError("Debes indicar un numero de expediente de Gestiona valido."));
|
|
}
|
|
|
|
var expedienteGestiona = $"{numeroExpediente.ToString(CultureInfo.InvariantCulture)}/{anioExpediente.ToString(CultureInfo.InvariantCulture)}";
|
|
var denuncia = await _filteredDenunciaStore.GetDenunciaByGestionaFileCodeAsync(
|
|
expedienteGestiona,
|
|
cancellationToken);
|
|
if (denuncia is null)
|
|
{
|
|
return NotFound(new ApiError("No se ha encontrado una denuncia asociada al expediente de Gestiona solicitado."));
|
|
}
|
|
|
|
return BuildGestionaFieldsResponse(denuncia);
|
|
}
|
|
|
|
private ActionResult<GestionaExternalFieldsResponse> BuildGestionaFieldsResponse(DenunciasGestiona denuncia)
|
|
{
|
|
var response = ToGestionaComplaintFields(denuncia);
|
|
var missingFields = GetMissingGestionaFields(response);
|
|
if (missingFields.Count > 0)
|
|
{
|
|
_logger.LogInformation(
|
|
"Campos Gestiona denuncia {DenunciaId}: campos vacios={MissingFields}; rawReportLength={RawReportLength}; formFieldsCount={FormFieldsCount}.",
|
|
denuncia.Id_Denuncia,
|
|
string.Join(", ", missingFields),
|
|
denuncia.TextoOriginalReport?.Length ?? 0,
|
|
denuncia.GetCamposFormulario().Count);
|
|
}
|
|
|
|
return Ok(ToExternalGestionaFields(response));
|
|
}
|
|
|
|
[HttpPost]
|
|
public async Task<IActionResult> Upsert(DenunciasGestiona denuncia, CancellationToken cancellationToken)
|
|
{
|
|
if (!await CanAccessAsync(denuncia.Id_Denuncia, cancellationToken))
|
|
{
|
|
return Forbid();
|
|
}
|
|
|
|
await _denunciaStore.UpsertDenunciaAsync(denuncia, cancellationToken);
|
|
await TryRegisterGestionaHistoryFromComplaintAsync(denuncia, cancellationToken);
|
|
return Ok(new { ok = true });
|
|
}
|
|
|
|
[HttpGet("ficheros")]
|
|
public async Task<ActionResult<List<FicherosDenuncias>>> GetAllFicheros(CancellationToken cancellationToken)
|
|
{
|
|
var allowedIds = await GetAllowedIdsAsync(cancellationToken);
|
|
if (allowedIds.Count == 0)
|
|
{
|
|
return Ok(new List<FicherosDenuncias>());
|
|
}
|
|
|
|
return Ok(await _filteredDenunciaStore.GetFicherosByDenunciaIdsAsync(allowedIds, cancellationToken));
|
|
}
|
|
|
|
[HttpGet("{denunciaId:int}/ficheros")]
|
|
public async Task<ActionResult<List<FicherosDenuncias>>> GetFicherosByDenuncia(int denunciaId, CancellationToken cancellationToken)
|
|
{
|
|
if (!await CanAccessAsync(denunciaId, cancellationToken))
|
|
{
|
|
return NotFound();
|
|
}
|
|
|
|
return Ok(await _denunciaStore.GetFicherosByDenunciaAsync(denunciaId, cancellationToken));
|
|
}
|
|
|
|
[HttpGet("gestiona-history")]
|
|
public async Task<ActionResult<List<GestionaUploadHistoryEntry>>> GetGestionaHistory(CancellationToken cancellationToken)
|
|
{
|
|
await _denunciaStore.EnsureSchemaAsync(cancellationToken);
|
|
return Ok(await _denunciaStore.GetGestionaUploadHistoryAsync(cancellationToken));
|
|
}
|
|
|
|
[HttpPost("gestiona-history")]
|
|
public async Task<IActionResult> AddGestionaHistory(
|
|
GestionaUploadHistoryCreateRequest request,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
if (!await CanAccessAsync(request.DenunciaId, cancellationToken))
|
|
{
|
|
return Forbid();
|
|
}
|
|
|
|
await _denunciaStore.AddGestionaUploadHistoryAsync(request, GetUsername(), cancellationToken);
|
|
await _trackingService.MarkReportHandledInGestionaAsync(
|
|
GetUsername(),
|
|
request.DenunciaId,
|
|
request.UploadedAtUtc,
|
|
cancellationToken);
|
|
return Ok(new { ok = true });
|
|
}
|
|
|
|
[HttpGet("{denunciaId:int}/ficheros/content")]
|
|
public async Task<IActionResult> GetFicheroContent(
|
|
int denunciaId,
|
|
[FromQuery] string fileName,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(fileName))
|
|
{
|
|
return BadRequest(new ApiError("Nombre de fichero obligatorio."));
|
|
}
|
|
|
|
if (!await CanAccessAsync(denunciaId, cancellationToken))
|
|
{
|
|
return NotFound();
|
|
}
|
|
|
|
var ficheros = await _denunciaStore.GetFicherosByDenunciaAsync(denunciaId, cancellationToken);
|
|
var fichero = ficheros.FirstOrDefault(file =>
|
|
string.Equals(file.NombreFichero, fileName, StringComparison.Ordinal));
|
|
|
|
if (fichero?.Fichero is not { Length: > 0 } bytes)
|
|
{
|
|
return NotFound();
|
|
}
|
|
|
|
return File(
|
|
bytes,
|
|
GetAttachmentContentType(fichero.NombreFichero),
|
|
enableRangeProcessing: true);
|
|
}
|
|
|
|
[HttpPost("ficheros")]
|
|
public async Task<IActionResult> UpsertFicheros(UpsertFicherosRequest request, CancellationToken cancellationToken)
|
|
{
|
|
var ficheros = request.Ficheros ?? [];
|
|
foreach (var denunciaId in ficheros.Select(f => f.Id_Denuncia).Distinct())
|
|
{
|
|
if (!await CanAccessAsync(denunciaId, cancellationToken))
|
|
{
|
|
return Forbid();
|
|
}
|
|
}
|
|
|
|
await _denunciaStore.UpsertFicherosAsync(ficheros, cancellationToken);
|
|
return Ok(new { ok = true });
|
|
}
|
|
|
|
[HttpPost("{denunciaId:int}/ficheros/mark-uploaded")]
|
|
public async Task<IActionResult> MarkFicherosAsUploaded(
|
|
int denunciaId,
|
|
MarkFicherosUploadedRequest request,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
if (!await CanAccessAsync(denunciaId, cancellationToken))
|
|
{
|
|
return Forbid();
|
|
}
|
|
|
|
await _denunciaStore.MarkFicherosAsUploadedAsync(
|
|
denunciaId,
|
|
request.FileNames,
|
|
request.UploadedAtUtc,
|
|
cancellationToken);
|
|
|
|
return Ok(new { ok = true });
|
|
}
|
|
|
|
private async Task<HashSet<int>> GetAllowedIdsAsync(CancellationToken cancellationToken)
|
|
{
|
|
await _denunciaStore.EnsureSchemaAsync(cancellationToken);
|
|
return await _accessService.GetAllowedComplaintIdsAsync(GetUsername(), cancellationToken);
|
|
}
|
|
|
|
private async Task<bool> CanAccessAsync(int denunciaId, CancellationToken cancellationToken)
|
|
{
|
|
if (denunciaId <= 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
await _denunciaStore.EnsureSchemaAsync(cancellationToken);
|
|
return await _accessService.CanAccessComplaintAsync(GetUsername(), denunciaId, cancellationToken);
|
|
}
|
|
|
|
private string GetUsername()
|
|
=> User.Identity?.Name ?? throw new InvalidOperationException("No hay usuario autenticado.");
|
|
|
|
private static void ApplyAccessMetadata(
|
|
IEnumerable<DenunciasGestiona> complaints,
|
|
IReadOnlyDictionary<int, ComplaintAccessInfo> access)
|
|
{
|
|
foreach (var complaint in complaints)
|
|
{
|
|
if (!access.TryGetValue(complaint.Id_Denuncia, out var item))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
complaint.OwnerUsername = item.OwnerUsername;
|
|
complaint.OwnedByCurrentUser = item.OwnedByCurrentUser;
|
|
complaint.RequiresOwnerConfirmation = item.RequiresOwnerConfirmation;
|
|
complaint.OwnerWorkGroups = item.OwnerGroupCodes;
|
|
}
|
|
}
|
|
|
|
private static GestionaComplaintFieldsResponse ToGestionaComplaintFields(DenunciasGestiona denuncia)
|
|
{
|
|
var preferenciaNotificacion = ResolveNotificationPreference(denuncia);
|
|
var seguimiento = ResolveSeguimientoDenuncia(denuncia);
|
|
var sms = ResolveSmsNotification(denuncia);
|
|
|
|
return new GestionaComplaintFieldsResponse(
|
|
FechaDenuncia: ToNullableDate(denuncia.Fecha),
|
|
NumeroDenunciaCanal: denuncia.Id_Denuncia,
|
|
AQuienDenuncia: ResolveReportField(denuncia, denuncia.A_Quien_Denuncia, "a quien denuncia"),
|
|
ResumenDenuncia: FirstNonEmpty(
|
|
ResolveReportField(denuncia, string.Empty, "resumen de la denuncia", "resumen denuncia"),
|
|
ResolveReportField(denuncia, denuncia.Descripcion_Denuncia, "describa su denuncia", "descripcion de la denuncia")),
|
|
FechaHechos: ResolveFechaHechos(denuncia),
|
|
LugarHechos: ResolveLugarHechos(denuncia),
|
|
AmbitoCompetencias: ResolveAmbitoCompetencias(denuncia),
|
|
SolicitaProteccion: ResolveReportField(denuncia, denuncia.SolicitaProteccion, "solicita medidas concretas de proteccion", "solicita proteccion"),
|
|
SexoDenunciante: ResolveReportField(denuncia, denuncia.Sexo, "sexo"),
|
|
AutorizaRemisionDenuncia: ResolveReportField(denuncia, denuncia.AutorizaRemision, "autorizacion para remitir su denuncia", "autoriza remision de la denuncia"),
|
|
AutorizaNotificacionesViaSms: sms,
|
|
PreferenciaNotificacionSeguimientoDenuncia: JoinDistinct(preferenciaNotificacion, seguimiento));
|
|
}
|
|
|
|
private static GestionaExternalFieldsResponse ToExternalGestionaFields(GestionaComplaintFieldsResponse source)
|
|
{
|
|
return new GestionaExternalFieldsResponse(
|
|
new Dictionary<string, GestionaExternalFieldValue>(StringComparer.Ordinal)
|
|
{
|
|
["fechaDenuncia"] = StringField(source.FechaDenuncia?.ToString("O", CultureInfo.InvariantCulture) ?? string.Empty),
|
|
["numeroDenunciaCanal"] = StringField(source.NumeroDenunciaCanal.ToString(CultureInfo.InvariantCulture)),
|
|
["aQuienDenuncia"] = StringField(source.AQuienDenuncia),
|
|
["resumenDenuncia"] = StringField(source.ResumenDenuncia),
|
|
["fechaHechos"] = StringField(source.FechaHechos),
|
|
["lugarHechos"] = StringField(source.LugarHechos),
|
|
["ambitoCompetencias"] = StringField(source.AmbitoCompetencias),
|
|
["solicitaProteccion"] = StringField(source.SolicitaProteccion),
|
|
["sexoDenunciante"] = StringField(source.SexoDenunciante),
|
|
["autorizaRemisionDenuncia"] = StringField(source.AutorizaRemisionDenuncia),
|
|
["autorizaNotificacionesViaSms"] = StringField(source.AutorizaNotificacionesViaSms),
|
|
["preferenciaNotificacionSeguimientoDenuncia"] = StringField(source.PreferenciaNotificacionSeguimientoDenuncia)
|
|
});
|
|
}
|
|
|
|
private static GestionaExternalFieldValue StringField(string? value)
|
|
=> new("STRING", value?.Trim() ?? string.Empty);
|
|
|
|
private async Task TryRegisterGestionaHistoryFromComplaintAsync(
|
|
DenunciasGestiona denuncia,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
if (!denuncia.EnGestiona || denuncia.FechaSubidaAGestiona == DateTime.MinValue)
|
|
{
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
await _denunciaStore.AddGestionaUploadHistoryAsync(
|
|
new GestionaUploadHistoryCreateRequest(
|
|
denuncia.Id_Denuncia,
|
|
denuncia.Expediente_Gestiona ?? string.Empty,
|
|
denuncia.ExpedienteGestionaMostrable,
|
|
denuncia.UltimaSubidaGestionaTipoMostrable,
|
|
denuncia.UltimoGrupoAsignadoGestionaMostrable,
|
|
denuncia.FechaSubidaAGestiona,
|
|
denuncia.NombreDenuncia ?? string.Empty,
|
|
denuncia.ArchivoElegido ?? string.Empty),
|
|
GetUsername(),
|
|
cancellationToken);
|
|
await _trackingService.MarkReportHandledInGestionaAsync(
|
|
GetUsername(),
|
|
denuncia.Id_Denuncia,
|
|
denuncia.FechaSubidaAGestiona,
|
|
cancellationToken);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogWarning(
|
|
ex,
|
|
"No se ha podido registrar el historico de subida a Gestiona para la denuncia {DenunciaId}.",
|
|
denuncia.Id_Denuncia);
|
|
}
|
|
}
|
|
|
|
private static DateTime? ToNullableDate(DateTime value)
|
|
=> value == DateTime.MinValue ? null : value;
|
|
|
|
private static IReadOnlyList<string> GetMissingGestionaFields(GestionaComplaintFieldsResponse response)
|
|
{
|
|
var missing = new List<string>();
|
|
|
|
AddIfMissing(missing, response.AQuienDenuncia, nameof(response.AQuienDenuncia));
|
|
AddIfMissing(missing, response.ResumenDenuncia, nameof(response.ResumenDenuncia));
|
|
AddIfMissing(missing, response.FechaHechos, nameof(response.FechaHechos));
|
|
AddIfMissing(missing, response.LugarHechos, nameof(response.LugarHechos));
|
|
AddIfMissing(missing, response.AmbitoCompetencias, nameof(response.AmbitoCompetencias));
|
|
AddIfMissing(missing, response.SolicitaProteccion, nameof(response.SolicitaProteccion));
|
|
AddIfMissing(missing, response.SexoDenunciante, nameof(response.SexoDenunciante));
|
|
AddIfMissing(missing, response.AutorizaRemisionDenuncia, nameof(response.AutorizaRemisionDenuncia));
|
|
AddIfMissing(missing, response.AutorizaNotificacionesViaSms, nameof(response.AutorizaNotificacionesViaSms));
|
|
AddIfMissing(missing, response.PreferenciaNotificacionSeguimientoDenuncia, nameof(response.PreferenciaNotificacionSeguimientoDenuncia));
|
|
|
|
return missing;
|
|
}
|
|
|
|
private static void AddIfMissing(List<string> missing, string? value, string fieldName)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(value))
|
|
{
|
|
missing.Add(fieldName);
|
|
}
|
|
}
|
|
|
|
private static string ResolveFechaHechos(DenunciasGestiona denuncia)
|
|
{
|
|
var literalValue = ResolveReportField(
|
|
denuncia,
|
|
string.Empty,
|
|
"fecha de los hechos que denuncia",
|
|
"fecha de los hechos");
|
|
|
|
if (!string.IsNullOrWhiteSpace(literalValue))
|
|
{
|
|
return literalValue;
|
|
}
|
|
|
|
var textDate = ExtractDateAfterReportLabel(
|
|
denuncia.TextoOriginalReport,
|
|
normalizedLabel => normalizedLabel.Contains("fecha", StringComparison.Ordinal) &&
|
|
normalizedLabel.Contains("hechos", StringComparison.Ordinal));
|
|
if (!string.IsNullOrWhiteSpace(textDate))
|
|
{
|
|
return textDate;
|
|
}
|
|
|
|
return denuncia.Fecha_Hechos == DateTime.MinValue
|
|
? string.Empty
|
|
: denuncia.Fecha_Hechos.ToString("dd/MM/yyyy", CultureInfo.InvariantCulture);
|
|
}
|
|
|
|
private static string ResolveLugarHechos(DenunciasGestiona denuncia)
|
|
{
|
|
var directValue = ResolveReportField(
|
|
denuncia,
|
|
denuncia.Lugar_Hechos,
|
|
"lugar en el que ocurrieron los hechos que denuncia",
|
|
"lugar en la que ocurrieron los hechos que denuncia",
|
|
"lugar de los hechos");
|
|
|
|
if (!string.IsNullOrWhiteSpace(directValue))
|
|
{
|
|
return directValue;
|
|
}
|
|
|
|
return ExtractReportTextValue(
|
|
denuncia.TextoOriginalReport,
|
|
normalizedLabel => normalizedLabel.Contains("lugar", StringComparison.Ordinal) &&
|
|
normalizedLabel.Contains("hechos", StringComparison.Ordinal));
|
|
}
|
|
|
|
private static string ResolveSeguimientoDenuncia(DenunciasGestiona denuncia)
|
|
{
|
|
var directValue = ResolveReportField(
|
|
denuncia,
|
|
denuncia.SeguimientoOnline,
|
|
"seguimiento online",
|
|
"seguimiento de su denuncia");
|
|
|
|
if (!string.IsNullOrWhiteSpace(directValue))
|
|
{
|
|
return directValue;
|
|
}
|
|
|
|
return ReportContainsLabel(denuncia.TextoOriginalReport, "seguimiento online")
|
|
? "Seguimiento Online"
|
|
: string.Empty;
|
|
}
|
|
|
|
private static string ResolveNotificationPreference(DenunciasGestiona denuncia)
|
|
{
|
|
var directValue = ResolveReportField(
|
|
denuncia,
|
|
denuncia.Notificacion_Preferencia,
|
|
"preferencia de notificacion",
|
|
"seleccione su preferencia de notificacion y seguimiento de su denuncia",
|
|
"preferencia de notificacion y seguimiento de su denuncia",
|
|
"notificaciones");
|
|
if (!string.IsNullOrWhiteSpace(directValue))
|
|
{
|
|
return directValue;
|
|
}
|
|
|
|
directValue = ResolveReportFieldAllowingLabelValues(
|
|
denuncia,
|
|
string.Empty,
|
|
"preferencia de notificacion",
|
|
"seleccione su preferencia de notificacion y seguimiento de su denuncia",
|
|
"preferencia de notificacion y seguimiento de su denuncia");
|
|
if (!string.IsNullOrWhiteSpace(directValue))
|
|
{
|
|
return directValue;
|
|
}
|
|
|
|
var electronic = ResolveReportField(
|
|
denuncia,
|
|
denuncia.Notificacion_Electronica,
|
|
"notificaciones electronicas",
|
|
"notificacion electronica");
|
|
if (!string.IsNullOrWhiteSpace(electronic) ||
|
|
ReportContainsLabel(denuncia.TextoOriginalReport, "notificaciones electronicas"))
|
|
{
|
|
return "Notificaciones electronicas";
|
|
}
|
|
|
|
var postal = ResolveReportField(
|
|
denuncia,
|
|
denuncia.NotificacionPostal,
|
|
"autorizo recibir notificaciones via correo postal",
|
|
"notificaciones via correo postal",
|
|
"correo postal");
|
|
return string.IsNullOrWhiteSpace(postal) ? string.Empty : "Correo postal";
|
|
}
|
|
|
|
private static string ResolveSmsNotification(DenunciasGestiona denuncia)
|
|
{
|
|
return ResolveReportField(
|
|
denuncia,
|
|
denuncia.Notificacion_Sms,
|
|
"autorizo recibir notificaciones via sms",
|
|
"autorizacion notificaciones via sms",
|
|
"autorizacion para recibir notificaciones via sms",
|
|
"autoriza notificaciones via sms",
|
|
"autorizo recibir notificaciones sms",
|
|
"notificaciones via sms",
|
|
"sms");
|
|
}
|
|
|
|
private static string ResolveAmbitoCompetencias(DenunciasGestiona denuncia)
|
|
{
|
|
var directValue = ResolveReportField(
|
|
denuncia,
|
|
FirstNonEmpty(denuncia.Modalidad_Informacion, denuncia.Asunto),
|
|
"asunto",
|
|
"categoria",
|
|
"tipo de denuncia",
|
|
"ambito de competencias",
|
|
"ambito competencial",
|
|
"ambito",
|
|
"competencias",
|
|
"modalidad de informacion",
|
|
"modalidad informacion");
|
|
|
|
if (!string.IsNullOrWhiteSpace(directValue))
|
|
{
|
|
return directValue;
|
|
}
|
|
|
|
return FindReportFieldValue(denuncia, normalizedLabel =>
|
|
normalizedLabel.Contains("ambito", StringComparison.Ordinal) &&
|
|
normalizedLabel.Contains("compet", StringComparison.Ordinal));
|
|
}
|
|
|
|
private static string ResolveReportField(
|
|
DenunciasGestiona denuncia,
|
|
string? currentValue,
|
|
params string[] candidateLabels)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(currentValue))
|
|
{
|
|
return currentValue.Trim();
|
|
}
|
|
|
|
var labels = candidateLabels
|
|
.Select(NormalizeLabel)
|
|
.Where(label => !string.IsNullOrWhiteSpace(label))
|
|
.ToHashSet(StringComparer.Ordinal);
|
|
|
|
if (labels.Count == 0)
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
foreach (var field in denuncia.GetCamposFormulario())
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(field.Value) &&
|
|
labels.Contains(NormalizeLabel(field.Label)))
|
|
{
|
|
return field.Value.Trim();
|
|
}
|
|
}
|
|
|
|
return ExtractReportTextValue(denuncia.TextoOriginalReport, labels);
|
|
}
|
|
|
|
private static string ResolveReportFieldAllowingLabelValues(
|
|
DenunciasGestiona denuncia,
|
|
string? currentValue,
|
|
params string[] candidateLabels)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(currentValue))
|
|
{
|
|
return currentValue.Trim();
|
|
}
|
|
|
|
var labels = candidateLabels
|
|
.Select(NormalizeLabel)
|
|
.Where(label => !string.IsNullOrWhiteSpace(label))
|
|
.ToHashSet(StringComparer.Ordinal);
|
|
|
|
if (labels.Count == 0)
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
foreach (var field in denuncia.GetCamposFormulario())
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(field.Value) &&
|
|
labels.Contains(NormalizeLabel(field.Label)))
|
|
{
|
|
return field.Value.Trim();
|
|
}
|
|
}
|
|
|
|
return ExtractReportTextValue(denuncia.TextoOriginalReport, labels, stopAtLikelyLabels: false);
|
|
}
|
|
|
|
private static string FindReportFieldValue(
|
|
DenunciasGestiona denuncia,
|
|
Func<string, bool> labelPredicate)
|
|
{
|
|
foreach (var field in denuncia.GetCamposFormulario())
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(field.Value) &&
|
|
labelPredicate(NormalizeLabel(field.Label)))
|
|
{
|
|
return field.Value.Trim();
|
|
}
|
|
}
|
|
|
|
return string.Empty;
|
|
}
|
|
|
|
private static string ExtractDateAfterReportLabel(string? reportText, Func<string, bool> labelPredicate)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(reportText))
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
var lines = reportText
|
|
.Replace("\r\n", "\n", StringComparison.Ordinal)
|
|
.Replace('\r', '\n')
|
|
.Split('\n')
|
|
.Select(line => line.Trim())
|
|
.ToArray();
|
|
|
|
for (var index = 0; index < lines.Length; index++)
|
|
{
|
|
var normalized = NormalizeLabel(lines[index]);
|
|
if (!labelPredicate(normalized))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
for (var valueIndex = index + 1; valueIndex < lines.Length && valueIndex <= index + 12; valueIndex++)
|
|
{
|
|
var candidate = lines[valueIndex].Trim();
|
|
if (string.IsNullOrWhiteSpace(candidate) || IsReportStructuralLine(candidate))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var dateMatch = Regex.Match(
|
|
candidate,
|
|
@"\b\d{1,2}/\d{1,2}/\d{4}\b",
|
|
RegexOptions.CultureInvariant);
|
|
if (dateMatch.Success)
|
|
{
|
|
return dateMatch.Value;
|
|
}
|
|
|
|
if (IsLikelyReportLabel(candidate))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
var rawMatch = Regex.Match(
|
|
reportText,
|
|
@"fecha\s+de\s+los\s+hechos[\s\S]{0,600}?(\b\d{1,2}/\d{1,2}/\d{4}\b)",
|
|
RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
|
|
return rawMatch.Success ? rawMatch.Groups[1].Value : string.Empty;
|
|
}
|
|
|
|
private static string ExtractReportTextValue(string? reportText, IReadOnlySet<string> normalizedLabels)
|
|
=> ExtractReportTextValue(
|
|
reportText,
|
|
normalizedLabel => normalizedLabels.Contains(normalizedLabel));
|
|
|
|
private static string ExtractReportTextValue(
|
|
string? reportText,
|
|
IReadOnlySet<string> normalizedLabels,
|
|
bool stopAtLikelyLabels)
|
|
=> ExtractReportTextValue(
|
|
reportText,
|
|
normalizedLabel => normalizedLabels.Contains(normalizedLabel),
|
|
stopAtLikelyLabels);
|
|
|
|
private static string ExtractReportTextValue(string? reportText, Func<string, bool> labelPredicate)
|
|
=> ExtractReportTextValue(reportText, labelPredicate, stopAtLikelyLabels: true);
|
|
|
|
private static string ExtractReportTextValue(
|
|
string? reportText,
|
|
Func<string, bool> labelPredicate,
|
|
bool stopAtLikelyLabels)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(reportText))
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
var lines = reportText
|
|
.Replace("\r\n", "\n", StringComparison.Ordinal)
|
|
.Replace('\r', '\n')
|
|
.Split('\n')
|
|
.Select(line => line.Trim())
|
|
.ToArray();
|
|
|
|
for (var index = 0; index < lines.Length; index++)
|
|
{
|
|
if (!labelPredicate(NormalizeLabel(lines[index])))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
for (var valueIndex = index + 1; valueIndex < lines.Length; valueIndex++)
|
|
{
|
|
var candidate = lines[valueIndex].Trim();
|
|
if (string.IsNullOrWhiteSpace(candidate) || IsReportStructuralLine(candidate))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (stopAtLikelyLabels && IsLikelyReportLabel(candidate))
|
|
{
|
|
break;
|
|
}
|
|
|
|
return candidate;
|
|
}
|
|
}
|
|
|
|
return string.Empty;
|
|
}
|
|
|
|
private static bool ReportContainsLabel(string? reportText, string label)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(reportText))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var normalizedLabel = NormalizeLabel(label);
|
|
return reportText
|
|
.Replace("\r\n", "\n", StringComparison.Ordinal)
|
|
.Replace('\r', '\n')
|
|
.Split('\n')
|
|
.Any(line => string.Equals(NormalizeLabel(line.Trim()), normalizedLabel, StringComparison.Ordinal));
|
|
}
|
|
|
|
private static bool IsReportStructuralLine(string value)
|
|
{
|
|
if (Regex.IsMatch(value, @"^\d+/\d+$", RegexOptions.CultureInvariant))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return value.StartsWith("REPORT ", StringComparison.OrdinalIgnoreCase) ||
|
|
value.Equals("[CONFIDENTIAL]", StringComparison.OrdinalIgnoreCase) ||
|
|
value.Equals("{Messages}", StringComparison.OrdinalIgnoreCase) ||
|
|
value.StartsWith("Comments", StringComparison.OrdinalIgnoreCase) ||
|
|
value.StartsWith("De:", StringComparison.OrdinalIgnoreCase) ||
|
|
value.StartsWith("Fecha:", StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
private static bool IsLikelyReportLabel(string value)
|
|
{
|
|
var normalized = NormalizeLabel(value);
|
|
if (string.IsNullOrWhiteSpace(normalized))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return normalized is "descripcion"
|
|
or "datos del denunciante"
|
|
or "condiciones y reglas de uso"
|
|
or "tratamiento de datos personales"
|
|
or "preferencias de notificacion"
|
|
or "notificaciones electronicas" ||
|
|
normalized.StartsWith("indique ", StringComparison.Ordinal) ||
|
|
normalized.StartsWith("describa ", StringComparison.Ordinal) ||
|
|
normalized.StartsWith("autoriza ", StringComparison.Ordinal) ||
|
|
normalized.StartsWith("autorizacion ", StringComparison.Ordinal) ||
|
|
normalized.StartsWith("ha denunciado ", StringComparison.Ordinal) ||
|
|
normalized.StartsWith("solicita ", StringComparison.Ordinal) ||
|
|
normalized.StartsWith("por favor ", StringComparison.Ordinal) ||
|
|
normalized.Contains(" denuncia", StringComparison.Ordinal) ||
|
|
normalized.Contains(" hechos", StringComparison.Ordinal) ||
|
|
normalized.Contains(" notificacion", StringComparison.Ordinal);
|
|
}
|
|
|
|
private static string JoinDistinct(params string[] values)
|
|
{
|
|
var result = new List<string>();
|
|
var seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
|
foreach (var value in values)
|
|
{
|
|
var trimmed = value?.Trim();
|
|
if (!string.IsNullOrWhiteSpace(trimmed) && seen.Add(trimmed))
|
|
{
|
|
result.Add(trimmed);
|
|
}
|
|
}
|
|
|
|
return string.Join("; ", result);
|
|
}
|
|
|
|
private static string FirstNonEmpty(params string[] values)
|
|
{
|
|
foreach (var value in values)
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(value))
|
|
{
|
|
return value.Trim();
|
|
}
|
|
}
|
|
|
|
return string.Empty;
|
|
}
|
|
//pruabass
|
|
private static string NormalizeLabel(string? value)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(value))
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
var normalized = value.Normalize(NormalizationForm.FormD);
|
|
var builder = new StringBuilder(normalized.Length);
|
|
|
|
foreach (var ch in normalized)
|
|
{
|
|
if (CharUnicodeInfo.GetUnicodeCategory(ch) == UnicodeCategory.NonSpacingMark)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (ch is '\u00BA' or '\u00AA')
|
|
{
|
|
continue;
|
|
}
|
|
|
|
builder.Append(char.IsLetterOrDigit(ch) ? char.ToLowerInvariant(ch) : ' ');
|
|
}
|
|
|
|
return string.Join(
|
|
' ',
|
|
builder
|
|
.ToString()
|
|
.Normalize(NormalizationForm.FormC)
|
|
.Split(' ', StringSplitOptions.RemoveEmptyEntries));
|
|
}
|
|
|
|
private static string GetAttachmentContentType(string? fileName)
|
|
{
|
|
return Path.GetExtension(fileName ?? string.Empty).ToLowerInvariant() switch
|
|
{
|
|
".pdf" => "application/pdf",
|
|
".txt" => "text/plain",
|
|
".jpg" or ".jpeg" => "image/jpeg",
|
|
".png" => "image/png",
|
|
".gif" => "image/gif",
|
|
".zip" => "application/zip",
|
|
_ => "application/octet-stream"
|
|
};
|
|
}
|
|
}
|