Skip to content

Commit 9454c6c

Browse files
committed
feat:Fix Pattern of Service Evaluation
1 parent f8206f1 commit 9454c6c

12 files changed

Lines changed: 87 additions & 49 deletions

File tree

backend/src/CCE.Api.Common/Localization/Resources.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,10 @@ VALIDATION_REQUIRED_FIELD:
162162
ar: "هذا الحقل مطلوب"
163163
en: "This field is required"
164164

165+
REQUIRED_FIELD:
166+
ar: "هذا الحقل مطلوب"
167+
en: "This field is required"
168+
165169
VALIDATION_INVALID_EMAIL:
166170
ar: "البريد الإلكتروني غير صالح"
167171
en: "Invalid email format"
@@ -174,6 +178,10 @@ VALIDATION_MAX_LENGTH:
174178
ar: "القيمة طويلة جدًا"
175179
en: "Value is too long"
176180

181+
MAX_LENGTH:
182+
ar: "القيمة طويلة جدًا"
183+
en: "Value is too long"
184+
177185
VALIDATION_INVALID_FORMAT:
178186
ar: "التنسيق غير صالح"
179187
en: "Invalid format"
@@ -182,6 +190,10 @@ VALIDATION_INVALID_ENUM:
182190
ar: "القيمة المحددة غير صالحة"
183191
en: "Selected value is invalid"
184192

193+
INVALID_ENUM:
194+
ar: "القيمة المحددة غير صالحة"
195+
en: "Selected value is invalid"
196+
185197
# ─── Identity Bare Keys (errors) ───
186198

187199
USER_NOT_FOUND:

backend/src/CCE.Api.Common/Middleware/ExceptionHandlingMiddleware.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,10 @@ private static async Task WriteValidationResultAsync(HttpContext ctx, Validation
9393

9494
var fieldErrors = ex.Errors.Select(e =>
9595
{
96-
var domainKey = e.ErrorMessage;
96+
var domainKey = e.ErrorCode;
9797
var valCode = SystemCodeMap.ToSystemCode(domainKey);
9898
var valMsg = l?.GetString(domainKey) ?? domainKey;
99+
if (valMsg == domainKey) valMsg = e.ErrorMessage;
99100
return new
100101
{
101102
field = ToCamelCase(e.PropertyName),

backend/src/CCE.Api.External/Endpoints/EvaluationEndpoints.cs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,19 @@ public static IEndpointRouteBuilder MapEvaluationEndpoints(this IEndpointRouteBu
2020
IMediator mediator,
2121
CancellationToken ct) =>
2222
{
23+
if (!Enum.IsDefined(typeof(EvaluationRating), body.OverallSatisfaction) || body.OverallSatisfaction == 0)
24+
return Results.BadRequest(new { error = "OverallSatisfaction must be 1-5 (1=Excellent, 2=Satisfied, 3=Neutral, 4=Dissatisfied, 5=Poor)." });
25+
26+
if (!Enum.IsDefined(typeof(EvaluationRating), body.EaseOfUse) || body.EaseOfUse == 0)
27+
return Results.BadRequest(new { error = "EaseOfUse must be 1-5 (1=Excellent, 2=Satisfied, 3=Neutral, 4=Dissatisfied, 5=Poor)." });
28+
29+
if (!Enum.IsDefined(typeof(EvaluationRating), body.ContentSuitability) || body.ContentSuitability == 0)
30+
return Results.BadRequest(new { error = "ContentSuitability must be 1-5 (1=Excellent, 2=Satisfied, 3=Neutral, 4=Dissatisfied, 5=Poor)." });
31+
2332
var cmd = new SubmitEvaluationCommand(
24-
body.OverallSatisfaction,
25-
body.EaseOfUse,
26-
body.ContentSuitability,
33+
(EvaluationRating)body.OverallSatisfaction,
34+
(EvaluationRating)body.EaseOfUse,
35+
(EvaluationRating)body.ContentSuitability,
2736
body.Feedback);
2837
var result = await mediator.Send(cmd, ct).ConfigureAwait(false);
2938
return result.ToHttpResult(StatusCodes.Status201Created);
@@ -36,7 +45,7 @@ public static IEndpointRouteBuilder MapEvaluationEndpoints(this IEndpointRouteBu
3645
}
3746

3847
public sealed record SubmitEvaluationRequest(
39-
EvaluationRating OverallSatisfaction,
40-
EvaluationRating EaseOfUse,
41-
EvaluationRating ContentSuitability,
48+
int OverallSatisfaction,
49+
int EaseOfUse,
50+
int ContentSuitability,
4251
string Feedback);

backend/src/CCE.Api.Internal/Endpoints/EvaluationEndpoints.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using CCE.Api.Common.Extensions;
12
using CCE.Application.Evaluation.Queries.GetAllEvaluations;
23
using CCE.Application.Evaluation.Queries.GetEvaluationById;
34
using CCE.Domain;
@@ -20,7 +21,7 @@ public static IEndpointRouteBuilder MapEvaluationEndpoints(this IEndpointRouteBu
2021
CancellationToken ct) =>
2122
{
2223
var result = await mediator.Send(new GetAllEvaluationsQuery(), ct).ConfigureAwait(false);
23-
return Results.Ok(result);
24+
return result.ToHttpResult();
2425
})
2526
.RequireAuthorization(Permissions.Survey_ReadAll)
2627
.WithName("GetAllEvaluations");
@@ -32,7 +33,7 @@ public static IEndpointRouteBuilder MapEvaluationEndpoints(this IEndpointRouteBu
3233
CancellationToken ct) =>
3334
{
3435
var result = await mediator.Send(new GetEvaluationByIdQuery(id), ct).ConfigureAwait(false);
35-
return result is null ? Results.NotFound() : Results.Ok(result);
36+
return result.ToHttpResult();
3637
})
3738
.RequireAuthorization(Permissions.Survey_ReadAll)
3839
.WithName("GetEvaluationById");

backend/src/CCE.Application/Common/Behaviors/ResponseValidationBehavior.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,10 @@ public async Task<TResponse> Handle(
4747
{
4848
var fieldErrors = failures.Select(f =>
4949
{
50-
var domainKey = f.ErrorMessage;
50+
var domainKey = f.ErrorCode;
5151
var valCode = SystemCodeMap.ToSystemCode(domainKey);
5252
var msg = _l.GetString(domainKey);
53+
if (msg == domainKey) msg = f.ErrorMessage;
5354
return new FieldError(
5455
ToCamelCase(f.PropertyName),
5556
valCode,

backend/src/CCE.Application/Evaluation/Commands/SubmitEvaluation/SubmitEvaluationCommandValidator.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,17 @@ public sealed class SubmitEvaluationCommandValidator : AbstractValidator<SubmitE
77
{
88
public SubmitEvaluationCommandValidator()
99
{
10-
RuleFor(x => x.OverallSatisfaction).IsInEnum().NotEqual(EvaluationRating.None);
11-
RuleFor(x => x.EaseOfUse).IsInEnum().NotEqual(EvaluationRating.None);
12-
RuleFor(x => x.ContentSuitability).IsInEnum().NotEqual(EvaluationRating.None);
13-
RuleFor(x => x.Feedback).NotEmpty().MaximumLength(500);
10+
RuleFor(x => x.OverallSatisfaction)
11+
.IsInEnum().WithErrorCode("INVALID_ENUM")
12+
.NotEqual(EvaluationRating.None).WithErrorCode("REQUIRED_FIELD");
13+
RuleFor(x => x.EaseOfUse)
14+
.IsInEnum().WithErrorCode("INVALID_ENUM")
15+
.NotEqual(EvaluationRating.None).WithErrorCode("REQUIRED_FIELD");
16+
RuleFor(x => x.ContentSuitability)
17+
.IsInEnum().WithErrorCode("INVALID_ENUM")
18+
.NotEqual(EvaluationRating.None).WithErrorCode("REQUIRED_FIELD");
19+
RuleFor(x => x.Feedback)
20+
.NotEmpty().WithErrorCode("REQUIRED_FIELD")
21+
.MaximumLength(500).WithErrorCode("MAX_LENGTH");
1422
}
1523
}

backend/src/CCE.Application/Evaluation/IEvaluationRepository.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,4 @@ namespace CCE.Application.Evaluation;
55
public interface IEvaluationRepository
66
{
77
Task AddAsync(ServiceEvaluation evaluation, CancellationToken ct);
8-
Task<List<ServiceEvaluation>> GetAllAsync(CancellationToken ct);
9-
Task<ServiceEvaluation?> GetByIdAsync(System.Guid id, CancellationToken ct);
108
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
using CCE.Application.Common;
12
using CCE.Application.Evaluation.DTOs;
23
using MediatR;
34

45
namespace CCE.Application.Evaluation.Queries.GetAllEvaluations;
56

6-
public sealed record GetAllEvaluationsQuery : IRequest<List<ServiceEvaluationDto>>;
7+
public sealed record GetAllEvaluationsQuery : IRequest<Response<List<ServiceEvaluationDto>>>;
Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,34 @@
1+
using CCE.Application.Common;
2+
using CCE.Application.Common.Interfaces;
13
using CCE.Application.Evaluation.DTOs;
4+
using CCE.Application.Messages;
25
using MediatR;
6+
using Microsoft.EntityFrameworkCore;
37

48
namespace CCE.Application.Evaluation.Queries.GetAllEvaluations;
59

610
public sealed class GetAllEvaluationsQueryHandler
7-
: IRequestHandler<GetAllEvaluationsQuery, List<ServiceEvaluationDto>>
11+
: IRequestHandler<GetAllEvaluationsQuery, Response<List<ServiceEvaluationDto>>>
812
{
9-
private readonly IEvaluationRepository _repository;
13+
private readonly ICceDbContext _db;
14+
private readonly MessageFactory _msg;
1015

11-
public GetAllEvaluationsQueryHandler(IEvaluationRepository repository)
16+
public GetAllEvaluationsQueryHandler(ICceDbContext db, MessageFactory msg)
1217
{
13-
_repository = repository;
18+
_db = db;
19+
_msg = msg;
1420
}
1521

16-
public async Task<List<ServiceEvaluationDto>> Handle(
22+
public async Task<Response<List<ServiceEvaluationDto>>> Handle(
1723
GetAllEvaluationsQuery request,
1824
CancellationToken cancellationToken)
1925
{
20-
var evaluations = await _repository.GetAllAsync(cancellationToken).ConfigureAwait(false);
26+
var evaluations = await _db.ServiceEvaluations
27+
.OrderByDescending(e => e.CreatedOn)
28+
.ToListAsync(cancellationToken)
29+
.ConfigureAwait(false);
2130

22-
return evaluations.Select(e => new ServiceEvaluationDto(
31+
var dtos = evaluations.Select(e => new ServiceEvaluationDto(
2332
e.Id,
2433
e.OverallSatisfaction,
2534
e.EaseOfUse,
@@ -28,5 +37,7 @@ public async Task<List<ServiceEvaluationDto>> Handle(
2837
e.UserId,
2938
e.CreatedOn,
3039
e.CreatedById)).ToList();
40+
41+
return _msg.Ok(dtos, "ITEMS_LISTED");
3142
}
3243
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1+
using CCE.Application.Common;
12
using CCE.Application.Evaluation.DTOs;
23
using MediatR;
34

45
namespace CCE.Application.Evaluation.Queries.GetEvaluationById;
56

6-
public sealed record GetEvaluationByIdQuery(System.Guid Id) : IRequest<ServiceEvaluationDto?>;
7+
public sealed record GetEvaluationByIdQuery(System.Guid Id) : IRequest<Response<ServiceEvaluationDto>>;

0 commit comments

Comments
 (0)