Implement step 17 modules: threads/messages, notifications with automation (submission.created, idea.created, grant_call.opened), innovation test feedback, admin panel (submissions, verify, metrics, grant call status), Middleman adaptation and partnerships. Split multi-type files into one type per file and replace object-valued dictionaries with string-valued maps in data contracts (migrations 0006/0007).
135 lines
4.3 KiB
C#
135 lines
4.3 KiB
C#
using Asp.Versioning;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using TarninaHub.Application.Abstractions;
|
|
using TarninaHub.Application.Dtos;
|
|
using TarninaHub.Application.Mappings;
|
|
using TarninaHub.Application.Security;
|
|
|
|
namespace TarninaHub.Controllers;
|
|
|
|
[ApiController]
|
|
[ApiVersion("1.0")]
|
|
[Route("api/innovations")]
|
|
[Authorize]
|
|
public class InnovationsController : ControllerBase
|
|
{
|
|
private readonly IInnovationService _innovations;
|
|
private readonly IMatchmakingService _matchmakingService;
|
|
private readonly ITestFeedbackService _testFeedback;
|
|
|
|
public InnovationsController(
|
|
IInnovationService innovations,
|
|
IMatchmakingService matchmakingService,
|
|
ITestFeedbackService testFeedback)
|
|
{
|
|
_innovations = innovations;
|
|
_matchmakingService = matchmakingService;
|
|
_testFeedback = testFeedback;
|
|
}
|
|
|
|
[HttpGet]
|
|
public async Task<ActionResult<IReadOnlyList<InnovationResponse>>> List(
|
|
[FromQuery] string? challengeId,
|
|
[FromQuery] string? stage,
|
|
[FromQuery] string? q,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
var innovations = await _innovations.ListAsync(challengeId, stage, q, !IsStaff(), cancellationToken);
|
|
|
|
return Ok(innovations);
|
|
}
|
|
|
|
[HttpGet("{innovationId}")]
|
|
public async Task<ActionResult<InnovationResponse>> GetById(
|
|
string innovationId,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
var innovation = await _innovations.GetAsync(innovationId, cancellationToken);
|
|
|
|
return innovation is null ? NotFound() : Ok(innovation);
|
|
}
|
|
|
|
[HttpPost]
|
|
[Authorize(Policy = Policies.OperatorOrAdmin)]
|
|
public async Task<ActionResult<InnovationResponse>> Create(
|
|
InnovationRequest request,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
if (!ValidateStage(request.Stage))
|
|
{
|
|
return InvalidStage();
|
|
}
|
|
|
|
var created = await _innovations.CreateAsync(request, cancellationToken);
|
|
|
|
await _matchmakingService.IndexInnovationAsync(created.Id, cancellationToken);
|
|
|
|
return CreatedAtAction(nameof(GetById), new { innovationId = created.Id }, created);
|
|
}
|
|
|
|
[HttpPut("{innovationId}")]
|
|
[Authorize(Policy = Policies.OperatorOrAdmin)]
|
|
public async Task<ActionResult<InnovationResponse>> Update(
|
|
string innovationId,
|
|
InnovationRequest request,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
if (!ValidateStage(request.Stage))
|
|
{
|
|
return InvalidStage();
|
|
}
|
|
|
|
var updated = await _innovations.UpdateAsync(innovationId, request, cancellationToken);
|
|
|
|
if (updated is not null)
|
|
{
|
|
await _matchmakingService.IndexInnovationAsync(updated.Id, cancellationToken);
|
|
}
|
|
|
|
return updated is null ? NotFound() : Ok(updated);
|
|
}
|
|
|
|
[HttpPost("{innovationId}/test-feedback")]
|
|
public async Task<ActionResult<TestFeedbackResponse>> CreateTestFeedback(
|
|
string innovationId,
|
|
CreateTestFeedbackRequest request,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
var userId = User.GetUserId();
|
|
|
|
if (string.IsNullOrWhiteSpace(userId))
|
|
{
|
|
return Unauthorized();
|
|
}
|
|
|
|
var feedback = await _testFeedback.CreateAsync(innovationId, userId, request, cancellationToken);
|
|
|
|
return feedback is null ? NotFound() : StatusCode(StatusCodes.Status201Created, feedback);
|
|
}
|
|
|
|
[HttpGet("{innovationId}/test-feedback")]
|
|
[Authorize(Policy = Policies.ManagerOrAbove)]
|
|
public async Task<ActionResult<IReadOnlyList<TestFeedbackResponse>>> ListTestFeedback(
|
|
string innovationId,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
var feedback = await _testFeedback.ListForInnovationAsync(innovationId, cancellationToken);
|
|
|
|
return Ok(feedback);
|
|
}
|
|
|
|
private bool ValidateStage(string? stage) => InnovationStageWire.IsValid(stage);
|
|
|
|
private ActionResult InvalidStage()
|
|
{
|
|
ModelState.AddModelError(nameof(InnovationRequest.Stage),
|
|
"Stage must be one of: idea, pilot, scaling, service.");
|
|
|
|
return ValidationProblem(ModelState);
|
|
}
|
|
|
|
private bool IsStaff() =>
|
|
User.IsInRole(RoleNames.Operator) || User.IsInRole(RoleNames.Manager) || User.IsInRole(RoleNames.Admin);
|
|
}
|