-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
2f8ea6d
commit cad4d5b
Showing
10 changed files
with
274 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
153 changes: 153 additions & 0 deletions
153
...board.Api/Features/Feedback/Requests/UpsertFeedbackSubmission/UpsertFeedbackSubmission.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
using System; | ||
using System.Linq; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Gameboard.Api.Common.Services; | ||
using Gameboard.Api.Data; | ||
using Gameboard.Api.Features.Teams; | ||
using Gameboard.Api.Services; | ||
using Gameboard.Api.Structure.MediatR; | ||
using MediatR; | ||
using Microsoft.EntityFrameworkCore; | ||
|
||
namespace Gameboard.Api.Features.Feedback; | ||
|
||
public record UpsertFeedbackSubmissionCommand(UpsertFeedbackSubmissionRequest Request) : IRequest<UpsertFeedbackSubmissionResponse>; | ||
|
||
// TODO: refactor this into separate commands for game/challenge that share an injected validator | ||
internal sealed class UpsertFeedbackSubmissionHandler | ||
( | ||
IActingUserService actingUserService, | ||
FeedbackService feedbackService, | ||
INowService now, | ||
IStore store, | ||
ITeamService teamService, | ||
IValidatorService validatorService | ||
) : IRequestHandler<UpsertFeedbackSubmissionCommand, UpsertFeedbackSubmissionResponse> | ||
{ | ||
private readonly IActingUserService _actingUserService = actingUserService; | ||
private readonly FeedbackService _feedbackService = feedbackService; | ||
private readonly INowService _nowService = now; | ||
private readonly IStore _store = store; | ||
private readonly ITeamService _teamService = teamService; | ||
private readonly IValidatorService _validator = validatorService; | ||
|
||
public async Task<UpsertFeedbackSubmissionResponse> Handle(UpsertFeedbackSubmissionCommand request, CancellationToken cancellationToken) | ||
{ | ||
var actingUserId = _actingUserService.Get()?.Id; | ||
|
||
_validator | ||
.Auth(c => c.RequireAuthentication()) | ||
.AddValidator(ctx => | ||
{ | ||
if (request.Request.AttachedEntity.EntityType != FeedbackSubmissionAttachedEntityType.ChallengeSpec && request.Request.AttachedEntity.EntityType != FeedbackSubmissionAttachedEntityType.Game) | ||
{ | ||
ctx.AddValidationException(new InvalidParameterValue<FeedbackSubmissionAttachedEntityType>(nameof(request.Request.AttachedEntity.EntityType), "Must be either game or challengespec", request.Request.AttachedEntity.EntityType)); | ||
} | ||
}) | ||
.AddValidator(async ctx => | ||
{ | ||
if (!await _teamService.IsOnTeam(request.Request.AttachedEntity.TeamId, _actingUserService.Get().Id)) | ||
{ | ||
ctx.AddValidationException(new UserIsntOnTeam(actingUserId, request.Request.AttachedEntity.TeamId, $"User isn't on the expected team.")); | ||
} | ||
}) | ||
.AddValidator(async ctx => | ||
{ | ||
var template = await _feedbackService.ResolveTemplate(request.Request.AttachedEntity.EntityType, request.Request.AttachedEntity.Id, cancellationToken); | ||
|
||
if (template is null || template.Id != request.Request.FeedbackTemplateId) | ||
{ | ||
ctx.AddValidationException(new InvalidFeedbackTemplateId(request.Request.FeedbackTemplateId, request.Request.AttachedEntity.EntityType, request.Request.AttachedEntity.Id)); | ||
} | ||
|
||
}) | ||
.AddEntityExistsValidator<FeedbackTemplate>(request.Request.FeedbackTemplateId); | ||
|
||
if (request.Request.AttachedEntity.EntityType == FeedbackSubmissionAttachedEntityType.ChallengeSpec) | ||
{ | ||
_validator.AddEntityExistsValidator<Data.ChallengeSpec>(request.Request.AttachedEntity.Id); | ||
|
||
if (request.Request.Id.IsNotEmpty()) | ||
{ | ||
_validator.AddEntityExistsValidator<FeedbackSubmissionChallengeSpec>(request.Request.Id); | ||
} | ||
} | ||
else | ||
{ | ||
_validator.AddEntityExistsValidator<Data.Game>(request.Request.AttachedEntity.Id); | ||
|
||
if (request.Request.Id.IsNotEmpty()) | ||
{ | ||
_validator.AddEntityExistsValidator<FeedbackSubmissionGame>(request.Request.Id); | ||
} | ||
} | ||
|
||
await _validator.Validate(cancellationToken); | ||
|
||
// if updating, update | ||
if (request.Request.Id.IsNotEmpty()) | ||
{ | ||
if (request.Request.AttachedEntity.EntityType == FeedbackSubmissionAttachedEntityType.ChallengeSpec) | ||
{ | ||
var existingSubmission = await _store | ||
.WithNoTracking<FeedbackSubmissionChallengeSpec>() | ||
.Where(s => s.Id == request.Request.Id) | ||
.SingleAsync(cancellationToken); | ||
|
||
existingSubmission.WhenEdited = _nowService.Get(); | ||
existingSubmission.Responses = [.. request.Request.Responses]; | ||
await _store.SaveUpdate(existingSubmission, cancellationToken); | ||
return new UpsertFeedbackSubmissionResponse { Submission = existingSubmission }; | ||
} | ||
else if (request.Request.AttachedEntity.EntityType == FeedbackSubmissionAttachedEntityType.Game) | ||
{ | ||
var existingSubmission = await _store | ||
.WithNoTracking<FeedbackSubmissionGame>() | ||
.Where(s => s.Id == request.Request.Id) | ||
.SingleAsync(cancellationToken); | ||
|
||
existingSubmission.WhenEdited = _nowService.Get(); | ||
existingSubmission.Responses = [.. request.Request.Responses]; | ||
await _store.SaveUpdate(existingSubmission, cancellationToken); | ||
return new UpsertFeedbackSubmissionResponse { Submission = existingSubmission }; | ||
} | ||
} | ||
else | ||
{ | ||
// if creating, create | ||
if (request.Request.AttachedEntity.EntityType == FeedbackSubmissionAttachedEntityType.ChallengeSpec) | ||
{ | ||
var result = await _store | ||
.Create<FeedbackSubmissionChallengeSpec>(new() | ||
{ | ||
ChallengeSpecId = request.Request.AttachedEntity.Id, | ||
FeedbackTemplateId = request.Request.FeedbackTemplateId, | ||
Responses = [.. request.Request.Responses], | ||
TeamId = request.Request.AttachedEntity.TeamId, | ||
UserId = actingUserId, | ||
WhenSubmitted = _nowService.Get(), | ||
}, cancellationToken); | ||
|
||
return new UpsertFeedbackSubmissionResponse { Submission = result }; | ||
} | ||
else | ||
{ | ||
var result = await _store | ||
.Create<FeedbackSubmissionGame>(new() | ||
{ | ||
GameId = request.Request.AttachedEntity.Id, | ||
FeedbackTemplateId = request.Request.FeedbackTemplateId, | ||
Responses = [.. request.Request.Responses], | ||
TeamId = request.Request.AttachedEntity.TeamId, | ||
UserId = actingUserId, | ||
WhenSubmitted = _nowService.Get(), | ||
}, cancellationToken); | ||
|
||
return new UpsertFeedbackSubmissionResponse { Submission = result }; | ||
} | ||
} | ||
|
||
throw new NotImplementedException(); | ||
} | ||
} |
34 changes: 34 additions & 0 deletions
34
...Api/Features/Feedback/Requests/UpsertFeedbackSubmission/UpsertFeedbackSubmissionModels.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
using System.Collections.Generic; | ||
using System.ComponentModel; | ||
using System.Text.Json.Serialization; | ||
using Gameboard.Api.Data; | ||
using Gameboard.Api.Structure; | ||
|
||
namespace Gameboard.Api.Features.Feedback; | ||
|
||
public sealed class InvalidFeedbackTemplateId : GameboardValidationException | ||
{ | ||
public InvalidFeedbackTemplateId(string id, FeedbackSubmissionAttachedEntityType type, string entityId) | ||
: base($"The template id {id} was not valid for {type} {entityId}") { } | ||
} | ||
|
||
public sealed class UpsertFeedbackSubmissionRequest | ||
{ | ||
public string Id { get; set; } | ||
public required UpsertFeedbackSubmissionRequestAttachedEntity AttachedEntity { get; set; } | ||
public required string FeedbackTemplateId { get; set; } | ||
public IEnumerable<QuestionSubmission> Responses { get; set; } | ||
} | ||
|
||
public sealed class UpsertFeedbackSubmissionRequestAttachedEntity | ||
{ | ||
public required string Id { get; set; } | ||
// [TypeConverter(typeof(JsonStringEnumConverter<FeedbackSubmissionAttachedEntityType>))] | ||
public required FeedbackSubmissionAttachedEntityType EntityType { get; set; } | ||
public required string TeamId { get; set; } | ||
} | ||
|
||
public sealed class UpsertFeedbackSubmissionResponse | ||
{ | ||
public required FeedbackSubmission Submission { get; set; } | ||
} |
Oops, something went wrong.