Skip to content

Commit 081da77

Browse files
FriptuTidormenco
andauthored
Feat/ElectionRoundFormTemplatesAssignment (#870)
* adding ElectionRoundFormTemplate #1 Creating entity and starting endpoint * Update .gitignore ignoring /api/src/Vote.Monitor.Api/Uploads * assign templates to election round - endpoint#1 assign templates to election round - endpoint with tests #1 * adding AssignTemplates tests for DeleteRangeAsync and Validator #2 * adjust for ElectionRoundFormTemplateAssignment #3 updates on assigning templates on an ElectionRound consisting of tests, endpoint and configuration files * adjust testValidators ElectionRoundFormTemplateAssignment #4 --------- Co-authored-by: Ion Dormenco <idormenco@gmail.com>
1 parent 6238959 commit 081da77

File tree

17 files changed

+7563
-1
lines changed

17 files changed

+7563
-1
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,3 +271,4 @@ log*.txt
271271
.vscode
272272

273273
OfflineCapabilities
274+
/api/src/Vote.Monitor.Api/Uploads
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
using Feature.FormTemplates.Specifications;
2+
using Microsoft.EntityFrameworkCore;
3+
using Vote.Monitor.Domain;
4+
using Vote.Monitor.Domain.Entities.ElectionRoundAggregate;
5+
using Vote.Monitor.Domain.Entities.ElectionRoundFormTemplateAggregate;
6+
7+
namespace Feature.FormTemplates.AssignTemplates;
8+
9+
public class Endpoint(
10+
IReadRepository<ElectionRound> electionRoundRepository,
11+
IReadRepository<FormTemplateAggregate> formTemplateRepository,
12+
IRepository<ElectionRoundFormTemplate> electionRoundFormTemplateRepository
13+
) :
14+
Endpoint<Request, Results<NoContent, NotFound>>
15+
{
16+
public override void Configure()
17+
{
18+
Post("/api/election-rounds/{electionRoundId}/form-templates:assign-templates");
19+
Policies(PolicyNames.PlatformAdminsOnly);
20+
}
21+
22+
public override async Task<Results<NoContent, NotFound>> ExecuteAsync(Request req, CancellationToken ct)
23+
{
24+
var electionRoundExists =
25+
await electionRoundRepository.AnyAsync(new GetElectionRoundByIdSpecification(req.ElectionRoundId), ct);
26+
27+
if (electionRoundExists is false)
28+
{
29+
return TypedResults.NotFound();
30+
}
31+
32+
if (await formTemplateRepository.CountAsync(new ListFormTemplatesByIds(req.FormTemplateIds)) !=
33+
req.FormTemplateIds.Count)
34+
{
35+
return TypedResults.NotFound();
36+
}
37+
38+
var existingAssignments = await electionRoundFormTemplateRepository
39+
.ListAsync(new ListElectionRoundFormTemplateSpecification(req.ElectionRoundId), ct);
40+
41+
var existingTemplateIds = existingAssignments
42+
.Select(x => x.FormTemplateId)
43+
.ToList();
44+
45+
var templatesToAdd = req.FormTemplateIds.Except(existingTemplateIds).ToList();
46+
var templatesToRemove = existingTemplateIds.Except(req.FormTemplateIds).ToList();
47+
48+
if (templatesToRemove.Any())
49+
{
50+
var assignmentsToDelete = existingAssignments
51+
.Where(x => templatesToRemove.Contains(x.FormTemplateId))
52+
.ToList();
53+
await electionRoundFormTemplateRepository.DeleteRangeAsync(assignmentsToDelete, ct);
54+
}
55+
56+
if (templatesToAdd.Any())
57+
{
58+
var newAssignments = templatesToAdd
59+
.Select(templateId => ElectionRoundFormTemplate.Create(req.ElectionRoundId, templateId))
60+
.ToList();
61+
await electionRoundFormTemplateRepository.AddRangeAsync(newAssignments, ct);
62+
}
63+
64+
return TypedResults.NoContent();
65+
}
66+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace Feature.FormTemplates.AssignTemplates;
2+
3+
public class Request
4+
{
5+
public Guid ElectionRoundId { get; set; }
6+
public List<Guid> FormTemplateIds { get; set; } = new List<Guid>();
7+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace Feature.FormTemplates.AssignTemplates;
2+
3+
public class Validator : Validator<Request>
4+
{
5+
public Validator()
6+
{
7+
RuleFor(x => x.ElectionRoundId).NotEmpty();
8+
RuleFor(x => x.FormTemplateIds).NotEmpty();
9+
RuleForEach(x => x.FormTemplateIds).NotEmpty();
10+
}
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using Vote.Monitor.Domain.Entities.ElectionRoundAggregate;
2+
3+
namespace Feature.FormTemplates.Specifications;
4+
5+
public sealed class GetElectionRoundByIdSpecification : Specification<ElectionRound>
6+
{
7+
public GetElectionRoundByIdSpecification(Guid electionRoundId)
8+
{
9+
Query.Where(x => x.Id == electionRoundId);
10+
}
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using Vote.Monitor.Domain.Entities.ElectionRoundFormTemplateAggregate;
2+
3+
namespace Feature.FormTemplates.Specifications;
4+
5+
public sealed class ListElectionRoundFormTemplateSpecification : Specification<ElectionRoundFormTemplate>
6+
{
7+
public ListElectionRoundFormTemplateSpecification(Guid electionRoundId)
8+
{
9+
Query.Where(e => e.ElectionRoundId == electionRoundId);
10+
}
11+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace Feature.FormTemplates.Specifications;
2+
3+
public sealed class ListFormTemplatesByIds: Specification<FormTemplateAggregate>
4+
{
5+
public ListFormTemplatesByIds(List<Guid> formTemplateIds)
6+
{
7+
Query.Where(formTemplate => formTemplateIds.Contains(formTemplate.Id));
8+
}
9+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using Vote.Monitor.Domain.Entities.FormTemplateAggregate;
2+
3+
namespace Vote.Monitor.Domain.Entities.ElectionRoundFormTemplateAggregate;
4+
5+
public class ElectionRoundFormTemplate: AuditableBaseEntity, IAggregateRoot
6+
{
7+
public Guid Id { get; private set; }
8+
public Guid ElectionRoundId { get; private set; }
9+
public ElectionRound ElectionRound { get; private set; }
10+
public Guid FormTemplateId { get; private set; }
11+
public FormTemplate FormTemplate { get; private set; }
12+
13+
internal ElectionRoundFormTemplate(Guid electionRoundId, Guid formTemplateId)
14+
{
15+
Id = Guid.NewGuid();
16+
ElectionRoundId = electionRoundId;
17+
FormTemplateId = formTemplateId;
18+
}
19+
20+
public static ElectionRoundFormTemplate Create(Guid electionRoundId, Guid formTemplateId) =>
21+
new(electionRoundId, formTemplateId);
22+
23+
#pragma warning disable CS8618 // Required by Entity Framework
24+
private ElectionRoundFormTemplate()
25+
{
26+
27+
}
28+
#pragma warning restore CS8618
29+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using Microsoft.EntityFrameworkCore.Metadata.Builders;
2+
using Vote.Monitor.Domain.Entities.ElectionRoundFormTemplateAggregate;
3+
4+
namespace Vote.Monitor.Domain.EntitiesConfiguration;
5+
6+
public class ElectionRoundFormTemplateConfiguration : IEntityTypeConfiguration<ElectionRoundFormTemplate>
7+
{
8+
public void Configure(EntityTypeBuilder<ElectionRoundFormTemplate> builder)
9+
{
10+
builder.HasKey(x => x.Id);
11+
12+
builder.HasIndex(x => new { x.ElectionRoundId, x.FormTemplateId }).IsUnique();
13+
14+
builder
15+
.HasOne(x => x.ElectionRound)
16+
.WithMany()
17+
.HasForeignKey(x => x.ElectionRoundId);
18+
19+
builder.HasOne(x => x.FormTemplate)
20+
.WithMany()
21+
.HasForeignKey(x => x.FormTemplateId);
22+
}
23+
}

0 commit comments

Comments
 (0)