arreglo certificados de registro

This commit is contained in:
2026-07-23 12:37:06 +02:00
parent 33c9c03822
commit dd31460cf0
25 changed files with 1370 additions and 119 deletions

View File

@@ -104,16 +104,25 @@ public sealed class InboxTrackingService : IInboxTrackingService
LastDownloadedAt = meta?.LastDownloadedAtUtc?.ToString("O", CultureInfo.InvariantCulture),
AlreadyImported = meta?.AlreadyImported ?? false,
AlreadyInGestiona = meta?.AlreadyInGestiona ?? false,
OwnerUsername = meta?.OwnerUsername,
OwnedByCurrentUser = meta?.OwnedByCurrentUser ?? false,
AccessibleByWorkGroup = meta?.AccessibleByWorkGroup ?? false,
RequiresOwnerConfirmation = meta?.RequiresOwnerConfirmation ?? false,
OwnerWorkGroups = meta?.OwnerWorkGroups ?? [],
TrackingNote = BuildTrackingNote(meta)
};
})
.Where(report => !IsLockedByAnotherUser(report))
.Where(report =>
string.IsNullOrWhiteSpace(report.OwnerUsername) ||
report.OwnedByCurrentUser ||
report.AccessibleByWorkGroup)
.ToArray();
}
public async Task EnsureReportCanBeImportedByUserAsync(
string username,
ReportDto report,
bool confirmDifferentOwner = false,
CancellationToken cancellationToken = default)
{
await _denunciaStore.EnsureSchemaAsync(cancellationToken);
@@ -140,14 +149,23 @@ public sealed class InboxTrackingService : IInboxTrackingService
await EnsureConnectionOpenAsync(connection, cancellationToken);
var metadata = await LoadMetadataAsync(connection, userId, [report.Id], cancellationToken);
if (metadata.TryGetValue(report.Id, out var meta) && meta.LockedByAnotherUser)
if (!metadata.TryGetValue(report.Id, out var meta) ||
string.IsNullOrWhiteSpace(meta.OwnerUsername) ||
meta.OwnedByCurrentUser)
{
var owner = string.IsNullOrWhiteSpace(meta.LastDownloadedByUsername)
? "otro usuario"
: meta.LastDownloadedByUsername;
return;
}
throw new InvalidOperationException(
$"La denuncia ya fue importada por {owner}. Solo ese usuario puede ver e importar sus actualizaciones.");
if (!meta.AccessibleByWorkGroup)
{
throw new ReportOwnershipException(
$"La denuncia pertenece a {meta.OwnerUsername} y no compartis ningun grupo de trabajo.");
}
if (!confirmDifferentOwner)
{
throw new ReportOwnershipException(
$"La denuncia pertenece a {meta.OwnerUsername}. Confirma expresamente que deseas importarla como miembro de su grupo.");
}
}
@@ -180,6 +198,7 @@ public sealed class InboxTrackingService : IInboxTrackingService
SET
last_downloaded_at_utc = @nowUtc,
last_downloaded_by_user_id = @userId,
owner_user_id = COALESCE(owner_user_id, @userId),
imported_complaint_report_id = COALESCE(@complaintId, imported_complaint_report_id),
imported_to_store_at_utc = COALESCE(imported_to_store_at_utc, @nowUtc),
updated_at_utc = CURRENT_TIMESTAMP(6)
@@ -298,6 +317,7 @@ public sealed class InboxTrackingService : IInboxTrackingService
ELSE last_downloaded_at_utc
END,
last_downloaded_by_user_id = @userId,
owner_user_id = COALESCE(owner_user_id, @userId),
imported_complaint_report_id = COALESCE(imported_complaint_report_id, @denunciaId),
imported_to_store_at_utc = COALESCE(imported_to_store_at_utc, @handledAtUtc),
updated_at_utc = CURRENT_TIMESTAMP(6)
@@ -512,11 +532,37 @@ public sealed class InboxTrackingService : IInboxTrackingService
ir.global_report_uuid,
ir.last_downloaded_at_utc,
downloader.username AS last_downloaded_by_username,
owner.username AS owner_username,
ir.imported_to_store_at_utc,
COALESCE(c.is_in_gestiona, 0) AS already_in_gestiona,
CASE WHEN uir.last_downloaded_at_utc IS NULL THEN 0 ELSE 1 END AS downloaded_by_current_user
CASE WHEN uir.last_downloaded_at_utc IS NULL THEN 0 ELSE 1 END AS downloaded_by_current_user,
CASE WHEN ir.owner_user_id = @userId THEN 1 ELSE 0 END AS owned_by_current_user,
CASE
WHEN ir.owner_user_id IS NULL THEN 0
WHEN EXISTS (
SELECT 1
FROM app_user_groups current_group
INNER JOIN app_user_groups owner_group
ON owner_group.work_group_id = current_group.work_group_id
INNER JOIN work_groups active_group
ON active_group.id = current_group.work_group_id
AND active_group.is_active = 1
WHERE current_group.app_user_id = @userId
AND owner_group.app_user_id = ir.owner_user_id
) THEN 1
ELSE 0
END AS accessible_by_group,
(
SELECT GROUP_CONCAT(DISTINCT wg.code ORDER BY wg.code SEPARATOR ',')
FROM app_user_groups owner_membership
INNER JOIN work_groups wg
ON wg.id = owner_membership.work_group_id
AND wg.is_active = 1
WHERE owner_membership.app_user_id = ir.owner_user_id
) AS owner_group_codes
FROM inbox_reports ir
LEFT JOIN app_users downloader ON downloader.id = ir.last_downloaded_by_user_id
LEFT JOIN app_users owner ON owner.id = ir.owner_user_id
LEFT JOIN user_inbox_reports uir
ON uir.inbox_report_id = ir.id
AND uir.app_user_id = @userId
@@ -533,14 +579,20 @@ public sealed class InboxTrackingService : IInboxTrackingService
? null
: reader.GetString(reader.GetOrdinal("last_downloaded_by_username"));
var downloadedByCurrentUser = reader.GetInt32(reader.GetOrdinal("downloaded_by_current_user")) == 1;
var lockedByAnotherUser =
!downloadedByCurrentUser &&
!reader.IsDBNull(reader.GetOrdinal("imported_to_store_at_utc")) &&
!string.IsNullOrWhiteSpace(lastDownloadedByUsername);
var downloadedByAnotherUser =
!downloadedByCurrentUser &&
!string.IsNullOrWhiteSpace(lastDownloadedByUsername);
var downloadedByAnotherUser =
!downloadedByCurrentUser &&
!string.IsNullOrWhiteSpace(lastDownloadedByUsername);
var ownerUsername = reader.IsDBNull(reader.GetOrdinal("owner_username"))
? null
: reader.GetString(reader.GetOrdinal("owner_username"));
var ownedByCurrentUser =
reader.GetInt32(reader.GetOrdinal("owned_by_current_user")) == 1;
var accessibleByGroup =
reader.GetInt32(reader.GetOrdinal("accessible_by_group")) == 1;
var ownerWorkGroups = reader.IsDBNull(reader.GetOrdinal("owner_group_codes"))
? []
: reader.GetString(reader.GetOrdinal("owner_group_codes"))
.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
metadata[reportId] = new ReportMetadata
{
@@ -550,7 +602,10 @@ public sealed class InboxTrackingService : IInboxTrackingService
LastDownloadedAtUtc = GetDateTimeOffset(reader, "last_downloaded_at_utc"),
AlreadyImported = !reader.IsDBNull(reader.GetOrdinal("imported_to_store_at_utc")),
AlreadyInGestiona = reader.GetInt32(reader.GetOrdinal("already_in_gestiona")) == 1,
LockedByAnotherUser = lockedByAnotherUser,
OwnerUsername = ownerUsername,
OwnedByCurrentUser = ownedByCurrentUser,
AccessibleByWorkGroup = accessibleByGroup,
OwnerWorkGroups = ownerWorkGroups,
};
}
@@ -654,11 +709,10 @@ public sealed class InboxTrackingService : IInboxTrackingService
return null;
}
if (metadata.LockedByAnotherUser)
if (!string.IsNullOrWhiteSpace(metadata.OwnerUsername) &&
!metadata.OwnedByCurrentUser)
{
return string.IsNullOrWhiteSpace(metadata.LastDownloadedByUsername)
? "Importada por otro usuario"
: $"Importada por {metadata.LastDownloadedByUsername}";
return $"Propiedad de {metadata.OwnerUsername}";
}
if (metadata.AlreadyInGestiona)
@@ -693,15 +747,25 @@ public sealed class InboxTrackingService : IInboxTrackingService
{
public bool DownloadedByCurrentUser { get; init; }
public bool DownloadedByAnotherUser { get; init; }
public bool LockedByAnotherUser { get; init; }
public string? LastDownloadedByUsername { get; init; }
public DateTimeOffset? LastDownloadedAtUtc { get; init; }
public bool AlreadyImported { get; init; }
public bool AlreadyInGestiona { get; init; }
public string? OwnerUsername { get; init; }
public bool OwnedByCurrentUser { get; init; }
public bool AccessibleByWorkGroup { get; init; }
public IReadOnlyList<string> OwnerWorkGroups { get; init; } = [];
public bool RequiresOwnerConfirmation =>
!OwnedByCurrentUser &&
AccessibleByWorkGroup &&
!string.IsNullOrWhiteSpace(OwnerUsername);
}
}
public sealed class ReportOwnershipException : InvalidOperationException
{
public ReportOwnershipException(string message)
: base(message)
{
}
private static bool IsLockedByAnotherUser(ReportDto report)
=> report.AlreadyImported &&
report.DownloadedByAnotherUser &&
!report.DownloadedByCurrentUser;
}