Files
GmRelayBot/src/GmRelay.Shared/Features/Sessions/ListSessions/ListSessionsHandler.cs
T
Toutsu a391c51761
Deploy Telegram Bot / build-and-push (push) Successful in 21m33s
Deploy Telegram Bot / scan-images (push) Successful in 8m55s
Deploy Telegram Bot / deploy (push) Successful in 2m3s
feat(listsessions): add join/leave buttons for players
For non-managers /listsessions now shows player-friendly actions:
-  Записаться <date> when not registered
- ✖️ Выйти <date> when already active
- ✖️ Выйти из ожидания <date> when waitlisted

Extend SessionListItemDto and the shared SQL query with IsUserActive
and IsUserWaitlisted flags so the renderer can choose the right button.
Update tests to cover all three player states.
2026-06-15 15:05:12 +03:00

88 lines
3.8 KiB
C#

using Dapper;
using GmRelay.Shared.Domain;
using GmRelay.Shared.Platform;
using Npgsql;
namespace GmRelay.Shared.Features.Sessions.ListSessions;
public sealed record SessionListItemDto(
Guid Id,
string Title,
DateTime ScheduledAt,
string Status,
int? MaxPlayers,
int PlayerCount,
int WaitlistCount,
bool CanManage,
bool IsUserActive,
bool IsUserWaitlisted);
public sealed record SessionListResult(
IReadOnlyList<SessionListItemDto> Sessions,
bool CanManage);
public sealed class ListSessionsHandler(
NpgsqlDataSource dataSource)
{
public async Task<SessionListResult> HandleAsync(ListSessionsCommand command, CancellationToken cancellationToken)
{
await using var connection = await dataSource.OpenConnectionAsync(cancellationToken);
var sessions = await connection.QueryAsync<SessionListItemDto>(
@"SELECT s.id as Id, s.title as Title, s.scheduled_at as ScheduledAt, s.status as Status, s.max_players as MaxPlayers,
COUNT(sp.id) FILTER (WHERE sp.is_gm = false AND sp.registration_status = @Active) as PlayerCount,
COUNT(sp.id) FILTER (WHERE sp.is_gm = false AND sp.registration_status = @Waitlisted) as WaitlistCount,
EXISTS (
SELECT 1
FROM group_managers gm
JOIN players manager_player ON manager_player.id = gm.player_id
WHERE gm.group_id = s.group_id
AND manager_player.platform = @Platform
AND manager_player.external_user_id = @ExternalUserId
) AS CanManage,
EXISTS (
SELECT 1
FROM session_participants user_sp
JOIN players user_p ON user_p.id = user_sp.player_id
WHERE user_sp.session_id = s.id
AND user_sp.is_gm = false
AND user_sp.registration_status = @Active
AND user_p.platform = @Platform
AND user_p.external_user_id = @ExternalUserId
) AS IsUserActive,
EXISTS (
SELECT 1
FROM session_participants user_sp
JOIN players user_p ON user_p.id = user_sp.player_id
WHERE user_sp.session_id = s.id
AND user_sp.is_gm = false
AND user_sp.registration_status = @Waitlisted
AND user_p.platform = @Platform
AND user_p.external_user_id = @ExternalUserId
) AS IsUserWaitlisted
FROM sessions s
JOIN game_groups g ON s.group_id = g.id
LEFT JOIN session_participants sp ON s.id = sp.session_id
WHERE g.platform = @Platform
AND g.external_group_id = @ExternalGroupId
AND s.status != @Cancelled
AND s.scheduled_at > NOW()
GROUP BY s.id, s.title, s.scheduled_at, s.status, s.max_players, s.group_id
ORDER BY s.scheduled_at ASC",
new
{
Platform = command.Group.Platform.ToString(),
ExternalGroupId = command.Group.ExternalGroupId,
ExternalUserId = command.User.ExternalUserId,
Cancelled = SessionStatus.Cancelled,
Active = ParticipantRegistrationStatus.Active,
Waitlisted = ParticipantRegistrationStatus.Waitlisted
});
var sessionsList = sessions.ToList();
var canManage = sessionsList.Count > 0 && sessionsList.First().CanManage;
return new SessionListResult(sessionsList, canManage);
}
}