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>> 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> 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> 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> 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> 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>> 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); }