f6d5281af8
PR Checks / test-and-build (pull_request) Successful in 8m46s
Context.Guild in NetCord resolves the Guild object from the gateway client cache (cache.Guilds.GetValueOrDefault(guildId)), not from the interaction JSON payload. After a bot restart, the guild may not yet be cached when the first slash command arrives, causing Context.Guild to be null even though the command is invoked inside a guild channel. This produced "This command can only be used in a guild." Changes: - DiscordListSessionsCommand: use Context.Interaction.GuildId instead of Context.Guild.Id - DiscordNewSessionCommand: use Context.Interaction.GuildId + REST GetGuildAsync/GetGuildUserAsync - DiscordRescheduleCommand: same as above - DiscordSessionInteractionModule: same fix for button interactions (CreateInput) - Add null guard in GetResolvedPermissions for safety - Bump version to 3.0.5 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
89 lines
3.6 KiB
C#
89 lines
3.6 KiB
C#
using GmRelay.DiscordBot.Rendering;
|
|
using NetCord.Rest;
|
|
using NetCord.Services.ApplicationCommands;
|
|
|
|
namespace GmRelay.DiscordBot.Features.Sessions;
|
|
|
|
public class DiscordNewSessionCommand : ApplicationCommandModule<SlashCommandContext>
|
|
{
|
|
private readonly DiscordNewSessionHandler _handler;
|
|
private readonly ILogger<DiscordNewSessionCommand> _logger;
|
|
|
|
public DiscordNewSessionCommand(DiscordNewSessionHandler handler, ILogger<DiscordNewSessionCommand> logger)
|
|
{
|
|
_handler = handler;
|
|
_logger = logger;
|
|
}
|
|
|
|
[SlashCommand("newsession", "Create a new game session")]
|
|
public async Task ExecuteAsync(
|
|
[SlashCommandParameter(Name = "title", Description = "Game title")] string title,
|
|
[SlashCommandParameter(Name = "time", Description = "Session time (YYYY-MM-DD HH:mm or DD.MM.YYYY HH:mm)")] string time,
|
|
[SlashCommandParameter(Name = "seats", Description = "Maximum number of players")] long? seats = null,
|
|
[SlashCommandParameter(Name = "link", Description = "Join link")] string? link = null)
|
|
{
|
|
var guildId = Context.Interaction.GuildId
|
|
?? throw new InvalidOperationException("This command can only be used in a guild.");
|
|
var guild = await Context.Client.Rest.GetGuildAsync(guildId);
|
|
var member = await Context.Client.Rest.GetGuildUserAsync(guildId, Context.User.Id);
|
|
|
|
var timeResult = DiscordNewSessionHandler.ParseTimeInput(time);
|
|
if (!timeResult.IsSuccess)
|
|
{
|
|
await Context.Interaction.SendResponseAsync(
|
|
InteractionCallback.Message($"X {timeResult.Error}"));
|
|
return;
|
|
}
|
|
|
|
var resolvedPermissions = GetResolvedPermissions(guild, member);
|
|
|
|
try
|
|
{
|
|
var view = await _handler.HandleAsync(
|
|
guildId: guild.Id.ToString(),
|
|
channelId: Context.Channel.Id.ToString(),
|
|
userId: Context.User.Id,
|
|
userDisplayName: Context.User.GlobalName ?? Context.User.Username,
|
|
resolvedPermissions: resolvedPermissions,
|
|
guildOwnerId: guild.OwnerId,
|
|
title: title,
|
|
scheduledAt: timeResult.Value,
|
|
maxPlayers: seats is null ? null : (int)seats.Value,
|
|
joinLink: link,
|
|
CancellationToken.None);
|
|
|
|
var (embeds, actionRows) = DiscordSessionBatchRenderer.Render(view);
|
|
await Context.Interaction.SendResponseAsync(
|
|
InteractionCallback.Message(new InteractionMessageProperties()
|
|
.WithContent(":white_check_mark: **Session created successfully!**")
|
|
.WithEmbeds(embeds)
|
|
.WithComponents(actionRows)));
|
|
}
|
|
catch (UnauthorizedAccessException ex)
|
|
{
|
|
await Context.Interaction.SendResponseAsync(
|
|
InteractionCallback.Message($":no_entry: {ex.Message}"));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Failed to create session for user {UserId} in guild {GuildId}", Context.User.Id, guild.Id);
|
|
await Context.Interaction.SendResponseAsync(
|
|
InteractionCallback.Message(":boom: An error occurred while creating the session."));
|
|
}
|
|
}
|
|
|
|
private static ulong GetResolvedPermissions(NetCord.Rest.RestGuild guild, NetCord.GuildUser member)
|
|
{
|
|
if (member is null)
|
|
return 0;
|
|
|
|
ulong resolved = 0;
|
|
foreach (var roleId in member.RoleIds)
|
|
{
|
|
if (guild.Roles.TryGetValue(roleId, out var role))
|
|
resolved |= (ulong)role.Permissions;
|
|
}
|
|
return resolved;
|
|
}
|
|
}
|