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,96 @@
|
||||
using SurrealDb.Net;
|
||||
using TarninaHub.Application.Abstractions;
|
||||
using TarninaHub.Application.Dtos;
|
||||
|
||||
namespace TarninaHub.Infrastructure.Persistence;
|
||||
|
||||
public sealed class AdminService : IAdminService
|
||||
{
|
||||
private const int MaxSubmissions = 200;
|
||||
|
||||
private readonly ISurrealDbClient _client;
|
||||
private readonly ISubmissionService _submissions;
|
||||
private readonly IKnowledgeItemService _knowledgeItems;
|
||||
|
||||
public AdminService(
|
||||
ISurrealDbClient client,
|
||||
ISubmissionService submissions,
|
||||
IKnowledgeItemService knowledgeItems)
|
||||
{
|
||||
_client = client;
|
||||
_submissions = submissions;
|
||||
_knowledgeItems = knowledgeItems;
|
||||
}
|
||||
|
||||
public async Task<IReadOnlyList<SubmissionResponse>> ListSubmissionsAsync(
|
||||
string? status,
|
||||
string? challengeId,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var page = await _submissions.ListAsync(
|
||||
viewerId: string.Empty,
|
||||
isStaff: true,
|
||||
status,
|
||||
page: 1,
|
||||
pageSize: MaxSubmissions,
|
||||
cancellationToken);
|
||||
|
||||
return string.IsNullOrWhiteSpace(challengeId)
|
||||
? page.Items
|
||||
: page.Items.Where(item => item.ChallengeId == challengeId).ToList();
|
||||
}
|
||||
|
||||
public async Task<KnowledgeItemResponse?> VerifyKnowledgeItemAsync(
|
||||
string knowledgeItemId,
|
||||
VerifyKnowledgeItemRequest request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var (table, id) = SurrealRecordId.Split(knowledgeItemId);
|
||||
|
||||
var response = await _client.RawQuery(
|
||||
"UPDATE type::record($table, $id) SET published = $published, updated_at = time::now();",
|
||||
new Dictionary<string, object?>
|
||||
{
|
||||
["table"] = table,
|
||||
["id"] = id,
|
||||
["published"] = request.Verified,
|
||||
},
|
||||
cancellationToken);
|
||||
response.EnsureAllOks();
|
||||
|
||||
return await _knowledgeItems.GetAsync(knowledgeItemId, cancellationToken);
|
||||
}
|
||||
|
||||
public async Task<AdminMetricsResponse> GetMetricsAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
var response = await _client.RawQuery(
|
||||
"SELECT count() AS count FROM submission GROUP ALL; " +
|
||||
"SELECT count() AS count FROM problem GROUP ALL; " +
|
||||
"SELECT count() AS count FROM idea GROUP ALL; " +
|
||||
"SELECT count() AS count FROM innovation GROUP ALL; " +
|
||||
"SELECT count() AS count FROM knowledge_item GROUP ALL; " +
|
||||
"SELECT count() AS count FROM user GROUP ALL; " +
|
||||
"SELECT count() AS count FROM grant_call WHERE status = 'open' GROUP ALL; " +
|
||||
"SELECT count() AS count FROM application GROUP ALL;",
|
||||
new Dictionary<string, object?>(),
|
||||
cancellationToken);
|
||||
response.EnsureAllOks();
|
||||
|
||||
return new AdminMetricsResponse(
|
||||
Count(response, 0),
|
||||
Count(response, 1),
|
||||
Count(response, 2),
|
||||
Count(response, 3),
|
||||
Count(response, 4),
|
||||
Count(response, 5),
|
||||
Count(response, 6),
|
||||
Count(response, 7));
|
||||
}
|
||||
|
||||
private static int Count(SurrealDb.Net.Models.Response.SurrealDbResponse response, int index)
|
||||
{
|
||||
var rows = response.GetValue<List<CountRow>>(index) ?? [];
|
||||
|
||||
return rows.Count > 0 ? rows[0].Count : 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user