[Activity] Add thread ping and refactor activity join/leave

This commit is contained in:
2023-03-24 23:39:35 +01:00
parent a3051ed060
commit ced9d15083
4 changed files with 139 additions and 98 deletions

View File

@@ -138,8 +138,7 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
private async Task CreateActivity(ActivityName activityName, string description, bool areRolesEnabled = true, uint? maxPlayers = null, uint? stage = null, InterstellarColor? interstellarColor = null) 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 // 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...***");
@@ -147,7 +146,7 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
var response = await GetOriginalResponseAsync(); var response = await GetOriginalResponseAsync();
// Create associated thread // Create associated thread
var threadId = await CreateThread(activityName, user.DisplayName); var threadId = await CreateThread(activityName, User.DisplayName);
var activityType = ActivityHelper.ActivityNameToType(activityName); var activityType = ActivityHelper.ActivityNameToType(activityName);
maxPlayers ??= ActivityHelper.ActivityTypeToMaxPlayers(activityType); maxPlayers ??= ActivityHelper.ActivityTypeToMaxPlayers(activityType);
@@ -202,7 +201,7 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
Description = description, Description = description,
Type = activityType, Type = activityType,
Name = activityName, Name = activityName,
AreRolesEnabled = true, AreRolesEnabled = areRolesEnabled,
MaxPlayers = (uint) maxPlayers MaxPlayers = (uint) maxPlayers
}; };
} }
@@ -211,7 +210,7 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
await _activitiesRepository.AddActivity(activity); await _activitiesRepository.AddActivity(activity);
// Add creator to activity // Add creator to activity
var rolePlayer = CreateActivityPlayer(activity, user, areRolesEnabled); var rolePlayer = CreateActivityPlayer(activity, User, areRolesEnabled);
activity.ActivityPlayers.Add(rolePlayer); activity.ActivityPlayers.Add(rolePlayer);
@@ -247,8 +246,6 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
[ComponentInteraction("activity join:*", ignoreGroupNames: true)] [ComponentInteraction("activity join:*", ignoreGroupNames: true)]
public async Task JoinActivity(ulong messageId) public async Task JoinActivity(ulong messageId)
{ {
var user = (SocketGuildUser)Context.User;
// Check if activity exists // Check if activity exists
if (await _activitiesRepository.FindActivity(Context.Guild.Id, Context.Channel.Id, messageId) is not { } activity) if (await _activitiesRepository.FindActivity(Context.Guild.Id, Context.Channel.Id, messageId) is not { } activity)
{ {
@@ -260,39 +257,11 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
return; return;
} }
// If player is already registered if (!await AddUserToActivity(activity, User, self: true))
if (await _activitiesRepository.FindActivityPlayer( Context.Guild.Id, Context.Channel.Id, messageId, user.Id) is not null)
{ {
await RespondAsync(
ephemeral: true,
embed: EmbedUtils.ErrorEmbed("Vous êtes **déjà inscrit** à cette activité").Build()
);
return; return;
} }
// Check if activity is full
if (_activitiesRepository.ActivityPlayerCount(activity) >= activity.MaxPlayers)
{
await RespondAsync(
ephemeral: true,
embed: EmbedUtils.ErrorEmbed("L'activité est **complète**").Build()
);
return;
}
_logger.LogTrace("Player {Player} joined activity {Id}", user.DisplayName, messageId);
var activityPlayer = CreateActivityPlayer(activity, User, activity.AreRolesEnabled);
// Add player to activity
activity.ActivityPlayers.Add(activityPlayer);
await _activitiesRepository.SaveChanges();
// Update activity embed
await UpdateActivityEmbed(activity, ActivityUpdateReason.PlayerJoin);
await RespondAsync( await RespondAsync(
ephemeral: true, ephemeral: true,
embed: EmbedUtils.SuccessEmbed("Vous avez bien été **inscrit** pour cette activité").Build() embed: EmbedUtils.SuccessEmbed("Vous avez bien été **inscrit** pour cette activité").Build()
@@ -302,8 +271,6 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
[ComponentInteraction("activity leave:*", ignoreGroupNames: true)] [ComponentInteraction("activity leave:*", ignoreGroupNames: true)]
public async Task LeaveActivity(ulong messageId) public async Task LeaveActivity(ulong messageId)
{ {
var user = (IGuildUser)Context.User;
// Check if activity exists // Check if activity exists
if (await _activitiesRepository.FindActivity(Context.Guild.Id, Context.Channel.Id, messageId) is not { } activity) if (await _activitiesRepository.FindActivity(Context.Guild.Id, Context.Channel.Id, messageId) is not { } activity)
{ {
@@ -315,25 +282,11 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
return; return;
} }
// Check if player is in activity if (!await RemovePlayerFromActivity(activity, User, self: true))
if (await _activitiesRepository.FindActivityPlayer(Context.Guild.Id, Context.Channel.Id, messageId, user.Id) is not { } activityPlayer)
{ {
await RespondAsync(
ephemeral: true,
embed: EmbedUtils.ErrorEmbed("Vous n'êtes **pas inscrit** à cette activité").Build()
);
return; return;
} }
_logger.LogTrace("Player {Player} left activity {Id}", user.DisplayName, messageId);
activity.ActivityPlayers.Remove(activityPlayer);
await _activitiesRepository.SaveChanges();
// Update activity embed
await UpdateActivityEmbed(activity, ActivityUpdateReason.PlayerLeave);
await RespondAsync( await RespondAsync(
ephemeral: true, ephemeral: true,
embed: EmbedUtils.SuccessEmbed("Vous avez bien été **désinscrit** pour cette activité").Build() embed: EmbedUtils.SuccessEmbed("Vous avez bien été **désinscrit** pour cette activité").Build()
@@ -343,8 +296,6 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
[ComponentInteraction("activity delete:*", ignoreGroupNames: true)] [ComponentInteraction("activity delete:*", ignoreGroupNames: true)]
public async Task DeleteActivity(ulong messageId) public async Task DeleteActivity(ulong messageId)
{ {
var user = (SocketGuildUser) Context.User;
// Check if activity exists // Check if activity exists
if (await _activitiesRepository.FindActivity(Context.Guild.Id, Context.Channel.Id, messageId) is not { } activity) if (await _activitiesRepository.FindActivity(Context.Guild.Id, Context.Channel.Id, messageId) is not { } activity)
{ {
@@ -357,7 +308,7 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
} }
// Check if user has permission to delete this activity // Check if user has permission to delete this activity
if (user.Id != activity.CreatorUserId && !user.GetPermissions((IGuildChannel) Context.Channel).ManageMessages) if (User.Id != activity.CreatorUserId && !User.GetPermissions((IGuildChannel) Context.Channel).ManageMessages)
{ {
await RespondAsync( await RespondAsync(
ephemeral: true, ephemeral: true,
@@ -378,6 +329,107 @@ public partial class ActivityModule : InteractionModuleBase<SocketInteractionCon
await Context.Channel.DeleteMessageAsync(messageId); 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()
);
return false;
}
_logger.LogTrace("Player {Player} joined activity {Id}", user.DisplayName, activity.MessageId);
var activityPlayer = CreateActivityPlayer(activity, user, activity.AreRolesEnabled);
// Add player to activity
activity.ActivityPlayers.Add(activityPlayer);
await _activitiesRepository.SaveChanges();
// Update activity embed
await UpdateActivityEmbed(activity, ActivityUpdateReason.PlayerJoin);
// 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;
}
private async Task<bool> RemovePlayerFromActivity(Activity activity, SocketGuildUser user, bool self)
{
// Check if player is in activity
if (await _activitiesRepository.FindActivityPlayer(activity.GuildId, activity.ChannelId, activity.MessageId, user.Id) is not { } activityPlayer)
{
await RespondAsync(
ephemeral: true,
embed: EmbedUtils.ErrorEmbed(self ? "Vous n'êtes **pas inscrit** à cette activité" : $"{user.DisplayName} n'est **pas inscrit** à cette activité").Build()
);
return false;
}
_logger.LogTrace("Player {Player} left activity {Id}", user.DisplayName, activity.MessageId);
activity.ActivityPlayers.Remove(activityPlayer);
await _activitiesRepository.SaveChanges();
// Update activity embed
await UpdateActivityEmbed(activity, ActivityUpdateReason.PlayerLeave);
// 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) private async Task UpdateActivityEmbed(Activity activity, ActivityUpdateReason updateReason)
{ {
// Get channel // Get channel

View File

@@ -1,4 +1,5 @@
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Text;
using Cocotte.Modules.Activities.Models; using Cocotte.Modules.Activities.Models;
using Cocotte.Utils; using Cocotte.Utils;
using Discord; using Discord;
@@ -56,34 +57,12 @@ public partial class ActivityModule
return; return;
} }
// Check that the user is not already in the activity await AddUserToActivity(activity, (SocketGuildUser) user, self: false);
if (await _activitiesRepository.ActivityContainsUser(activity, user.Id))
{
await RespondAsync(
ephemeral: true,
embed: EmbedUtils.ErrorEmbed("Cet utilisateur est **déjà inscrit** à cette activité").Build()
);
return;
}
var activityPlayer = CreateActivityPlayer(activity, (SocketGuildUser) user, activity.AreRolesEnabled);
activity.ActivityPlayers.Add(activityPlayer);
await _activitiesRepository.SaveChanges();
await UpdateActivityEmbed(activity, ActivityUpdateReason.PlayerJoin);
await RespondAsync(
ephemeral: true,
embed: EmbedUtils.SuccessEmbed($"{((IGuildUser) user).DisplayName} a bien été **ajouté** à l'activité").Build()
);
} }
[SlashCommand("ajouter", "Ajouter un joueur à cette activité")] [SlashCommand("enlever", "Enlever un joueur de cette activité")]
public async Task ThreadRemovePlayer(IUser user) public async Task ThreadRemovePlayer(IUser user)
{ {
// TODO: Autocomplete
// Get activity linked to this thread // Get activity linked to this thread
var activity = _activitiesRepository.FindActivityByThreadId(Context.Channel.Id); var activity = _activitiesRepository.FindActivityByThreadId(Context.Channel.Id);
@@ -92,31 +71,32 @@ public partial class ActivityModule
return; return;
} }
// Check that the user is not already in the activity await RemovePlayerFromActivity(activity, (SocketGuildUser) user, self: false);
if (await _activitiesRepository.ActivityContainsUser(activity, user.Id)) }
{
await RespondAsync(
ephemeral: true,
embed: EmbedUtils.ErrorEmbed("Cet utilisateur est **déjà inscrit** à cette activité").Build()
);
[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; return;
} }
var activityPlayer = CreateActivityPlayer(activity, (SocketGuildUser) user, activity.AreRolesEnabled); // Get user ids
var userIds = await _activitiesRepository.GetActivityPlayerIds(activity);
activity.ActivityPlayers.Add(activityPlayer);
await _activitiesRepository.SaveChanges();
await UpdateActivityEmbed(activity, ActivityUpdateReason.PlayerJoin); // Generate message
var pingMessageBuilder = new StringBuilder(message);
pingMessageBuilder.AppendLine("\n");
pingMessageBuilder.Append(string.Join(", ", userIds.Select(id => MentionUtils.MentionUser(id))));
await RespondAsync( await RespondAsync(pingMessageBuilder.ToString());
ephemeral: true,
embed: EmbedUtils.SuccessEmbed($"{((IGuildUser) user).DisplayName} a bien été **ajouté** à l'activité").Build()
);
} }
private async Task<bool> CheckCommandInThread(Activity? activity) private async Task<bool> CheckCommandInThread(Activity? activity)
{ {
// Check if activity is not null (means we are in a valid thread) // Check if activity is not null (means we are in a valid thread)

View File

@@ -22,7 +22,7 @@ public class ActivitiesRepository
return await _cocotteDbContext.ActivityPlayers.FindAsync(guildId, channelId, messageId, userId); return await _cocotteDbContext.ActivityPlayers.FindAsync(guildId, channelId, messageId, userId);
} }
public int ActivityPlayerCount(Activity activity) => activity.ActivityPlayers.Count; 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) public async Task<IReadOnlyCollection<ActivityPlayer>> LoadActivityPlayers(Activity activity)
{ {
@@ -61,4 +61,13 @@ public class ActivitiesRepository
.Query() .Query()
.AnyAsync(p => p.UserId == userId); .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();
}
} }

View File

@@ -72,7 +72,7 @@ await using(var scope = host.Services.CreateAsyncScope())
if (hostEnvironment.IsDevelopment()) if (hostEnvironment.IsDevelopment())
{ {
var dbContext = scope.ServiceProvider.GetRequiredService<CocotteDbContext>(); var dbContext = scope.ServiceProvider.GetRequiredService<CocotteDbContext>();
await dbContext.Database.EnsureDeletedAsync(); // await dbContext.Database.EnsureDeletedAsync();
await dbContext.Database.EnsureCreatedAsync(); await dbContext.Database.EnsureCreatedAsync();
} }
} }