Files
GameList/Endpoints/ResultsWorkflowService.cs

97 lines
3.4 KiB
C#

using GameList.Contracts;
using GameList.Data;
using GameList.Domain;
using Microsoft.EntityFrameworkCore;
namespace GameList.Endpoints;
internal sealed class ResultsWorkflowService(AppDbContext db)
{
public async Task<ServiceResult<IReadOnlyList<ResultItemDto>>> GetResultsAsync(Guid playerId)
{
var appState = await db.AppState.AsNoTracking().SingleAsync();
if (!appState.ResultsOpen)
return ServiceResult<IReadOnlyList<ResultItemDto>>.Failure(ServiceError.BadRequest("Results are locked until the admin enables them."));
var phase = await EndpointHelpers.GetCurrentPhaseAsync(db, playerId);
if (phase != Phase.Results)
return ServiceResult<IReadOnlyList<ResultItemDto>>.Failure(ServiceError.PhaseMismatch(Phase.Results, phase));
var results = await db
.Suggestions.AsNoTracking()
.Include(s => s.Player)
.Include(s => s.Votes)
.Select(s => new
{
s.Id,
s.Name,
Author = s.Player!.DisplayName,
s.MinPlayers,
s.MaxPlayers,
Total = s.Votes.Sum(v => v.Score),
s.Votes.Count,
Average = s.Votes.Count == 0 ? 0 : s.Votes.Average(v => v.Score),
Votes = s.Votes.Select(v => v.Score).ToList(),
VoterNames = s.Votes
.Select(v => v.Player!.DisplayName ?? v.Player!.Username)
.ToList(),
MyVote = s.Votes
.Where(v => v.PlayerId == playerId)
.Select(v => (int?)v.Score)
.FirstOrDefault(),
s.ScreenshotUrl,
s.YoutubeUrl,
s.GameUrl,
s.Description,
s.Genre,
s.ParentSuggestionId
})
.OrderByDescending(r => r.Average)
.ToListAsync();
var rootIndex = EndpointHelpers.BuildLinkRoots(results.Select(r => (r.Id, r.ParentSuggestionId)));
var nameLookup = results.ToDictionary(r => r.Id, r => r.Name);
IReadOnlyList<ResultItemDto> shaped = results.Select(r =>
{
var linkedIds = EndpointHelpers.LinkedIdsFor(r.Id, rootIndex)
.Where(id => id != r.Id)
.ToList();
var linkedTitles = linkedIds
.Where(nameLookup.ContainsKey)
.Select(id => nameLookup[id])
.ToList();
var voterNames = r.VoterNames
.Where(name => !string.IsNullOrWhiteSpace(name))
.Distinct(StringComparer.OrdinalIgnoreCase)
.OrderBy(name => name, StringComparer.OrdinalIgnoreCase)
.ToList();
return new ResultItemDto(
r.Id,
r.Name,
r.Author,
r.MinPlayers,
r.MaxPlayers,
r.Total,
r.Count,
r.Average,
r.Votes,
voterNames,
r.MyVote,
r.ScreenshotUrl,
r.YoutubeUrl,
r.GameUrl,
r.Description,
r.Genre,
r.ParentSuggestionId,
linkedIds,
linkedTitles
);
}).ToList();
return ServiceResult<IReadOnlyList<ResultItemDto>>.Success(shaped);
}
}