Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
7 changes: 7 additions & 0 deletions api/Vote.Monitor.sln
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Feature.IncidentReports.Att
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Feature.Citizen.Notifications", "src\Feature.Citizen.Notifications\Feature.Citizen.Notifications.csproj", "{A43F29F9-5765-4143-AB9A-C3ECFCDD402F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Feature.Coalitions", "src\Feature.Coalitions\Feature.Coalitions.csproj", "{5F573792-C095-44F5-8DDD-05257CA41C9E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -470,6 +472,10 @@ Global
{A43F29F9-5765-4143-AB9A-C3ECFCDD402F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A43F29F9-5765-4143-AB9A-C3ECFCDD402F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A43F29F9-5765-4143-AB9A-C3ECFCDD402F}.Release|Any CPU.Build.0 = Release|Any CPU
{5F573792-C095-44F5-8DDD-05257CA41C9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5F573792-C095-44F5-8DDD-05257CA41C9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5F573792-C095-44F5-8DDD-05257CA41C9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5F573792-C095-44F5-8DDD-05257CA41C9E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -550,6 +556,7 @@ Global
{0567FED6-2464-462D-BE59-3A4FA50BF438} = {3441EE1D-E3C6-45BE-A020-553816015081}
{DF354318-6856-4925-96A0-0C458E530091} = {3441EE1D-E3C6-45BE-A020-553816015081}
{A43F29F9-5765-4143-AB9A-C3ECFCDD402F} = {17945B3C-5A4C-4279-8022-65ABC606A510}
{5F573792-C095-44F5-8DDD-05257CA41C9E} = {17945B3C-5A4C-4279-8022-65ABC606A510}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {50C20C9F-F2AF-45D8-994A-06661772B31C}
Expand Down
1 change: 1 addition & 0 deletions api/src/Authorization.Policies/PoliciesInstaller.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public static IServiceCollection AddAuthorizationPolicies(this IServiceCollectio
services.AddScoped<IAuthorizationHandler, MonitoringObserverAuthorizationHandler>();
services.AddScoped<IAuthorizationHandler, NgoAdminAuthorizationHandler>();
services.AddScoped<IAuthorizationHandler, CitizenReportingNgoAdminAuthorizationHandler>();
services.AddScoped<IAuthorizationHandler, CoalitionLeaderAuthorizationHandler>();

services.AddAuthorization(options =>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ protected override async Task HandleRequirementAsync(AuthorizationHandlerContext
return;
}

if (result.ElectionRoundStatus == ElectionRoundStatus.Archived
|| result.NgoStatus == NgoStatus.Deactivated
if (result.NgoStatus == NgoStatus.Deactivated
|| result.MonitoringNgoStatus == MonitoringNgoStatus.Suspended)
{
context.Fail();
Expand All @@ -46,4 +45,4 @@ protected override async Task HandleRequirementAsync(AuthorizationHandlerContext

context.Succeed(requirement);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using Authorization.Policies.Requirements;
using Authorization.Policies.Specifications;
using Vote.Monitor.Domain.Entities.CoalitionAggregate;
using Vote.Monitor.Domain.Entities.ElectionRoundAggregate;

namespace Authorization.Policies.RequirementHandlers;

internal class CoalitionLeaderAuthorizationHandler(
ICurrentUserProvider currentUserProvider,
ICurrentUserRoleProvider currentUserRoleProvider,
IReadRepository<Coalition> coalitionRepository)
: AuthorizationHandler<CoalitionLeaderRequirement>
{
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context,
CoalitionLeaderRequirement requirement)
{
if (!currentUserRoleProvider.IsNgoAdmin())
{
context.Fail();
return;
}

var ngoId = currentUserProvider.GetNgoId();
if (ngoId is null)
{
context.Fail();
return;
}

var coalitionLeaderSpecification = new GetCoalitionLeaderDetailsSpecification(requirement.ElectionRoundId, requirement.CoalitionId, ngoId.Value);
var result = await coalitionRepository.FirstOrDefaultAsync(coalitionLeaderSpecification);

if (result is null)
{
context.Fail();
return;
}

if (result.ElectionRoundStatus == ElectionRoundStatus.Archived
|| result.NgoStatus == NgoStatus.Deactivated
|| result.MonitoringNgoStatus == MonitoringNgoStatus.Suspended)
{
context.Fail();
return;
}

context.Succeed(requirement);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,7 @@ protected override async Task HandleRequirementAsync(AuthorizationHandlerContext

if (ngoAdminResult is not null)
{
if (ngoAdminResult.ElectionRoundStatus == ElectionRoundStatus.Archived ||
ngoAdminResult.NgoStatus == NgoStatus.Deactivated ||
if (ngoAdminResult.NgoStatus == NgoStatus.Deactivated ||
ngoAdminResult.MonitoringNgoStatus == MonitoringNgoStatus.Suspended)
{
context.Fail();
Expand All @@ -66,4 +65,4 @@ protected override async Task HandleRequirementAsync(AuthorizationHandlerContext

context.Fail();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Authorization.Policies.Requirements;

public class CoalitionLeaderRequirement(Guid electionRoundId, Guid coalitionId) : IAuthorizationRequirement
{
public Guid ElectionRoundId { get; } = electionRoundId;
public Guid CoalitionId { get; } = coalitionId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Vote.Monitor.Domain.Entities.ElectionRoundAggregate;

namespace Authorization.Policies.Specifications;

internal class CoalitionLeaderView
{
public required Guid ElectionRoundId { get; set; }
public required ElectionRoundStatus ElectionRoundStatus { get; set; }
public required Guid NgoId { get; set; }
public required NgoStatus NgoStatus { get; set; }
public required Guid MonitoringNgoId { get; set; }
public required MonitoringNgoStatus MonitoringNgoStatus { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Ardalis.Specification;
using Vote.Monitor.Domain.Entities.CoalitionAggregate;

namespace Authorization.Policies.Specifications;

internal sealed class GetCoalitionLeaderDetailsSpecification : SingleResultSpecification<Coalition, CoalitionLeaderView>
{
public GetCoalitionLeaderDetailsSpecification(Guid electionRoundId, Guid coalitionId, Guid ngoId)
{
Query
.Include(x => x.ElectionRound)
.Include(x => x.Leader)
.Where(x => x.Leader.NgoId == ngoId && x.ElectionRoundId == electionRoundId && x.Id == coalitionId)
.AsNoTracking();

Query.Select(x => new CoalitionLeaderView
{
ElectionRoundId = x.ElectionRoundId,
ElectionRoundStatus = x.ElectionRound.Status,
NgoId = x.Leader.NgoId,
NgoStatus = x.Leader.Ngo.Status,
MonitoringNgoId = x.Id,
MonitoringNgoStatus = x.Leader.Status
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ public GetMonitoringNgoSpecification(Guid electionRoundId, Guid ngoId)
MonitoringNgoStatus = x.Status
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ public GetMonitoringObserverSpecification(Guid electionRoundId, Guid? ngoId, Gui
Query
.Include(x => x.MonitoringNgo)
.ThenInclude(x => x.ElectionRound)
.Where(x => x.ObserverId == observerId && x.ElectionRoundId == electionRoundId && x.MonitoringNgo.NgoId == ngoId);
.Where(x => x.ObserverId == observerId
&& x.ElectionRoundId == electionRoundId
&& x.MonitoringNgo.NgoId == ngoId
&& x.MonitoringNgo.ElectionRoundId == electionRoundId);

Query.Select(x => new MonitoringObserverView
{
Expand All @@ -31,7 +34,7 @@ public GetMonitoringObserverSpecification(Guid electionRoundId, Guid observerId)
Query
.Include(x => x.MonitoringNgo)
.ThenInclude(x => x.ElectionRound)
.Where(x => x.ObserverId == observerId && x.MonitoringNgo.ElectionRoundId == electionRoundId)
.Where(x => x.ObserverId == observerId && x.ElectionRoundId == electionRoundId && x.MonitoringNgo.ElectionRoundId == electionRoundId)
.AsNoTracking();

Query.Select(x => new MonitoringObserverView
Expand Down
2 changes: 1 addition & 1 deletion api/src/Feature.Attachments/Create/Endpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public override async Task<Results<Ok<AttachmentModel>, NotFound, BadRequest<Pro
ElectionRoundId = attachment.ElectionRoundId,
PollingStationId = attachment.PollingStationId,
FormId = attachment.FormId,
QuestionId = attachment.QuestionId,
QuestionId = attachment.QuestionId
});
}
}
2 changes: 1 addition & 1 deletion api/src/Feature.Attachments/Get/Endpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public override async Task<Results<Ok<AttachmentModel>, BadRequest<ProblemDetail
ElectionRoundId = attachment.ElectionRoundId,
PollingStationId = attachment.PollingStationId,
FormId = attachment.FormId,
QuestionId = attachment.QuestionId,
QuestionId = attachment.QuestionId
});
}
}
2 changes: 1 addition & 1 deletion api/src/Feature.Attachments/List/Endpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public override async Task<Results<Ok<List<AttachmentModel>>, NotFound, BadReque
ElectionRoundId = attachment.ElectionRoundId,
PollingStationId = attachment.PollingStationId,
FormId = attachment.FormId,
QuestionId = attachment.QuestionId,
QuestionId = attachment.QuestionId
};
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ public sealed class GetAttachmentByIdSpecification : SingleResultSpecification<A
public GetAttachmentByIdSpecification(Guid electionRoundId, Guid observerId, Guid attachmentId)
{
Query.Where(x => x.ElectionRoundId == electionRoundId
&& x.MonitoringObserver.ObserverId == observerId && x.Id == attachmentId);
&& x.MonitoringObserver.ElectionRoundId == electionRoundId
&& x.MonitoringObserver.ObserverId == observerId
&& x.Id == attachmentId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ public GetObserverAttachmentsSpecification(Guid electionRoundId, Guid pollingSta
.Where(x => x.ElectionRoundId == electionRoundId
&& x.PollingStationId == pollingStationId
&& x.MonitoringObserver.ObserverId == observerId
&& x.MonitoringObserver.ElectionRoundId == electionRoundId
&& x.Form.ElectionRoundId == electionRoundId
&& x.FormId == formId
&& x.IsDeleted == false
&& x.IsCompleted == true);
Expand Down
2 changes: 1 addition & 1 deletion api/src/Feature.Citizen.Guides/GetById/Endpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ public override async Task<Results<Ok<CitizenGuideModel>, NotFound>> ExecuteAsyn
return TypedResults.Ok(citizenGuideModel with
{
PresignedUrl = (presignedUrl as GetPresignedUrlResult.Ok)?.Url ?? string.Empty,
UrlValidityInSeconds = (presignedUrl as GetPresignedUrlResult.Ok)?.UrlValidityInSeconds ?? 0,
UrlValidityInSeconds = (presignedUrl as GetPresignedUrlResult.Ok)?.UrlValidityInSeconds ?? 0
});
}

Expand Down
6 changes: 3 additions & 3 deletions api/src/Feature.Citizen.Notifications/Get/Endpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public override async Task<Results<Ok<CitizenNotificationModel>, NotFound>> Exec
CN."Title",
CN."Body",
CN."CreatedOn" "SentAt",
U."FirstName" || ' ' || U."LastName" "Sender"
U."DisplayName" "Sender"
FROM
"CitizenNotifications" CN
INNER JOIN "NgoAdmins" NA ON CN."SenderId" = NA."Id"
Expand All @@ -49,7 +49,7 @@ public override async Task<Results<Ok<CitizenNotificationModel>, NotFound>> Exec
{
electionRoundId = req.ElectionRoundId,
ngoId = req.NgoId,
id = req.Id,
id = req.Id
};

CitizenNotificationModel? notification;
Expand All @@ -61,4 +61,4 @@ public override async Task<Results<Ok<CitizenNotificationModel>, NotFound>> Exec

return notification == null ? TypedResults.NotFound() : TypedResults.Ok(notification);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ ORDER BY

var queryArgs = new
{
electionRoundId = req.ElectionRoundId,
electionRoundId = req.ElectionRoundId
};

string? ngoName;
Expand Down
6 changes: 3 additions & 3 deletions api/src/Feature.Citizen.Notifications/ListSent/Endpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public override async Task<Results<Ok<PagedResponse<CitizenNotificationModel>>,
CN."Title",
CN."Body",
CN."CreatedOn" AS "SentAt",
U."FirstName" || ' ' || U."LastName" AS "Sender"
U."DisplayName" AS "Sender"
FROM
"CitizenNotifications" CN
INNER JOIN "ElectionRounds" ER ON CN."ElectionRoundId" = ER."Id"
Expand All @@ -64,7 +64,7 @@ OFFSET @offset ROWS
electionRoundId = req.ElectionRoundId,
ngoId = req.NgoId,
offset = PaginationHelper.CalculateSkip(req.PageSize, req.PageNumber),
pageSize = req.PageSize,
pageSize = req.PageSize
};

int totalRowCount;
Expand All @@ -80,4 +80,4 @@ OFFSET @offset ROWS
return TypedResults.Ok(
new PagedResponse<CitizenNotificationModel>(entries, totalRowCount, req.PageNumber, req.PageSize));
}
}
}
2 changes: 1 addition & 1 deletion api/src/Feature.CitizenReports.Attachments/Get/Endpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ await repository.FirstOrDefaultAsync(
ElectionRoundId = attachment.ElectionRoundId,
CitizenReportId = attachment.CitizenReportId,
FormId = attachment.FormId,
QuestionId = attachment.QuestionId,
QuestionId = attachment.QuestionId
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public override async Task<Response>
ElectionRoundId = attachment.ElectionRoundId,
CitizenReportId = attachment.CitizenReportId,
FormId = attachment.FormId,
QuestionId = attachment.QuestionId,
QuestionId = attachment.QuestionId
};
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ public ListCitizenReportAttachmentsSpecification(Guid electionRoundId, Guid citi
Query
.Where(x => x.ElectionRoundId == electionRoundId
&& x.FormId == formId
&& x.Form.ElectionRoundId == electionRoundId
&& x.CitizenReportId == citizenReportId
&& !x.IsDeleted
&& x.IsCompleted);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@ public sealed class ListNotesSpecification : Specification<CitizenReportNoteAggr
{
public ListNotesSpecification(Guid electionRoundId, Guid citizenReportId)
{
Query.Where(x => x.ElectionRoundId == electionRoundId && x.FormId == citizenReportId);

Query.Where(x =>
x.ElectionRoundId == electionRoundId && x.FormId == citizenReportId &&
x.Form.ElectionRoundId == electionRoundId
);

Query.Select(note => CitizenReportNoteModel.FromEntity(note));
}
}
}
12 changes: 7 additions & 5 deletions api/src/Feature.CitizenReports/GetById/Endpoint.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
using Feature.CitizenReports.Models;
using Vote.Monitor.Answer.Module.Mappers;
using Vote.Monitor.Answer.Module.Mappers;
using Vote.Monitor.Core.Services.FileStorage.Contracts;
using Vote.Monitor.Form.Module.Mappers;
using AttachmentModel = Feature.CitizenReports.Models.AttachmentModel;
using NoteModel = Feature.CitizenReports.Models.NoteModel;

namespace Feature.CitizenReports.GetById;

Expand Down Expand Up @@ -37,6 +38,7 @@ public override async Task<Results<Ok<Response>, NotFound>> ExecuteAsync(Request
.Where(x =>
x.ElectionRoundId == req.ElectionRoundId
&& x.Form.MonitoringNgo.NgoId == req.NgoId
&& x.Form.MonitoringNgo.ElectionRoundId == req.ElectionRoundId
&& x.Id == req.CitizenReportId)
.AsSplitQuery()
.FirstOrDefaultAsync(ct);
Expand Down Expand Up @@ -64,7 +66,7 @@ public override async Task<Results<Ok<Response>, NotFound>> ExecuteAsync(Request
return attachment with
{
PresignedUrl = (presignedUrl as GetPresignedUrlResult.Ok)?.Url ?? string.Empty,
UrlValidityInSeconds = (presignedUrl as GetPresignedUrlResult.Ok)?.UrlValidityInSeconds ?? 0,
UrlValidityInSeconds = (presignedUrl as GetPresignedUrlResult.Ok)?.UrlValidityInSeconds ?? 0
};
}).ToArray();

Expand All @@ -89,9 +91,9 @@ public override async Task<Results<Ok<Response>, NotFound>> ExecuteAsync(Request
LocationLevel2 = citizenReport.Location.Level2,
LocationLevel3 = citizenReport.Location.Level3,
LocationLevel4 = citizenReport.Location.Level4,
LocationLevel5 = citizenReport.Location.Level5,
LocationLevel5 = citizenReport.Location.Level5
};

return TypedResults.Ok(response);
}
}
}
Loading