Compare commits
3 Commits
79d9f16a8b
...
ced9d15083
| Author | SHA1 | Date | |
|---|---|---|---|
| ced9d15083 | |||
| a3051ed060 | |||
| bd52e37454 |
@@ -18,7 +18,7 @@ public class ActivityFormatter
|
||||
_options = options.Value;
|
||||
}
|
||||
|
||||
public static string FormatActivityName(ActivityName activityName)
|
||||
public string FormatActivityName(ActivityName activityName)
|
||||
{
|
||||
return activityName switch
|
||||
{
|
||||
@@ -38,7 +38,7 @@ public class ActivityFormatter
|
||||
};
|
||||
}
|
||||
|
||||
public static string GetActivityBanner(ActivityName activityName)
|
||||
public string GetActivityBanner(ActivityName activityName)
|
||||
{
|
||||
return CdnUtils.GetAsset($"banner/{GetActivityCode(activityName)}.webp");
|
||||
}
|
||||
@@ -66,9 +66,15 @@ public class ActivityFormatter
|
||||
$"{FormatActivityName(activity.Name)} ({players.Count}/{activity.MaxPlayers})"
|
||||
};
|
||||
|
||||
string description = string.IsNullOrWhiteSpace(activity.Description)
|
||||
? $"Rejoignez l'activité de {MentionUtils.MentionUser(activity.CreatorDiscordId)}"
|
||||
: activity.Description;
|
||||
var descriptionBuilder = new StringBuilder();
|
||||
descriptionBuilder.AppendLine(
|
||||
string.IsNullOrWhiteSpace(activity.Description)
|
||||
? $"Rejoignez l'activité de {MentionUtils.MentionUser(activity.CreatorUserId)}"
|
||||
: activity.Description
|
||||
);
|
||||
|
||||
descriptionBuilder.AppendLine();
|
||||
descriptionBuilder.Append($"**[Fil associé]({ChannelUtils.GetChannelLink(activity.GuildId, activity.ThreadId)})**");
|
||||
|
||||
string bannerUrl = GetActivityBanner(activity.Name);
|
||||
|
||||
@@ -77,7 +83,7 @@ public class ActivityFormatter
|
||||
var builder = new EmbedBuilder()
|
||||
.WithColor(color)
|
||||
.WithTitle(title)
|
||||
.WithDescription(description)
|
||||
.WithDescription(descriptionBuilder.ToString())
|
||||
.WithImageUrl(bannerUrl)
|
||||
.WithFields(playersField);
|
||||
|
||||
@@ -90,7 +96,7 @@ public class ActivityFormatter
|
||||
return builder;
|
||||
}
|
||||
|
||||
private static string GetActivityCode(ActivityName activityName) => activityName switch
|
||||
private string GetActivityCode(ActivityName activityName) => activityName switch
|
||||
{
|
||||
ActivityName.Abyss => "VA",
|
||||
ActivityName.OriginsOfWar => "OOW",
|
||||
|
||||
@@ -24,6 +24,8 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
|
||||
private readonly ActivitiesRepository _activitiesRepository;
|
||||
private readonly ActivityFormatter _activityFormatter;
|
||||
|
||||
private SocketGuildUser User => (SocketGuildUser) Context.User;
|
||||
|
||||
public ActivityModule(ILogger<ActivityModule> logger, IOptions<ActivityOptions> options, ActivityHelper activityHelper, ActivitiesRepository activitiesRepository, ActivityFormatter activityFormatter)
|
||||
{
|
||||
_logger = logger;
|
||||
@@ -33,6 +35,7 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
|
||||
_options = options.Value;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
[RequireOwner]
|
||||
[SlashCommand("setup-info", "Display activity setup info")]
|
||||
public async Task SetupInfo()
|
||||
@@ -44,6 +47,9 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
|
||||
- Healer: {MentionUtils.MentionRole(_options.SupportRoleId)} {_options.SupportEmote.ToEmote()}
|
||||
""");
|
||||
}
|
||||
#endif
|
||||
|
||||
#region activities
|
||||
|
||||
[SlashCommand("abime-néant", "Créer un groupe pour l'Abîme du Néant")]
|
||||
[Alias("abime", "abyss")]
|
||||
@@ -128,16 +134,20 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
|
||||
await CreateActivity(ActivityName.MirroriaRace, description, areRolesEnabled: false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private async Task CreateActivity(ActivityName activityName, string description, bool areRolesEnabled = true, uint? maxPlayers = null, uint? stage = null, InterstellarColor? interstellarColor = null)
|
||||
{
|
||||
var user = (SocketGuildUser)Context.User;
|
||||
_logger.LogTrace("{User} is creating activity {Activity}", user.DisplayName, activityName);
|
||||
_logger.LogTrace("{User} is creating activity {Activity}", User.DisplayName, activityName);
|
||||
|
||||
// Activities are identified using their original message id
|
||||
await RespondAsync("> *Création de l'activité en cours...*");
|
||||
await RespondAsync("> ***Création de l'activité en cours...***");
|
||||
|
||||
var response = await GetOriginalResponseAsync();
|
||||
|
||||
// Create associated thread
|
||||
var threadId = await CreateThread(activityName, User.DisplayName);
|
||||
|
||||
var activityType = ActivityHelper.ActivityNameToType(activityName);
|
||||
maxPlayers ??= ActivityHelper.ActivityTypeToMaxPlayers(activityType);
|
||||
Activity activity;
|
||||
@@ -146,9 +156,12 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
|
||||
{
|
||||
activity = new StagedActivity
|
||||
{
|
||||
ActivityId = response.Id,
|
||||
CreatorDiscordId = Context.User.Id,
|
||||
CreatorDiscordName = ((SocketGuildUser) Context.User).DisplayName,
|
||||
MessageId = response.Id,
|
||||
ChannelId = Context.Channel.Id,
|
||||
GuildId = Context.Guild.Id,
|
||||
ThreadId = threadId,
|
||||
CreatorUserId = Context.User.Id,
|
||||
CreatorDisplayName = ((SocketGuildUser) Context.User).DisplayName,
|
||||
Description = description,
|
||||
Type = activityType,
|
||||
Name = activityName,
|
||||
@@ -161,9 +174,12 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
|
||||
{
|
||||
activity = new InterstellarActivity
|
||||
{
|
||||
ActivityId = response.Id,
|
||||
CreatorDiscordId = Context.User.Id,
|
||||
CreatorDiscordName = ((SocketGuildUser) Context.User).DisplayName,
|
||||
MessageId = response.Id,
|
||||
ChannelId = Context.Channel.Id,
|
||||
GuildId = Context.Guild.Id,
|
||||
ThreadId = threadId,
|
||||
CreatorUserId = Context.User.Id,
|
||||
CreatorDisplayName = ((SocketGuildUser) Context.User).DisplayName,
|
||||
Description = description,
|
||||
Type = activityType,
|
||||
Name = activityName,
|
||||
@@ -176,13 +192,16 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
|
||||
{
|
||||
activity = new Activity
|
||||
{
|
||||
ActivityId = response.Id,
|
||||
CreatorDiscordId = Context.User.Id,
|
||||
CreatorDiscordName = ((SocketGuildUser) Context.User).DisplayName,
|
||||
MessageId = response.Id,
|
||||
ChannelId = Context.Channel.Id,
|
||||
GuildId = Context.Guild.Id,
|
||||
ThreadId = threadId,
|
||||
CreatorUserId = Context.User.Id,
|
||||
CreatorDisplayName = ((SocketGuildUser) Context.User).DisplayName,
|
||||
Description = description,
|
||||
Type = activityType,
|
||||
Name = activityName,
|
||||
AreRolesEnabled = true,
|
||||
AreRolesEnabled = areRolesEnabled,
|
||||
MaxPlayers = (uint) maxPlayers
|
||||
};
|
||||
}
|
||||
@@ -191,24 +210,14 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
|
||||
await _activitiesRepository.AddActivity(activity);
|
||||
|
||||
// Add creator to activity
|
||||
var rolePlayer = areRolesEnabled ? new ActivityRolePlayer
|
||||
{
|
||||
Activity = activity,
|
||||
DiscordId = user.Id,
|
||||
Name = user.DisplayName,
|
||||
Roles = _activityHelper.GetPlayerRoles(user.Roles)
|
||||
} : new ActivityPlayer
|
||||
{
|
||||
Activity = activity,
|
||||
DiscordId = user.Id,
|
||||
Name = user.DisplayName
|
||||
};
|
||||
var rolePlayer = CreateActivityPlayer(activity, User, areRolesEnabled);
|
||||
|
||||
activity.ActivityPlayers.Add(rolePlayer);
|
||||
|
||||
await _activitiesRepository.SaveChanges();
|
||||
|
||||
// Add components
|
||||
var components = ActivityComponents(activity.ActivityId);
|
||||
var components = ActivityComponents(activity.MessageId);
|
||||
|
||||
await ModifyOriginalResponseAsync(m =>
|
||||
{
|
||||
@@ -218,58 +227,136 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
|
||||
});
|
||||
}
|
||||
|
||||
[ComponentInteraction("activity join:*", ignoreGroupNames: true)]
|
||||
private async Task JoinActivity(ulong activityId)
|
||||
private ActivityPlayer CreateActivityPlayer(Activity activity, SocketGuildUser user, bool areRolesEnabled)
|
||||
{
|
||||
var user = (SocketGuildUser)Context.User;
|
||||
return areRolesEnabled ? new ActivityRolePlayer
|
||||
{
|
||||
Activity = activity,
|
||||
UserId = user.Id,
|
||||
Name = user.DisplayName,
|
||||
Roles = _activityHelper.GetPlayerRoles(user.Roles)
|
||||
} : new ActivityPlayer
|
||||
{
|
||||
Activity = activity,
|
||||
UserId = user.Id,
|
||||
Name = user.DisplayName
|
||||
};
|
||||
}
|
||||
|
||||
[ComponentInteraction("activity join:*", ignoreGroupNames: true)]
|
||||
public async Task JoinActivity(ulong messageId)
|
||||
{
|
||||
// Check if activity exists
|
||||
if (await _activitiesRepository.FindActivity(activityId) is not { } activity)
|
||||
if (await _activitiesRepository.FindActivity(Context.Guild.Id, Context.Channel.Id, messageId) is not { } activity)
|
||||
{
|
||||
await RespondAsync(
|
||||
ephemeral: true,
|
||||
embed: EmbedUtils.ErrorEmbed("Cette activité n'existe plus").Build()
|
||||
embed: EmbedUtils.ErrorEmbed("Cette activité **n'existe plus**").Build()
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// If player is already registered
|
||||
if (await _activitiesRepository.FindActivityPlayer(activityId, user.Id) is not null)
|
||||
if (!await AddUserToActivity(activity, User, self: true))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await RespondAsync(
|
||||
ephemeral: true,
|
||||
embed: EmbedUtils.SuccessEmbed("Vous avez bien été **inscrit** pour cette activité").Build()
|
||||
);
|
||||
}
|
||||
|
||||
[ComponentInteraction("activity leave:*", ignoreGroupNames: true)]
|
||||
public async Task LeaveActivity(ulong messageId)
|
||||
{
|
||||
// Check if activity exists
|
||||
if (await _activitiesRepository.FindActivity(Context.Guild.Id, Context.Channel.Id, messageId) is not { } activity)
|
||||
{
|
||||
await RespondAsync(
|
||||
ephemeral: true,
|
||||
embed: EmbedUtils.ErrorEmbed("Vous êtes déjà inscrit à cette activité").Build()
|
||||
embed: EmbedUtils.ErrorEmbed("Cette activité **n'existe plus**").Build()
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!await RemovePlayerFromActivity(activity, User, self: true))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await RespondAsync(
|
||||
ephemeral: true,
|
||||
embed: EmbedUtils.SuccessEmbed("Vous avez bien été **désinscrit** pour cette activité").Build()
|
||||
);
|
||||
}
|
||||
|
||||
[ComponentInteraction("activity delete:*", ignoreGroupNames: true)]
|
||||
public async Task DeleteActivity(ulong messageId)
|
||||
{
|
||||
// Check if activity exists
|
||||
if (await _activitiesRepository.FindActivity(Context.Guild.Id, Context.Channel.Id, messageId) is not { } activity)
|
||||
{
|
||||
await RespondAsync(
|
||||
ephemeral: true,
|
||||
embed: EmbedUtils.ErrorEmbed("Cette activité **n'existe plus**").Build()
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if user has permission to delete this activity
|
||||
if (User.Id != activity.CreatorUserId && !User.GetPermissions((IGuildChannel) Context.Channel).ManageMessages)
|
||||
{
|
||||
await RespondAsync(
|
||||
ephemeral: true,
|
||||
embed: EmbedUtils.ErrorEmbed("Vous n'avez **pas la permission** d'exécuter cette action").Build()
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove from database
|
||||
_activitiesRepository.DeleteActivity(activity);
|
||||
await _activitiesRepository.SaveChanges();
|
||||
|
||||
// Remove thread
|
||||
await Context.Guild.GetThreadChannel(activity.ThreadId).DeleteAsync();
|
||||
|
||||
// Delete response
|
||||
await Context.Channel.DeleteMessageAsync(messageId);
|
||||
}
|
||||
|
||||
private async Task<bool> AddUserToActivity(Activity activity, SocketGuildUser user, bool self)
|
||||
{
|
||||
// If player is already registered
|
||||
if (await _activitiesRepository.FindActivityPlayer(activity.GuildId, activity.ChannelId, activity.MessageId, user.Id) is not
|
||||
null)
|
||||
{
|
||||
await RespondAsync(
|
||||
ephemeral: true,
|
||||
embed: EmbedUtils.ErrorEmbed(self ? "Vous êtes **déjà inscrit** à cette activité" : $"{user.DisplayName} est **déjà inscrit** à cette activité").Build()
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if activity is full
|
||||
if (await _activitiesRepository.ActivityPlayerCount(activity) >= activity.MaxPlayers)
|
||||
{
|
||||
await RespondAsync(
|
||||
ephemeral: true,
|
||||
embed: EmbedUtils.ErrorEmbed("L'activité est complète").Build()
|
||||
embed: EmbedUtils.ErrorEmbed("L'activité est **complète**").Build()
|
||||
);
|
||||
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
_logger.LogTrace("Player {Player} joined activity {Id}", user.DisplayName, activityId);
|
||||
_logger.LogTrace("Player {Player} joined activity {Id}", user.DisplayName, activity.MessageId);
|
||||
|
||||
var activityPlayer = activity.AreRolesEnabled ? new ActivityRolePlayer
|
||||
{
|
||||
Activity = activity,
|
||||
DiscordId = user.Id,
|
||||
Name = user.DisplayName,
|
||||
Roles = _activityHelper.GetPlayerRoles(user.Roles)
|
||||
} : new ActivityPlayer
|
||||
{
|
||||
Activity = activity,
|
||||
DiscordId = user.Id,
|
||||
Name = user.DisplayName
|
||||
};
|
||||
var activityPlayer = CreateActivityPlayer(activity, user, activity.AreRolesEnabled);
|
||||
|
||||
// Add player to activity
|
||||
activity.ActivityPlayers.Add(activityPlayer);
|
||||
@@ -278,40 +365,42 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
|
||||
// Update activity embed
|
||||
await UpdateActivityEmbed(activity, ActivityUpdateReason.PlayerJoin);
|
||||
|
||||
await RespondAsync(
|
||||
ephemeral: true,
|
||||
embed: EmbedUtils.SuccessEmbed("Vous avez bien été inscrit pour cette activité").Build()
|
||||
);
|
||||
// Send join message to thread and add user to thread
|
||||
var thread = Context.Guild.GetThreadChannel(activity.ThreadId);
|
||||
|
||||
await thread.AddUserAsync(user);
|
||||
|
||||
string embedContent = $"**{user.DisplayName}** a été **ajouté** à l'activité";
|
||||
if (self)
|
||||
{
|
||||
await thread.SendMessageAsync(
|
||||
embed: EmbedUtils.InfoEmbed(embedContent).Build()
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
await RespondAsync(
|
||||
embed: EmbedUtils.InfoEmbed(embedContent).Build()
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[ComponentInteraction("activity leave:*", ignoreGroupNames: true)]
|
||||
private async Task LeaveActivity(ulong activityId)
|
||||
private async Task<bool> RemovePlayerFromActivity(Activity activity, SocketGuildUser user, bool self)
|
||||
{
|
||||
var user = (IGuildUser)Context.User;
|
||||
|
||||
// Check if activity exists
|
||||
if (await _activitiesRepository.FindActivity(activityId) is not { } activity)
|
||||
{
|
||||
await RespondAsync(
|
||||
ephemeral: true,
|
||||
embed: EmbedUtils.ErrorEmbed("Cette activité n'existe plus").Build()
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if player is in activity
|
||||
if (await _activitiesRepository.FindActivityPlayer(activityId, user.Id) is not { } activityPlayer)
|
||||
if (await _activitiesRepository.FindActivityPlayer(activity.GuildId, activity.ChannelId, activity.MessageId, user.Id) is not { } activityPlayer)
|
||||
{
|
||||
await RespondAsync(
|
||||
ephemeral: true,
|
||||
embed: EmbedUtils.ErrorEmbed("Vous n'êtes pas inscrit à cette activité").Build()
|
||||
embed: EmbedUtils.ErrorEmbed(self ? "Vous n'êtes **pas inscrit** à cette activité" : $"{user.DisplayName} n'est **pas inscrit** à cette activité").Build()
|
||||
);
|
||||
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
_logger.LogTrace("Player {Player} left activity {Id}", user.DisplayName, activityId);
|
||||
_logger.LogTrace("Player {Player} left activity {Id}", user.DisplayName, activity.MessageId);
|
||||
|
||||
activity.ActivityPlayers.Remove(activityPlayer);
|
||||
await _activitiesRepository.SaveChanges();
|
||||
@@ -319,18 +408,32 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
|
||||
// Update activity embed
|
||||
await UpdateActivityEmbed(activity, ActivityUpdateReason.PlayerLeave);
|
||||
|
||||
await RespondAsync(
|
||||
ephemeral: true,
|
||||
embed: EmbedUtils.SuccessEmbed("Vous avez bien été désinscrit pour cette activité").Build()
|
||||
);
|
||||
// Send leave message to thread and remove user from thread
|
||||
var thread = Context.Guild.GetThreadChannel(activity.ThreadId);
|
||||
|
||||
await thread.RemoveUserAsync(user);
|
||||
|
||||
string embedContent = $"{user.DisplayName} a été **enlevé** de l'activité";
|
||||
if (self)
|
||||
{
|
||||
await thread.SendMessageAsync(
|
||||
embed: EmbedUtils.InfoEmbed(embedContent).Build()
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
await RespondAsync(
|
||||
embed: EmbedUtils.InfoEmbed(embedContent).Build()
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private async Task UpdateActivityEmbed(Activity activity, ActivityUpdateReason updateReason)
|
||||
{
|
||||
// Get channel
|
||||
var channel = await Context.Interaction.GetChannelAsync();
|
||||
|
||||
if (channel is null)
|
||||
if (Context.Guild.GetChannel(activity.ChannelId) is not SocketTextChannel channel)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -338,7 +441,7 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
|
||||
// Fetch players
|
||||
var players = await _activitiesRepository.LoadActivityPlayers(activity);
|
||||
|
||||
await channel.ModifyMessageAsync(activity.ActivityId, properties =>
|
||||
await channel.ModifyMessageAsync(activity.MessageId, properties =>
|
||||
{
|
||||
properties.Embed = _activityFormatter.ActivityEmbed(activity, players).Build();
|
||||
|
||||
@@ -346,8 +449,8 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
|
||||
var isActivityFull = players.Count >= activity.MaxPlayers;
|
||||
properties.Components = updateReason switch
|
||||
{
|
||||
ActivityUpdateReason.PlayerJoin when isActivityFull => ActivityComponents(activity.ActivityId, disabled: true).Build(),
|
||||
ActivityUpdateReason.PlayerLeave when !isActivityFull => ActivityComponents(activity.ActivityId, disabled: false).Build(),
|
||||
ActivityUpdateReason.PlayerJoin when isActivityFull => ActivityComponents(activity.MessageId, disabled: true).Build(),
|
||||
ActivityUpdateReason.PlayerLeave when !isActivityFull => ActivityComponents(activity.MessageId, disabled: false).Build(),
|
||||
_ => Optional<MessageComponent>.Unspecified
|
||||
};
|
||||
});
|
||||
@@ -358,18 +461,24 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
|
||||
return new ComponentBuilder()
|
||||
.AddRow(new ActionRowBuilder()
|
||||
.WithButton(new ButtonBuilder()
|
||||
.WithLabel("Rejoindre l'activité")
|
||||
.WithLabel("Rejoindre")
|
||||
.WithCustomId($"activity join:{activityId}")
|
||||
.WithEmote(":white_check_mark:".ToEmote())
|
||||
.WithStyle(ButtonStyle.Primary)
|
||||
.WithDisabled(disabled)
|
||||
)
|
||||
.WithButton(new ButtonBuilder()
|
||||
.WithLabel("Se désinscrire de l'activité")
|
||||
.WithLabel("Se désinscrire")
|
||||
.WithCustomId($"activity leave:{activityId}")
|
||||
.WithEmote(":x:".ToEmote())
|
||||
.WithStyle(ButtonStyle.Secondary)
|
||||
)
|
||||
.WithButton(new ButtonBuilder()
|
||||
.WithLabel("Supprimer")
|
||||
.WithCustomId($"activity delete:{activityId}")
|
||||
.WithEmote(":wastebasket:".ToEmote())
|
||||
.WithStyle(ButtonStyle.Danger)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,14 +13,14 @@ public partial class ActivityModule
|
||||
{
|
||||
if (message is IUserMessage userMessage && userMessage.Author.IsBot)
|
||||
{
|
||||
if (await _activitiesRepository.FindActivity(message.Id) is { } activity)
|
||||
if (await _activitiesRepository.FindActivity(Context.Guild.Id, Context.Channel.Id, message.Id) is { } activity)
|
||||
{
|
||||
// Generate random player
|
||||
var player = new ActivityRolePlayer
|
||||
{
|
||||
Activity = activity,
|
||||
Name = $"Player{Random.Shared.Next(1, 100)}",
|
||||
DiscordId = (ulong) Random.Shared.NextInt64(),
|
||||
UserId = (ulong) Random.Shared.NextInt64(),
|
||||
Roles = (PlayerRoles) Random.Shared.Next((int) (PlayerRoles.Dps | PlayerRoles.Helper |
|
||||
PlayerRoles.Support | PlayerRoles.Tank) + 1)
|
||||
};
|
||||
|
||||
115
Cocotte/Modules/Activities/ActivityModuleThread.cs
Normal file
115
Cocotte/Modules/Activities/ActivityModuleThread.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text;
|
||||
using Cocotte.Modules.Activities.Models;
|
||||
using Cocotte.Utils;
|
||||
using Discord;
|
||||
using Discord.Interactions;
|
||||
using Discord.WebSocket;
|
||||
|
||||
namespace Cocotte.Modules.Activities;
|
||||
|
||||
public partial class ActivityModule
|
||||
{
|
||||
private string GetStartMessage(ActivityName activityName, string creatorName) =>
|
||||
$"""
|
||||
**― Bienvenue ―**
|
||||
Bienvenue sur le thread lié à l'activité **{_activityFormatter.FormatActivityName(activityName)}** de **{creatorName}**
|
||||
|
||||
Ici, vous pouvez **discuter** de l'activité, mais aussi **gérer** cette activité à l'aide de diverses **commandes**.
|
||||
|
||||
**― Commandes ―**
|
||||
- `/activite ajouter <joueur>` - **Ajoute un joueur** à cette activité
|
||||
- `/activite supprimer <joueur>` - **Supprime un joueur** de cette activité
|
||||
- `/activite ping` - **Ping les joueurs** inscrits à cette activité
|
||||
- `/activite description` - **Modifie la description** de l'activité
|
||||
- `/activite etage` - Pour l'abîme du néant et l'origine de la guerre, **modifie l'étage** de l'activité
|
||||
""";
|
||||
|
||||
private async Task<ulong> CreateThread(ActivityName activityName, string creatorName)
|
||||
{
|
||||
var channel = (SocketTextChannel) Context.Channel;
|
||||
var message = await GetOriginalResponseAsync();
|
||||
|
||||
// Create thread
|
||||
var thread = await channel.CreateThreadAsync(
|
||||
$"{_activityFormatter.FormatActivityName(activityName)} - {creatorName}", ThreadType.PublicThread,
|
||||
ThreadArchiveDuration.OneHour,
|
||||
message, true
|
||||
);
|
||||
|
||||
// Send management message
|
||||
await thread.SendMessageAsync(GetStartMessage(activityName, creatorName));
|
||||
|
||||
// Add activity creator
|
||||
await thread.AddUserAsync((IGuildUser) Context.User);
|
||||
|
||||
return thread.Id;
|
||||
}
|
||||
|
||||
[SlashCommand("ajouter", "Ajouter un joueur à cette activité")]
|
||||
public async Task ThreadAddPlayer(IUser user)
|
||||
{
|
||||
// Get activity linked to this thread
|
||||
var activity = _activitiesRepository.FindActivityByThreadId(Context.Channel.Id);
|
||||
|
||||
if (!await CheckCommandInThread(activity) || activity is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await AddUserToActivity(activity, (SocketGuildUser) user, self: false);
|
||||
}
|
||||
|
||||
[SlashCommand("enlever", "Enlever un joueur de cette activité")]
|
||||
public async Task ThreadRemovePlayer(IUser user)
|
||||
{
|
||||
// Get activity linked to this thread
|
||||
var activity = _activitiesRepository.FindActivityByThreadId(Context.Channel.Id);
|
||||
|
||||
if (!await CheckCommandInThread(activity) || activity is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await RemovePlayerFromActivity(activity, (SocketGuildUser) user, self: false);
|
||||
}
|
||||
|
||||
[SlashCommand("ping", "Ping les joueurs inscrits à cette activité")]
|
||||
public async Task ThreadPingPlayers(string message = "**Appel de groupe**")
|
||||
{
|
||||
// Get activity linked to this thread
|
||||
var activity = _activitiesRepository.FindActivityByThreadId(Context.Channel.Id);
|
||||
|
||||
if (!await CheckCommandInThread(activity) || activity is null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Get user ids
|
||||
var userIds = await _activitiesRepository.GetActivityPlayerIds(activity);
|
||||
|
||||
|
||||
// Generate message
|
||||
var pingMessageBuilder = new StringBuilder(message);
|
||||
pingMessageBuilder.AppendLine("\n");
|
||||
pingMessageBuilder.Append(string.Join(", ", userIds.Select(id => MentionUtils.MentionUser(id))));
|
||||
|
||||
await RespondAsync(pingMessageBuilder.ToString());
|
||||
}
|
||||
|
||||
private async Task<bool> CheckCommandInThread(Activity? activity)
|
||||
{
|
||||
// Check if activity is not null (means we are in a valid thread)
|
||||
if (activity is null)
|
||||
{
|
||||
await RespondAsync(
|
||||
ephemeral: true,
|
||||
embed: EmbedUtils.ErrorEmbed("Vous devez être dans un **thread lié à une activité** pour utiliser cette commande").Build()
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -12,18 +12,17 @@ public class ActivitiesRepository
|
||||
_cocotteDbContext = cocotteDbContext;
|
||||
}
|
||||
|
||||
public async Task<Activity?> FindActivity(ulong activityId)
|
||||
public async Task<Activity?> FindActivity(ulong guildId, ulong channelId, ulong messageId)
|
||||
{
|
||||
return await _cocotteDbContext.Activities.FindAsync(activityId);
|
||||
return await _cocotteDbContext.Activities.FindAsync(guildId, channelId, messageId);
|
||||
}
|
||||
|
||||
public async Task<ActivityPlayer?> FindActivityPlayer(ulong activityId, ulong playerId)
|
||||
public async Task<ActivityPlayer?> FindActivityPlayer(ulong guildId, ulong channelId, ulong messageId, ulong userId)
|
||||
{
|
||||
return await _cocotteDbContext.ActivityPlayers.FindAsync(activityId, playerId);
|
||||
return await _cocotteDbContext.ActivityPlayers.FindAsync(guildId, channelId, messageId, userId);
|
||||
}
|
||||
|
||||
public async Task<int> ActivityPlayerCount(Activity activity) =>
|
||||
await _cocotteDbContext.ActivityPlayers.Where(player => player.ActivityId == activity.ActivityId).CountAsync();
|
||||
public async Task<int> ActivityPlayerCount(Activity activity) => await _cocotteDbContext.Entry(activity).Collection(a => a.ActivityPlayers).Query().CountAsync();
|
||||
|
||||
public async Task<IReadOnlyCollection<ActivityPlayer>> LoadActivityPlayers(Activity activity)
|
||||
{
|
||||
@@ -44,4 +43,31 @@ public class ActivitiesRepository
|
||||
{
|
||||
await _cocotteDbContext.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public void DeleteActivity(Activity activity)
|
||||
{
|
||||
_cocotteDbContext.Activities.Remove(activity);
|
||||
}
|
||||
|
||||
public Activity? FindActivityByThreadId(ulong threadId)
|
||||
{
|
||||
return _cocotteDbContext.Activities.FirstOrDefault(activity => activity.ThreadId == threadId);
|
||||
}
|
||||
|
||||
public async Task<bool> ActivityContainsUser(Activity activity, ulong userId)
|
||||
{
|
||||
return await _cocotteDbContext.Entry(activity)
|
||||
.Collection(a => a.ActivityPlayers)
|
||||
.Query()
|
||||
.AnyAsync(p => p.UserId == userId);
|
||||
}
|
||||
|
||||
public async Task<IList<ulong>> GetActivityPlayerIds(Activity activity)
|
||||
{
|
||||
return await _cocotteDbContext.Entry(activity)
|
||||
.Collection(a => a.ActivityPlayers)
|
||||
.Query()
|
||||
.Select(p => p.UserId)
|
||||
.ToListAsync();
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,24 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Cocotte.Modules.Activities.Models;
|
||||
|
||||
[PrimaryKey(nameof(GuildId), nameof(ChannelId), nameof(MessageId))]
|
||||
[Index(nameof(ThreadId))]
|
||||
public class Activity
|
||||
{
|
||||
[Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
|
||||
public required ulong ActivityId { get; set; }
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.None)]
|
||||
public required ulong GuildId { get; init; }
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.None)]
|
||||
public required ulong ChannelId { get; init; }
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.None)]
|
||||
public required ulong MessageId { get; init; }
|
||||
|
||||
public required ulong CreatorDiscordId { get; init; }
|
||||
public required string CreatorDiscordName { get; set; }
|
||||
public string? Description { get; init; }
|
||||
public required ulong ThreadId { get; init; }
|
||||
public required ulong CreatorUserId { get; init; }
|
||||
public required string CreatorDisplayName { get; init; }
|
||||
public string? Description { get; set; }
|
||||
public required ActivityType Type { get; init; }
|
||||
public required ActivityName Name { get; init; }
|
||||
public required bool AreRolesEnabled { get; init; }
|
||||
@@ -20,6 +28,6 @@ public class Activity
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{nameof(ActivityId)}: {ActivityId}, {nameof(CreatorDiscordId)}: {CreatorDiscordId}, {nameof(Description)}: {Description}, {nameof(Type)}: {Type}, {nameof(Name)}: {Name}, {nameof(MaxPlayers)}: {MaxPlayers}";
|
||||
return $"{nameof(MessageId)}: {MessageId}, {nameof(CreatorUserId)}: {CreatorUserId}, {nameof(Description)}: {Description}, {nameof(Type)}: {Type}, {nameof(Name)}: {Name}, {nameof(MaxPlayers)}: {MaxPlayers}";
|
||||
}
|
||||
}
|
||||
@@ -3,19 +3,21 @@ using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Cocotte.Modules.Activities.Models;
|
||||
|
||||
[PrimaryKey(nameof(ActivityId), nameof(DiscordId))]
|
||||
[PrimaryKey(nameof(GuildId), nameof(ChannelId), nameof(MessageId), nameof(UserId))]
|
||||
public class ActivityPlayer
|
||||
{
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.None)]
|
||||
public required ulong DiscordId { get; init; }
|
||||
public required ulong UserId { get; init; }
|
||||
|
||||
public required string Name { get; init; }
|
||||
|
||||
public ulong ActivityId { get; init; }
|
||||
public ulong GuildId { get; set; }
|
||||
public ulong ChannelId { get; set; }
|
||||
public ulong MessageId { get; init; }
|
||||
public required Activity Activity { get; init; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{nameof(DiscordId)}: {DiscordId}, {nameof(Name)}: {Name}";
|
||||
return $"{nameof(UserId)}: {UserId}, {nameof(Name)}: {Name}";
|
||||
}
|
||||
}
|
||||
@@ -72,7 +72,7 @@ await using(var scope = host.Services.CreateAsyncScope())
|
||||
if (hostEnvironment.IsDevelopment())
|
||||
{
|
||||
var dbContext = scope.ServiceProvider.GetRequiredService<CocotteDbContext>();
|
||||
await dbContext.Database.EnsureDeletedAsync();
|
||||
// await dbContext.Database.EnsureDeletedAsync();
|
||||
await dbContext.Database.EnsureCreatedAsync();
|
||||
}
|
||||
}
|
||||
|
||||
16
Cocotte/Utils/ChannelUtils.cs
Normal file
16
Cocotte/Utils/ChannelUtils.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using Discord;
|
||||
|
||||
namespace Cocotte.Utils;
|
||||
|
||||
public class ChannelUtils
|
||||
{
|
||||
public static string GetChannelLink(IGuildChannel guildChannel)
|
||||
{
|
||||
return GetChannelLink(guildChannel.GuildId, guildChannel.Id);
|
||||
}
|
||||
|
||||
public static string GetChannelLink(ulong guildId, ulong channelId)
|
||||
{
|
||||
return $"https://discord.com/channels/{guildId}/{channelId}";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user