feat(backend): add communication, tester, admin and middleman modules
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).
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
using Asp.Versioning;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using TarninaHub.Application.Abstractions;
|
||||
using TarninaHub.Application.Dtos;
|
||||
using TarninaHub.Application.Security;
|
||||
|
||||
namespace TarninaHub.Controllers;
|
||||
|
||||
[ApiController]
|
||||
[ApiVersion("1.0")]
|
||||
[Route("api/admin")]
|
||||
[Authorize(Policy = Policies.OperatorOrAdmin)]
|
||||
public class AdminController : ControllerBase
|
||||
{
|
||||
private readonly IAdminService _admin;
|
||||
private readonly IGrantCallService _grantCalls;
|
||||
private readonly IIdeaService _ideas;
|
||||
private readonly INotificationService _notifications;
|
||||
|
||||
public AdminController(
|
||||
IAdminService admin,
|
||||
IGrantCallService grantCalls,
|
||||
IIdeaService ideas,
|
||||
INotificationService notifications)
|
||||
{
|
||||
_admin = admin;
|
||||
_grantCalls = grantCalls;
|
||||
_ideas = ideas;
|
||||
_notifications = notifications;
|
||||
}
|
||||
|
||||
[HttpGet("submissions")]
|
||||
public async Task<ActionResult<IReadOnlyList<SubmissionResponse>>> ListSubmissions(
|
||||
[FromQuery] string? status,
|
||||
[FromQuery] string? challengeId,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var submissions = await _admin.ListSubmissionsAsync(status, challengeId, cancellationToken);
|
||||
|
||||
return Ok(submissions);
|
||||
}
|
||||
|
||||
[HttpPut("knowledge-items/{knowledgeItemId}/verify")]
|
||||
public async Task<ActionResult<KnowledgeItemResponse>> VerifyKnowledgeItem(
|
||||
string knowledgeItemId,
|
||||
VerifyKnowledgeItemRequest request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var item = await _admin.VerifyKnowledgeItemAsync(knowledgeItemId, request, cancellationToken);
|
||||
|
||||
return item is null ? NotFound() : Ok(item);
|
||||
}
|
||||
|
||||
[HttpGet("metrics")]
|
||||
public async Task<ActionResult<AdminMetricsResponse>> Metrics(CancellationToken cancellationToken)
|
||||
{
|
||||
var metrics = await _admin.GetMetricsAsync(cancellationToken);
|
||||
|
||||
return Ok(metrics);
|
||||
}
|
||||
|
||||
[HttpPut("grant-calls/{grantCallId}/status")]
|
||||
public async Task<ActionResult<GrantCallResponse>> UpdateGrantCallStatus(
|
||||
string grantCallId,
|
||||
UpdateGrantCallStatusRequest request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var updated = await _grantCalls.UpdateStatusAsync(grantCallId, request.Status, cancellationToken);
|
||||
|
||||
if (updated is null)
|
||||
{
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (string.Equals(request.Status, "open", StringComparison.Ordinal))
|
||||
{
|
||||
await NotifyIdeaAuthorsAsync(updated, cancellationToken);
|
||||
}
|
||||
|
||||
return Ok(updated);
|
||||
}
|
||||
|
||||
private async Task NotifyIdeaAuthorsAsync(GrantCallResponse call, CancellationToken cancellationToken)
|
||||
{
|
||||
var authorIds = await _ideas.ListDistinctAuthorIdsAsync(cancellationToken);
|
||||
var payload = new Dictionary<string, string?>
|
||||
{
|
||||
["grantCallId"] = call.Id,
|
||||
["name"] = call.Name,
|
||||
};
|
||||
|
||||
foreach (var authorId in authorIds)
|
||||
{
|
||||
await _notifications.NotifyUserAsync(authorId, "grant_call.opened", payload, cancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user