Skip to content

Commit 058a8a3

Browse files
feat: restriction table (#361)
* feat: add RestrictionEntry and RestrictionTable entities with configuration * feat: add DTOs and mapping extensions for RestrictionEntry and RestrictionTable * feat: implement RestrictionEntry and RestrictionTable controllers, services, and repositories * feat: enhance RestrictionTable to include RestrictionEntries in DTOs and repository queries * feat: enhance restriction table functionality with rebuilding logic and DTO adjustments * feat: add Restriction and RestrictionEntry tables with relationships and constraints - Created RestrictionTables and RestrictionEntries with necessary columns and constraints. - Implemented foreign key relationships to Options, Outcomes, Projects, and Users. - Added computed columns for ParentStateId and ChildStateId in RestrictionEntries. - Defined check constraints to ensure valid combinations of Parent and Child options/outcomes. - Updated AppDbContextModelSnapshot to reflect new entities and their relationships. * feat: ensure changes are saved after rebuilding restriction tables
1 parent 807cc44 commit 058a8a3

30 files changed

Lines changed: 5370 additions & 15 deletions
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
using PrismaApi.Api.Extensions;
3+
using PrismaApi.Application.Interfaces.Services;
4+
using PrismaApi.Domain.Dtos;
5+
using PrismaApi.Infrastructure.Context;
6+
7+
namespace PrismaApi.Api.Controllers;
8+
9+
[ApiController]
10+
[Route("")]
11+
public class RestrictionEntriesController : PrismaBaseEntityController
12+
{
13+
private readonly IRestrictionEntryService _restrictionEntryService;
14+
15+
public RestrictionEntriesController(
16+
IRestrictionEntryService restrictionEntryService,
17+
AppDbContext dbContext)
18+
: base(dbContext)
19+
{
20+
_restrictionEntryService = restrictionEntryService;
21+
}
22+
23+
[HttpPost("restriction_entries")]
24+
public async Task<ActionResult<List<RestrictionEntryOutgoingDto>>> CreateRestrictionEntries([FromBody] List<RestrictionEntryIncomingDto> dtos, CancellationToken ct = default)
25+
{
26+
UserOutgoingDto user = HttpContext.GetLoadedUser();
27+
28+
await BeginTransactionAsync(ct);
29+
try
30+
{
31+
var result = await _restrictionEntryService.CreateAsync(dtos, user, ct);
32+
await CommitTransactionAsync(ct);
33+
return Ok(result);
34+
}
35+
catch
36+
{
37+
await RollbackTransactionAsync(CancellationToken.None);
38+
throw;
39+
}
40+
}
41+
42+
[HttpGet("restriction_entries/{id:guid}")]
43+
public async Task<ActionResult<RestrictionEntryOutgoingDto>> GetRestrictionEntry(Guid id, CancellationToken ct = default)
44+
{
45+
UserOutgoingDto user = HttpContext.GetLoadedUser();
46+
var result = await _restrictionEntryService.GetAsync(new List<Guid> { id }, user, ct);
47+
return result.Count > 0 ? Ok(result[0]) : NotFound();
48+
}
49+
50+
[HttpGet("restriction_entries")]
51+
public async Task<ActionResult<List<RestrictionEntryOutgoingDto>>> GetAllRestrictionEntries(CancellationToken ct = default)
52+
{
53+
UserOutgoingDto user = HttpContext.GetLoadedUser();
54+
var result = await _restrictionEntryService.GetAllAsync(user, ct);
55+
return Ok(result);
56+
}
57+
58+
[HttpPut("restriction_entries")]
59+
public async Task<ActionResult<List<RestrictionEntryOutgoingDto>>> UpdateRestrictionEntries([FromBody] List<RestrictionEntryIncomingDto> dtos, CancellationToken ct = default)
60+
{
61+
UserOutgoingDto user = HttpContext.GetLoadedUser();
62+
63+
await BeginTransactionAsync(ct);
64+
try
65+
{
66+
var result = await _restrictionEntryService.UpdateAsync(dtos, user, ct);
67+
await CommitTransactionAsync(ct);
68+
return Ok(result);
69+
}
70+
catch
71+
{
72+
await RollbackTransactionAsync(CancellationToken.None);
73+
throw;
74+
}
75+
}
76+
77+
[HttpDelete("restriction_entries/{id:guid}")]
78+
public async Task<IActionResult> DeleteRestrictionEntry(Guid id, CancellationToken ct = default)
79+
{
80+
UserOutgoingDto user = HttpContext.GetLoadedUser();
81+
82+
await BeginTransactionAsync(ct);
83+
try
84+
{
85+
await _restrictionEntryService.DeleteAsync(new List<Guid> { id }, user, ct);
86+
await CommitTransactionAsync(ct);
87+
return NoContent();
88+
}
89+
catch
90+
{
91+
await RollbackTransactionAsync(CancellationToken.None);
92+
throw;
93+
}
94+
}
95+
96+
[HttpDelete("restriction_entries")]
97+
public async Task<IActionResult> DeleteRestrictionEntries([FromQuery] List<Guid> ids, CancellationToken ct = default)
98+
{
99+
UserOutgoingDto user = HttpContext.GetLoadedUser();
100+
101+
await BeginTransactionAsync(ct);
102+
try
103+
{
104+
await _restrictionEntryService.DeleteAsync(ids, user, ct);
105+
await CommitTransactionAsync(ct);
106+
return NoContent();
107+
}
108+
catch
109+
{
110+
await RollbackTransactionAsync(CancellationToken.None);
111+
throw;
112+
}
113+
}
114+
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
using PrismaApi.Api.Extensions;
3+
using PrismaApi.Application.Interfaces.Services;
4+
using PrismaApi.Domain.Dtos;
5+
using PrismaApi.Infrastructure.Context;
6+
7+
namespace PrismaApi.Api.Controllers;
8+
9+
[ApiController]
10+
[Route("")]
11+
public class RestrictionTablesController : PrismaBaseEntityController
12+
{
13+
private readonly IRestrictionTableService _restrictionTableService;
14+
private readonly ITableRebuildingService _tableRebuildingService;
15+
16+
public RestrictionTablesController(
17+
IRestrictionTableService restrictionTableService,
18+
ITableRebuildingService tableRebuildingService,
19+
AppDbContext dbContext)
20+
: base(dbContext)
21+
{
22+
_restrictionTableService = restrictionTableService;
23+
_tableRebuildingService = tableRebuildingService;
24+
}
25+
26+
[HttpPost("restriction_tables")]
27+
public async Task<ActionResult<List<RestrictionTableOutgoingDto>>> CreateRestrictionTables([FromBody] List<RestrictionTableIncomingDto> dtos, CancellationToken ct = default)
28+
{
29+
UserOutgoingDto user = HttpContext.GetLoadedUser();
30+
31+
await BeginTransactionAsync(ct);
32+
try
33+
{
34+
var result = await _restrictionTableService.CreateAsync(dtos, user, ct);
35+
await _tableRebuildingService.RebuildTablesAsync(ct);
36+
await CommitTransactionAsync(ct);
37+
return Ok(result);
38+
}
39+
catch
40+
{
41+
await RollbackTransactionAsync(CancellationToken.None);
42+
throw;
43+
}
44+
}
45+
46+
[HttpGet("restriction_tables/{id:guid}")]
47+
public async Task<ActionResult<RestrictionTableOutgoingDto>> GetRestrictionTable(Guid id, CancellationToken ct = default)
48+
{
49+
UserOutgoingDto user = HttpContext.GetLoadedUser();
50+
var result = await _restrictionTableService.GetAsync(new List<Guid> { id }, user, ct);
51+
return result.Count > 0 ? Ok(result[0]) : NotFound();
52+
}
53+
54+
[HttpGet("restriction_tables")]
55+
public async Task<ActionResult<List<RestrictionTableOutgoingDto>>> GetAllRestrictionTables(CancellationToken ct = default)
56+
{
57+
UserOutgoingDto user = HttpContext.GetLoadedUser();
58+
var result = await _restrictionTableService.GetAllAsync(user, ct);
59+
return Ok(result);
60+
}
61+
62+
[HttpPut("restriction_tables")]
63+
public async Task<ActionResult<List<RestrictionTableOutgoingDto>>> UpdateRestrictionTables([FromBody] List<RestrictionTableIncomingDto> dtos, CancellationToken ct = default)
64+
{
65+
UserOutgoingDto user = HttpContext.GetLoadedUser();
66+
67+
await BeginTransactionAsync(ct);
68+
try
69+
{
70+
var result = await _restrictionTableService.UpdateAsync(dtos, user, ct);
71+
await _tableRebuildingService.RebuildTablesAsync(ct);
72+
await CommitTransactionAsync(ct);
73+
return Ok(result);
74+
}
75+
catch
76+
{
77+
await RollbackTransactionAsync(CancellationToken.None);
78+
throw;
79+
}
80+
}
81+
82+
[HttpDelete("restriction_tables/{id:guid}")]
83+
public async Task<IActionResult> DeleteRestrictionTable(Guid id, CancellationToken ct = default)
84+
{
85+
UserOutgoingDto user = HttpContext.GetLoadedUser();
86+
87+
await BeginTransactionAsync(ct);
88+
try
89+
{
90+
await _restrictionTableService.DeleteAsync(new List<Guid> { id }, user, ct);
91+
await CommitTransactionAsync(ct);
92+
return NoContent();
93+
}
94+
catch
95+
{
96+
await RollbackTransactionAsync(CancellationToken.None);
97+
throw;
98+
}
99+
}
100+
101+
[HttpDelete("restriction_tables")]
102+
public async Task<IActionResult> DeleteRestrictionTables([FromQuery] List<Guid> ids, CancellationToken ct = default)
103+
{
104+
UserOutgoingDto user = HttpContext.GetLoadedUser();
105+
106+
await BeginTransactionAsync(ct);
107+
try
108+
{
109+
await _restrictionTableService.DeleteAsync(ids, user, ct);
110+
await CommitTransactionAsync(ct);
111+
return NoContent();
112+
}
113+
catch
114+
{
115+
await RollbackTransactionAsync(CancellationToken.None);
116+
throw;
117+
}
118+
}
119+
}

PrismaDotnetApi/PrismaApi.Api/Program.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ public static void Main(string[] args)
119119
builder.Services.AddScoped<IAssessmentRepository, AssessmentRepository>();
120120
builder.Services.AddScoped<IDecisionQualityAssessmentRepository, DecisionQualityAssessmentRepository>();
121121
builder.Services.AddScoped<IBoardNodeRepository, BoardNodeRepository>();
122+
builder.Services.AddScoped<IRestrictionTableRepository, RestrictionTableRepository>();
123+
builder.Services.AddScoped<IRestrictionEntryRepository, RestrictionEntryRepository>();
122124

123125
builder.Services.AddScoped<ITableRebuildingService, TableRebuildingService>();
124126
builder.Services.AddScoped<IProjectService, ProjectService>();
@@ -139,6 +141,8 @@ public static void Main(string[] args)
139141
builder.Services.AddScoped<IProjectRoleService, ProjectRoleService>();
140142
builder.Services.AddScoped<IBoardNodeService, BoardNodeService>();
141143
builder.Services.AddHostedService<TableCleanupService>();
144+
builder.Services.AddScoped<IRestrictionTableService, RestrictionTableService>();
145+
builder.Services.AddScoped<IRestrictionEntryService, RestrictionEntryService>();
142146

143147
if (isPublicInstance)
144148
{
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using PrismaApi.Domain.Entities;
2+
using System.Linq.Expressions;
3+
4+
namespace PrismaApi.Application.Interfaces.Repositories;
5+
6+
public interface IRestrictionEntryRepository : ICrudRepository<RestrictionEntry, Guid>
7+
{
8+
Task UpdateRangeAsync(IEnumerable<RestrictionEntry> incomingEntities, Expression<Func<RestrictionEntry, bool>> filterPredicate, CancellationToken ct = default);
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using PrismaApi.Domain.Entities;
2+
using System.Linq.Expressions;
3+
4+
namespace PrismaApi.Application.Interfaces.Repositories;
5+
6+
public interface IRestrictionTableRepository : ICrudRepository<RestrictionTable, Guid>
7+
{
8+
Task UpdateRangeAsync(IEnumerable<RestrictionTable> incomingEntities, Expression<Func<RestrictionTable, bool>> filterPredicate, CancellationToken ct = default);
9+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using PrismaApi.Domain.Dtos;
2+
3+
namespace PrismaApi.Application.Interfaces.Services;
4+
5+
public interface IRestrictionEntryService
6+
{
7+
Task<List<RestrictionEntryOutgoingDto>> CreateAsync(List<RestrictionEntryIncomingDto> dtos, UserOutgoingDto userDto, CancellationToken ct = default);
8+
Task<List<RestrictionEntryOutgoingDto>> UpdateAsync(List<RestrictionEntryIncomingDto> dtos, UserOutgoingDto userDto, CancellationToken ct = default);
9+
Task DeleteAsync(List<Guid> ids, UserOutgoingDto user, CancellationToken ct = default);
10+
Task<List<RestrictionEntryOutgoingDto>> GetAsync(List<Guid> ids, UserOutgoingDto user, CancellationToken ct = default);
11+
Task<List<RestrictionEntryOutgoingDto>> GetAllAsync(UserOutgoingDto user, CancellationToken ct = default);
12+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using PrismaApi.Domain.Dtos;
2+
3+
namespace PrismaApi.Application.Interfaces.Services;
4+
5+
public interface IRestrictionTableService
6+
{
7+
Task<List<RestrictionTableOutgoingDto>> CreateAsync(List<RestrictionTableIncomingDto> dtos, UserOutgoingDto userDto, CancellationToken ct = default);
8+
Task<List<RestrictionTableOutgoingDto>> UpdateAsync(List<RestrictionTableIncomingDto> dtos, UserOutgoingDto userDto, CancellationToken ct = default);
9+
Task DeleteAsync(List<Guid> ids, UserOutgoingDto user, CancellationToken ct = default);
10+
Task<List<RestrictionTableOutgoingDto>> GetAsync(List<Guid> ids, UserOutgoingDto user, CancellationToken ct = default);
11+
Task<List<RestrictionTableOutgoingDto>> GetAllAsync(UserOutgoingDto user, CancellationToken ct = default);
12+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
using PrismaApi.Domain.Dtos;
2+
using PrismaApi.Domain.Entities;
3+
4+
namespace PrismaApi.Application.Mapping;
5+
6+
public static class RestrictionEntryMappingExtensions
7+
{
8+
public static RestrictionEntryOutgoingDto ToOutgoingDto(this RestrictionEntry entity)
9+
{
10+
11+
Guid? parentStateId = entity.ParentOptionId.HasValue ? entity.ParentOptionId : entity.ParentOutcomeId;
12+
Guid? childStateId = entity.ChildOptionId.HasValue ? entity.ChildOptionId : entity.ChildOutcomeId;
13+
bool isParentUncertainty = entity.ParentOutcomeId.HasValue;
14+
bool isChildUncertainty = entity.ChildOutcomeId.HasValue;
15+
return new RestrictionEntryOutgoingDto
16+
{
17+
Id = entity.Id,
18+
ProjectId = entity.ProjectId,
19+
RestrictionTableId = entity.RestrictionTableId,
20+
RestrictionValue = entity.RestrictionValue,
21+
ParentStateId = parentStateId,
22+
IsParentUncertainty = isParentUncertainty,
23+
ChildStateId = childStateId,
24+
IsChildUncertainty = isChildUncertainty,
25+
CreatedAt = entity.CreatedAt,
26+
UpdatedAt = entity.UpdatedAt
27+
};
28+
}
29+
30+
public static List<RestrictionEntryOutgoingDto> ToOutgoingDtos(this IEnumerable<RestrictionEntry> entities)
31+
{
32+
return entities.Select(ToOutgoingDto).ToList();
33+
}
34+
35+
public static RestrictionEntry ToEntity(this RestrictionEntryIncomingDto dto, UserOutgoingDto userDto)
36+
{
37+
Guid? parentOptionId = dto.IsParentUncertainty ? null : dto.ParentStateId;
38+
Guid? parentOutcomeId = dto.IsParentUncertainty ? dto.ParentStateId : null;
39+
Guid? childOptionId = dto.IsChildUncertainty ? null : dto.ChildStateId;
40+
Guid? childOutcomeId = dto.IsChildUncertainty ? dto.ChildStateId : null;
41+
return new RestrictionEntry
42+
{
43+
Id = dto.Id,
44+
ProjectId = dto.ProjectId,
45+
RestrictionTableId = dto.RestrictionTableId,
46+
RestrictionValue = dto.RestrictionValue,
47+
ParentOptionId = parentOptionId,
48+
ParentOutcomeId = parentOutcomeId,
49+
ChildOptionId = childOptionId,
50+
ChildOutcomeId = childOutcomeId,
51+
};
52+
}
53+
public static List<RestrictionEntry> ToEntities(this IEnumerable<RestrictionEntryIncomingDto> dtos, UserOutgoingDto userDto)
54+
{
55+
return dtos.Select(x => ToEntity(x, userDto)).ToList();
56+
}
57+
}

0 commit comments

Comments
 (0)