denuncias
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using GestionaDenuncias.Shared.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -19,11 +20,16 @@ namespace ApiDenuncias.Services
|
||||
{
|
||||
private readonly HttpClient _http;
|
||||
private readonly GestionaOptions _opts;
|
||||
private readonly ILogger<GestionaService> _logger;
|
||||
|
||||
public GestionaService(HttpClient http, IOptions<GestionaOptions> optsAccessor)
|
||||
public GestionaService(
|
||||
HttpClient http,
|
||||
IOptions<GestionaOptions> optsAccessor,
|
||||
ILogger<GestionaService> logger)
|
||||
{
|
||||
_http = http;
|
||||
_opts = optsAccessor.Value;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
@@ -58,7 +64,7 @@ namespace ApiDenuncias.Services
|
||||
return null;
|
||||
}
|
||||
|
||||
// Reemplaza este helper si quieres controlar la versi<EFBFBD>n en Accept:
|
||||
// Reemplaza este helper si quieres controlar la versión en Accept:
|
||||
private void AddTokenAndAccept(HttpRequestMessage req, string mediaType, string? version = null)
|
||||
{
|
||||
req.Headers.TryAddWithoutValidation("X-Gestiona-Access-Token", _opts.AccessToken);
|
||||
@@ -83,6 +89,17 @@ namespace ApiDenuncias.Services
|
||||
req.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
}
|
||||
|
||||
private void LogDeprecatedHeaders(HttpResponseMessage response, string operation)
|
||||
{
|
||||
if (response.Headers.TryGetValues("X-Gestiona-Deprecated", out var deprecated))
|
||||
{
|
||||
_logger.LogWarning(
|
||||
"Gestiona devolvio X-Gestiona-Deprecated en {Operation}: {Deprecated}",
|
||||
operation,
|
||||
string.Join(" | ", deprecated));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// =========================================================
|
||||
@@ -113,65 +130,20 @@ namespace ApiDenuncias.Services
|
||||
using var doc = JsonDocument.Parse(body);
|
||||
var fileUrl = GetLinkHref(doc.RootElement, "file")
|
||||
?? throw new InvalidOperationException("CreateFileAsync: Gestiona no ha devuelto link 'file'.");
|
||||
var fileOpenUrl = GetLinkHref(doc.RootElement, "file-open");
|
||||
var fileOpenUrl = GetLinkHref(doc.RootElement, "file-open")
|
||||
?? throw new InvalidOperationException("CreateFileAsync: Gestiona no ha devuelto link 'file-open'.");
|
||||
|
||||
return new GestionaCreateFileResponse(fileUrl, fileOpenUrl);
|
||||
}
|
||||
|
||||
private async Task<string> ResolveExternalProcedureCreateFileUrlAsync(Guid procedureId)
|
||||
private Task<string> ResolveExternalProcedureCreateFileUrlAsync(Guid procedureId)
|
||||
{
|
||||
if (Guid.TryParse(_opts.ExternalProcedureId, out var configuredExternalProcedureId))
|
||||
{
|
||||
return $"/rest/catalog-2015/procedures/{procedureId}/external-procedures/{configuredExternalProcedureId}/create-file";
|
||||
}
|
||||
var externalProcedureId = Guid.TryParse(_opts.ExternalProcedureId, out var configuredExternalProcedureId)
|
||||
? configuredExternalProcedureId
|
||||
: procedureId;
|
||||
|
||||
using var req = new HttpRequestMessage(HttpMethod.Get, $"/rest/catalog-2015/procedures/{procedureId}/external-procedures");
|
||||
AddTokenAndAccept(req, "application/vnd.gestiona.external-procedures-page+json");
|
||||
|
||||
using var resp = await _http.SendAsync(req);
|
||||
if (resp.StatusCode == System.Net.HttpStatusCode.NoContent)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"El procedimiento {procedureId} no tiene tramites externos configurados en Gestiona.");
|
||||
}
|
||||
|
||||
var body = await resp.Content.ReadAsStringAsync();
|
||||
if (!resp.IsSuccessStatusCode)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"ResolveExternalProcedureCreateFileUrlAsync: {(int)resp.StatusCode} {resp.StatusCode}\n{body}");
|
||||
}
|
||||
|
||||
using var doc = JsonDocument.Parse(body);
|
||||
if (!doc.RootElement.TryGetProperty("content", out var content) || content.ValueKind != JsonValueKind.Array)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"El procedimiento {procedureId} no ha devuelto tramites externos validos en Gestiona.");
|
||||
}
|
||||
|
||||
var createFileCandidates = new List<(string? Id, string Href)>();
|
||||
foreach (var item in content.EnumerateArray())
|
||||
{
|
||||
var createFileHref = GetLinkHref(item, "create-file");
|
||||
if (!string.IsNullOrWhiteSpace(createFileHref))
|
||||
{
|
||||
var externalProcedureId = item.TryGetProperty("id", out var idProp) && idProp.ValueKind == JsonValueKind.String
|
||||
? idProp.GetString()
|
||||
: null;
|
||||
createFileCandidates.Add((externalProcedureId, createFileHref!));
|
||||
}
|
||||
}
|
||||
|
||||
if (createFileCandidates.Count == 0)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"El procedimiento {procedureId} no tiene ningun tramite externo con link create-file.");
|
||||
}
|
||||
|
||||
return createFileCandidates
|
||||
.FirstOrDefault(candidate => string.Equals(candidate.Id, procedureId.ToString(), StringComparison.OrdinalIgnoreCase))
|
||||
.Href
|
||||
?? createFileCandidates[0].Href;
|
||||
return Task.FromResult(
|
||||
$"/rest/catalog-2015/procedures/{procedureId}/external-procedures/{externalProcedureId}/create-file");
|
||||
}
|
||||
|
||||
public async Task OpenFileAsync(
|
||||
@@ -183,9 +155,13 @@ namespace ApiDenuncias.Services
|
||||
string freeTitle,
|
||||
string siaCode)
|
||||
{
|
||||
var url = string.IsNullOrWhiteSpace(fileOpenUrl)
|
||||
? $"{fileUrl.TrimEnd('/')}/open"
|
||||
: fileOpenUrl;
|
||||
if (string.IsNullOrWhiteSpace(fileOpenUrl))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"OpenFileAsync: falta el link 'file-open' devuelto por Gestiona. No se usa el fallback /open para evitar la ruta deprecated.");
|
||||
}
|
||||
|
||||
var url = fileOpenUrl;
|
||||
|
||||
var payload = new
|
||||
{
|
||||
@@ -228,7 +204,8 @@ namespace ApiDenuncias.Services
|
||||
{
|
||||
Content = content
|
||||
};
|
||||
AddTokenAndAccept(req, "application/json");
|
||||
req.Headers.TryAddWithoutValidation("Prefer", "return=minimal");
|
||||
AddTokenAndAccept(req, "application/vnd.gestiona.file-folder+json", "1");
|
||||
|
||||
using var resp = await _http.SendAsync(req);
|
||||
var body = await resp.Content.ReadAsStringAsync();
|
||||
@@ -248,7 +225,8 @@ namespace ApiDenuncias.Services
|
||||
{
|
||||
using var createReq = new HttpRequestMessage(HttpMethod.Post, "/rest/uploads");
|
||||
createReq.Headers.TryAddWithoutValidation("X-Gestiona-Access-Token", _opts.AccessToken);
|
||||
createReq.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
createReq.Headers.Accept.Add(
|
||||
MediaTypeWithQualityHeaderValue.Parse("application/vnd.gestiona.upload+json"));
|
||||
|
||||
using var createResp = await _http.SendAsync(createReq);
|
||||
var createBody = await createResp.Content.ReadAsStringAsync();
|
||||
@@ -256,7 +234,7 @@ namespace ApiDenuncias.Services
|
||||
throw new InvalidOperationException($"CreateUpload (POST): {(int)createResp.StatusCode} {createResp.StatusCode}\n{createBody}");
|
||||
|
||||
var uploadUri = createResp.Headers.Location?.ToString()
|
||||
?? throw new InvalidOperationException("No se devolvi<EFBFBD> Location en /rest/uploads");
|
||||
?? throw new InvalidOperationException("No se devolvió Location en /rest/uploads");
|
||||
|
||||
string md5Hex;
|
||||
using (var md5 = MD5.Create())
|
||||
@@ -269,8 +247,9 @@ namespace ApiDenuncias.Services
|
||||
putReq.Headers.TryAddWithoutValidation("X-Gestiona-Access-Token", _opts.AccessToken);
|
||||
putReq.Headers.TryAddWithoutValidation("X-Gestiona-Upload-MD5", md5Hex);
|
||||
putReq.Headers.TryAddWithoutValidation("Slug", fileName);
|
||||
putReq.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
|
||||
putReq.Headers.TryAddWithoutValidation("Prefer", "return=minimal");
|
||||
putReq.Headers.Accept.Add(
|
||||
MediaTypeWithQualityHeaderValue.Parse("application/vnd.gestiona.upload+json"));
|
||||
putReq.Content = new ByteArrayContent(contentBytes);
|
||||
putReq.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
|
||||
|
||||
@@ -279,11 +258,15 @@ namespace ApiDenuncias.Services
|
||||
if (!putResp.IsSuccessStatusCode)
|
||||
throw new InvalidOperationException($"CreateUpload (PUT): {(int)putResp.StatusCode} {putResp.StatusCode}\n{infoJson}");
|
||||
|
||||
using var infoDoc = JsonDocument.Parse(infoJson);
|
||||
var status = infoDoc.RootElement.GetProperty("status").GetString();
|
||||
if (status != "READY")
|
||||
throw new InvalidOperationException($"Upload no READY: {status}");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(infoJson))
|
||||
{
|
||||
using var infoDoc = JsonDocument.Parse(infoJson);
|
||||
var status = infoDoc.RootElement.TryGetProperty("status", out var statusProp)
|
||||
? statusProp.GetString()
|
||||
: "READY";
|
||||
if (!string.Equals(status, "READY", StringComparison.OrdinalIgnoreCase))
|
||||
throw new InvalidOperationException($"Upload no READY: {status}");
|
||||
}
|
||||
return uploadUri;
|
||||
}
|
||||
|
||||
@@ -309,8 +292,10 @@ namespace ApiDenuncias.Services
|
||||
using var metaReq = new HttpRequestMessage(HttpMethod.Post, $"{fileUrl}/documents-and-folders")
|
||||
{ Content = metaContent };
|
||||
metaReq.Headers.TryAddWithoutValidation("X-Gestiona-Access-Token", _opts.AccessToken);
|
||||
metaReq.Headers.TryAddWithoutValidation("Prefer", "return=minimal");
|
||||
metaReq.Headers.Accept.Clear();
|
||||
metaReq.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
metaReq.Headers.Accept.Add(
|
||||
MediaTypeWithQualityHeaderValue.Parse("application/vnd.gestiona.file-document+json; version=4"));
|
||||
|
||||
using var metaResp = await _http.SendAsync(metaReq);
|
||||
var body = await metaResp.Content.ReadAsStringAsync();
|
||||
@@ -386,7 +371,7 @@ namespace ApiDenuncias.Services
|
||||
if (thirdParty.IsLegalEntity)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(thirdParty.BusinessName))
|
||||
throw new ArgumentException("La raz<EFBFBD>n social es obligatoria para terceros jur<EFBFBD>dicos.", nameof(thirdParty));
|
||||
throw new ArgumentException("La razón social es obligatoria para terceros jurídicos.", nameof(thirdParty));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -485,7 +470,7 @@ namespace ApiDenuncias.Services
|
||||
{
|
||||
foreach (var item in content.EnumerateArray())
|
||||
{
|
||||
if (item.TryGetProperty("links", out var links))
|
||||
if (item.TryGetProperty("links", out var links))
|
||||
{
|
||||
var third = links.EnumerateArray().FirstOrDefault(l => l.GetProperty("rel").GetString() == "third");
|
||||
if (third.ValueKind != JsonValueKind.Undefined)
|
||||
@@ -561,12 +546,15 @@ namespace ApiDenuncias.Services
|
||||
};
|
||||
}
|
||||
|
||||
// --- CONSULTAS DE EXPEDIENTES (sin recorrer hist<EFBFBD>rico paginado) ---
|
||||
// --- CONSULTAS DE EXPEDIENTES (sin recorrer histórico paginado) ---
|
||||
|
||||
private async Task<string> GetFilesAsync(object? filter = null)
|
||||
{
|
||||
using var req = new HttpRequestMessage(HttpMethod.Get, "/rest/files");
|
||||
AddBasicHeaders(req);
|
||||
req.Headers.Accept.Clear();
|
||||
req.Headers.Accept.Add(
|
||||
MediaTypeWithQualityHeaderValue.Parse("application/vnd.gestiona.files-page+json"));
|
||||
|
||||
if (filter is not null)
|
||||
{
|
||||
@@ -575,6 +563,7 @@ namespace ApiDenuncias.Services
|
||||
}
|
||||
|
||||
using var resp = await _http.SendAsync(req);
|
||||
LogDeprecatedHeaders(resp, "GET /rest/files");
|
||||
if (resp.StatusCode == System.Net.HttpStatusCode.NoContent)
|
||||
{
|
||||
return "{\"content\":[]}";
|
||||
@@ -612,7 +601,7 @@ namespace ApiDenuncias.Services
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Devuelve el JSON crudo de /rest/files acumulando hasta maxPages p<EFBFBD>ginas.
|
||||
/// Devuelve el JSON crudo de /rest/files acumulando hasta maxPages páginas.
|
||||
/// </summary>
|
||||
public async Task<string> ListarExpedientesJsonAsyncBasico(int maxPages = 1)
|
||||
{
|
||||
@@ -683,9 +672,10 @@ namespace ApiDenuncias.Services
|
||||
}
|
||||
|
||||
using var req = new HttpRequestMessage(HttpMethod.Get, fileUrl);
|
||||
AddTokenAndAccept(req, "application/json");
|
||||
AddTokenAndAccept(req, "application/vnd.gestiona.file+json", "2");
|
||||
|
||||
using var resp = await _http.SendAsync(req);
|
||||
LogDeprecatedHeaders(resp, $"GET {fileUrl}");
|
||||
if (resp.StatusCode == System.Net.HttpStatusCode.NoContent ||
|
||||
resp.StatusCode == System.Net.HttpStatusCode.NotFound)
|
||||
{
|
||||
@@ -910,7 +900,7 @@ namespace ApiDenuncias.Services
|
||||
using var resp = await _http.SendAsync(req);
|
||||
var body = await resp.Content.ReadAsStringAsync();
|
||||
if (!resp.IsSuccessStatusCode)
|
||||
throw new InvalidOperationException($"Error actualizando direcci<EFBFBD>n del tercero: {(int)resp.StatusCode} {resp.ReasonPhrase}\n{body}");
|
||||
throw new InvalidOperationException($"Error actualizando dirección del tercero: {(int)resp.StatusCode} {resp.ReasonPhrase}\n{body}");
|
||||
}
|
||||
|
||||
private async Task<bool> ThirdHasAddressesAsync(string thirdSelfHref)
|
||||
@@ -1160,7 +1150,7 @@ namespace ApiDenuncias.Services
|
||||
return value switch
|
||||
{
|
||||
"" => "ESP",
|
||||
"es" or "esp" or "espana" or "espa<EFBFBD>a" or "spain" => "ESP",
|
||||
"es" or "esp" or "espana" or "españa" or "spain" => "ESP",
|
||||
"prt" or "pt" or "portugal" => "PRT",
|
||||
_ when country is { Length: >= 3 } => country.Trim().ToUpperInvariant()[..3],
|
||||
_ => "ESP",
|
||||
|
||||
Reference in New Issue
Block a user