From 286e8981d86afaec8c6e16b05728a408ece05e0a Mon Sep 17 00:00:00 2001 From: Ion Dormenco Date: Thu, 13 Feb 2025 12:08:34 +0200 Subject: [PATCH] Fix guide access for observers --- .../Feature.ObserverGuide/List/Endpoint.cs | 107 ++++++++++++------ .../Features/Coalition/GuideAccessTests.cs | 24 ++++ 2 files changed, 97 insertions(+), 34 deletions(-) diff --git a/api/src/Feature.ObserverGuide/List/Endpoint.cs b/api/src/Feature.ObserverGuide/List/Endpoint.cs index 662ced81c..ca5722981 100644 --- a/api/src/Feature.ObserverGuide/List/Endpoint.cs +++ b/api/src/Feature.ObserverGuide/List/Endpoint.cs @@ -238,45 +238,84 @@ private async Task, NotFound>> ListObserverGuidesAsObserver G."WebsiteUrl", G."FilePath", G."UploadedFileName", - COALESCE(G."LastModifiedOn", G."CreatedOn") AS"CreatedOn", - n."Name" AS "CreatedBy", - EXISTS ( + G."CreatedOn", + G."CreatedBy" + FROM + ( SELECT - 1 + G."Id", + G."Title", + G."FileName", + G."MimeType", + G."GuideType", + G."Text", + G."WebsiteUrl", + G."FilePath", + G."UploadedFileName", + COALESCE(G."LastModifiedOn", G."CreatedOn") AS"CreatedOn", + n."Name" AS "CreatedBy" FROM - "GetMonitoringNgoDetails" (@electionRoundId, @ngoId) + "CoalitionGuideAccess" CGA + INNER JOIN "Coalitions" C ON CGA."CoalitionId" = C."Id" + INNER JOIN "ObserversGuides" G ON CGA."GuideId" = G."Id" + INNER JOIN "MonitoringNgos" mn on g."MonitoringNgoId" = mn."Id" + INNER JOIN "Ngos" n on n."Id" = mn."NgoId" WHERE - "MonitoringNgoId" = G."MonitoringNgoId" - ) AS "IsGuideOwner" - FROM - "CoalitionGuideAccess" CGA - INNER JOIN "Coalitions" C ON CGA."CoalitionId" = C."Id" - INNER JOIN "ObserversGuides" G ON CGA."GuideId" = G."Id" - INNER JOIN "MonitoringNgos" mn on g."MonitoringNgoId" = mn."Id" - INNER JOIN "Ngos" n on n."Id" = mn."NgoId" - WHERE - CGA."MonitoringNgoId" = ( + CGA."MonitoringNgoId" = ( + SELECT + "MonitoringNgoId" + FROM + "GetMonitoringNgoDetails" (@electionRoundId, @ngoId) + ) + AND g."IsDeleted" = false + AND C."ElectionRoundId" = @electionRoundId + AND ( + ( + SELECT + "CoalitionId" IS NOT NULL + FROM + "GetMonitoringNgoDetails" (@electionRoundId, @ngoId) + ) + OR ( + SELECT + "IsCoalitionLeader" + FROM + "GetMonitoringNgoDetails" (@electionRoundId, @ngoId) + ) + ) + UNION SELECT - "MonitoringNgoId" + G."Id", + G."Title", + G."FileName", + G."MimeType", + G."GuideType", + G."Text", + G."WebsiteUrl", + G."FilePath", + G."UploadedFileName", + COALESCE(G."LastModifiedOn", G."CreatedOn") AS"CreatedOn", + n."Name" AS "CreatedBy" FROM - "GetMonitoringNgoDetails" (@electionRoundId, @ngoId) - ) - AND C."ElectionRoundId" = @electionRoundId - AND g."IsDeleted" = false - AND ( - ( - SELECT - "CoalitionId" IS NOT NULL - FROM - "GetMonitoringNgoDetails" (@electionRoundId, @ngoId) - ) - OR ( - SELECT - "IsCoalitionLeader" - FROM - "GetMonitoringNgoDetails" (@electionRoundId, @ngoId) - ) - ) + "ObserversGuides" G + INNER JOIN "MonitoringNgos" MN ON G."MonitoringNgoId" = MN."Id" + INNER JOIN "Ngos" n on n."Id" = mn."NgoId" + WHERE + MN."ElectionRoundId" = @electionRoundId + AND g."IsDeleted" = false + AND G."MonitoringNgoId" = ( + SELECT + "MonitoringNgoId" + FROM + "GetMonitoringNgoDetails" (@electionRoundId, @ngoId) + ) + AND ( + SELECT + "CoalitionId" IS NULL + FROM + "GetMonitoringNgoDetails" (@electionRoundId, @ngoId) + ) + ) G """; var queryArgs = new { electionRoundId, ngoId = ngo.NgoId }; diff --git a/api/tests/Vote.Monitor.Api.IntegrationTests/Features/Coalition/GuideAccessTests.cs b/api/tests/Vote.Monitor.Api.IntegrationTests/Features/Coalition/GuideAccessTests.cs index 3a6420b02..fd9c8363d 100644 --- a/api/tests/Vote.Monitor.Api.IntegrationTests/Features/Coalition/GuideAccessTests.cs +++ b/api/tests/Vote.Monitor.Api.IntegrationTests/Features/Coalition/GuideAccessTests.cs @@ -11,6 +11,30 @@ namespace Vote.Monitor.Api.IntegrationTests.Features.Coalition; public class GuideAccessTests : BaseApiTestFixture { + [Test] + public void ShouldGrantAccessToObservers_WhenNotInACoalition() + { + // Arrange + var scenarioData = ScenarioBuilder.New(CreateClient) + .WithNgo(ScenarioNgos.Alfa) + .WithNgo(ScenarioNgos.Beta) + .WithObserver(ScenarioObserver.Alice) + .WithObserver(ScenarioObserver.Bob) + .WithElectionRound(ScenarioElectionRound.A, + er => er + .WithMonitoringNgo(ScenarioNgos.Alfa, + alfa => alfa.WithMonitoringObserver(ScenarioObserver.Alice).WithGuide())) + .Please(); + + // Act + var aliceGuides = scenarioData + .ObserverByName(ScenarioObserver.Alice) + .GetResponse($"/api/election-rounds/{scenarioData.ElectionRoundId}/observer-guide"); + + // Assert + aliceGuides.Guides.Should().NotBeEmpty(); + } + [Test] public void ShouldNotGrantGuideAccessForMonitoringObservers_WhenCreatingNewGuide() {