Skip to content

Commit

Permalink
Merge pull request #28 from EpicOfficer/FEATURE/Wordle
Browse files Browse the repository at this point in the history
Feature/wordle
  • Loading branch information
EpicOfficer authored Apr 15, 2024
2 parents 12e299e + 555bd79 commit abc7b80
Show file tree
Hide file tree
Showing 40 changed files with 525 additions and 140 deletions.
6 changes: 2 additions & 4 deletions Blink3.Bot/Enums/WordleLanguageEnum.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ namespace Blink3.Bot.Enums;

public enum WordleLanguageEnum
{
[ChoiceDisplay("English (Default)")]
English,
[ChoiceDisplay("Spanish")]
Spanish
[ChoiceDisplay("English (Default)")] English,
[ChoiceDisplay("Spanish")] Spanish
}
5 changes: 2 additions & 3 deletions Blink3.Bot/Modules/BaseModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@

namespace Blink3.Bot.Modules;

public class BlinkModuleBase<T>(IBlinkGuildRepository? blinkGuildRepository = null) : InteractionModuleBase<T> where T : class, IInteractionContext
public class BlinkModuleBase<T>(IBlinkGuildRepository? blinkGuildRepository = null)
: InteractionModuleBase<T> where T : class, IInteractionContext
{
/// <summary>
/// Responds to an interaction with the provided embed, ephemeral flag, and message components.
Expand Down Expand Up @@ -82,9 +83,7 @@ protected async Task RespondErrorAsync(string? name = null, string message = "",
protected async Task<BlinkGuild> FetchConfig()
{
if (blinkGuildRepository is not null && Context.Interaction.GuildId is not null)
{
return await blinkGuildRepository.GetOrCreateByIdAsync(Context.Interaction.GuildId);
}

return new BlinkGuild();
}
Expand Down
19 changes: 9 additions & 10 deletions Blink3.Bot/Modules/ConfigModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,12 @@ namespace Blink3.Bot.Modules;
public class ConfigModule(IBlinkGuildRepository blinkGuildRepository)
: BlinkModuleBase<IInteractionContext>(blinkGuildRepository)
{
private readonly IBlinkGuildRepository _blinkGuildRepository = blinkGuildRepository;

public enum SettingsEnum
{
[ChoiceDisplay("Wordle Background Colour")]
WordleBackgroundColour,

[ChoiceDisplay("Wordle Text Colour")]
WordleTextColour,

[ChoiceDisplay("Wordle Text Colour")] WordleTextColour,

[ChoiceDisplay("Wordle Correct Tile Colour")]
WordleCorrectTileColour,
Expand All @@ -32,14 +29,16 @@ public enum SettingsEnum

[ChoiceDisplay("Wordle Incorrect Tile Colour")]
WordleIncorrectTileColour,

[ChoiceDisplay("Staff Logging Channel")]
StaffLoggingChannel,

[ChoiceDisplay("Temporary VC Category")]
TempVcCategory
}


private readonly IBlinkGuildRepository _blinkGuildRepository = blinkGuildRepository;

[SlashCommand("set", "Change or reset config values")]
public async Task Set(SettingsEnum setting, string? value = null)
{
Expand Down Expand Up @@ -97,15 +96,15 @@ await _blinkGuildRepository.UpdatePropertiesAsync(guild,
await RespondSuccessAsync("Value reset", "The ID has been reset to default");
return;
}

if (ulong.TryParse(value, out ulong channelId))
{
await _blinkGuildRepository.UpdatePropertiesAsync(guild,
entity => setUlong(entity, channelId));
await RespondSuccessAsync("Value updated", "The ID has been updated successfully");
return;
}

await RespondErrorAsync("Invalid channel", "The value you provided is not a valid ID.");
}

Expand Down
31 changes: 15 additions & 16 deletions Blink3.Bot/Modules/DeleteMessageModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,52 +10,51 @@ namespace Blink3.Bot.Modules;
[RequireUserPermission(GuildPermission.ManageMessages)]
[CommandContextType(InteractionContextType.Guild)]
[IntegrationType(ApplicationIntegrationType.GuildInstall)]
public class DeleteMessageModule(IBlinkGuildRepository blinkGuildRepository,
public class DeleteMessageModule(
IBlinkGuildRepository blinkGuildRepository,
IDiscordAttachmentService discordAttachmentService)
: BlinkModuleBase<IInteractionContext>(blinkGuildRepository)
{
private readonly IBlinkGuildRepository _blinkGuildRepository = blinkGuildRepository;

[MessageCommand("Delete & log")]
public async Task DeleteAndLogMessage(IMessage message)
{
BlinkGuild guildConfig = await FetchConfig();
IMessage fullMessage = await Context.Channel.GetMessageAsync(message.Id);

IMessageChannel? logChannel = await GetValidatedLogChannel(guildConfig, fullMessage);
if (logChannel is null) return;

EmbedBuilder embed = BuildEmbed(fullMessage);

if (fullMessage.Attachments.Count > 0)
{
await DeferAsync(true);
using IDisposableCollection<FileAttachment> attachments =
await discordAttachmentService.DownloadAsync(message, true);
await logChannel.SendFilesAsync(attachments: attachments, text: "", embed: embed.Build());
await logChannel.SendFilesAsync(attachments, "", embed: embed.Build());
}
else
{
await logChannel.SendMessageAsync(embed: embed.Build());
}

await message.DeleteAsync();
await RespondSuccessAsync("Message Deleted", "The message has been deleted and logged.");
}

private EmbedBuilder BuildEmbed(IMessage fullMessage)
{
return new EmbedBuilder()
.WithAuthor(fullMessage.Author)
.WithDescription(fullMessage.Content)
.WithTimestamp(fullMessage.Timestamp)
.WithFields(new EmbedFieldBuilder[] {
new EmbedFieldBuilder().WithName("Deleted by").WithValue($"{Context.User.Mention}"),
new EmbedFieldBuilder().WithName("Channel").WithValue($"<#{Context.Channel.Id}>")
})
.WithFields(new EmbedFieldBuilder().WithName("Deleted by").WithValue($"{Context.User.Mention}"),
new EmbedFieldBuilder().WithName("Channel").WithValue($"<#{Context.Channel.Id}>"))
.WithFooter($"User ID: {fullMessage.Author.Id}");
}

private async Task<IMessageChannel?> GetValidatedLogChannel(BlinkGuild guildConfig, IMessage fullMessage)
{
if (guildConfig.LoggingChannelId is null)
Expand All @@ -72,16 +71,16 @@ await RespondErrorAsync("Logging channel not found",
"The logging channel could not be found. Please set a valid logging channel.");
return null;
}

if (logChannel.Id == Context.Channel.Id)
{
await RespondErrorAsync("Cannot log to the same channel",
"You cannot log messages to the same channel you are deleting them from.");
return null;
}

// ReSharper disable once InvertIf
if (fullMessage.Author.IsBot || fullMessage.Author.IsWebhook)
if (fullMessage.Author.IsBot || fullMessage.Author.IsWebhook)
{
await RespondErrorAsync("Cannot delete bot messages",
"You cannot delete messages from bots or webhooks.");
Expand Down
1 change: 0 additions & 1 deletion Blink3.Bot/Modules/MoveMessageModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using Blink3.Core.Extensions;
using Blink3.Core.Interfaces;
using Blink3.Core.Models;
using Blink3.DataAccess.Extensions;
using Discord;
using Discord.Interactions;
using Discord.Webhook;
Expand Down
10 changes: 5 additions & 5 deletions Blink3.Bot/Modules/TempVcModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ public async Task CamOnly()
return;

await tempVcRepository.UpdatePropertiesAsync(tempVc, vc => vc.CamOnly = !vc.CamOnly);

try
{
switch (tempVc.CamOnly)
Expand All @@ -123,7 +123,7 @@ await voiceChannel.ModifyAsync(vc =>
{
// ignored
}

await RespondSuccessAsync("Temporary VC updated",
$"Camera only mode has been {(tempVc.CamOnly ? "enabled" : "disabled")}.");
}
Expand All @@ -145,19 +145,19 @@ public async Task Delete()
{
TempVc? tempVc = await tempVcRepository.GetByUserIdAsync(Context.Guild.Id, Context.User.Id);
if (tempVc is not null) return tempVc;

await RespondErrorAsync("No Temporary VC", "You do not have a temporary VC in this server.");
return null;
}

private async Task<(TempVc?, IVoiceChannel?)> GetTempVcAndVoiceChannelAsync()
{
TempVc? tempVc = await GetTempVcAsync();
if (tempVc is null) return (null, null);

IVoiceChannel? voiceChannel = await Context.Guild.GetVoiceChannelAsync(tempVc.ChannelId);
if (voiceChannel is not null) return (tempVc, voiceChannel);

await RespondErrorAsync("Temporary VC not found", "Your temporary VC could not be found.");
return (null, null);
}
Expand Down
19 changes: 8 additions & 11 deletions Blink3.Bot/Modules/WordleModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using Blink3.Core.Interfaces;
using Blink3.Core.Models;
using Blink3.Core.Repositories.Interfaces;
using Blink3.DataAccess.Extensions;
using Discord;
using Discord.Interactions;

Expand Down Expand Up @@ -38,19 +37,19 @@ await RespondInfoAsync("Game already in progress",
WordleLanguageEnum.Spanish => "es",
_ => "en"
};

string langString = language switch
{
WordleLanguageEnum.Spanish => "Spanish",
WordleLanguageEnum.English => "English",
_ => "English"
};

wordleGameService.StartNewGameAsync(Context.Channel.Id, lang, 5).Forget();

List<EmbedFieldBuilder> fields =
[
new EmbedFieldBuilder()
new EmbedFieldBuilder
{
Name = "Language",
Value = langString
Expand All @@ -65,7 +64,7 @@ await RespondInfoAsync("Game already in progress",
public async Task Guess(string word)
{
await DeferAsync();

Wordle? wordle = await wordleRepository.GetByChannelIdAsync(Context.Channel.Id);
if (wordle is null)
{
Expand Down Expand Up @@ -111,10 +110,8 @@ await RespondErrorAsync("No game in progress",

ComponentBuilder? component = null;
if (wordle.Language == "en")
{
component = new ComponentBuilder().WithButton("Define", $"blink-define-word_{guess.Word}");
}


await FollowupWithFileAsync(text: text, attachment: attachment, ephemeral: false,
components: component?.Build());
}
Expand Down Expand Up @@ -150,7 +147,7 @@ public async Task Define(string word)
return builder;
})
.ToArray();

await RespondPlainAsync(
$"Definition of {word.ToTitleCase()}",
details is null ? "No definition found" : string.Empty,
Expand Down Expand Up @@ -182,9 +179,9 @@ public async Task Leaderboard()
};
return field;
});

EmbedFieldBuilder[] embedFieldBuilder = await Task.WhenAll(embedFieldBuilderTasks);

await RespondPlainAsync("Points Leaderboard",
embedFields: embedFieldBuilder,
ephemeral: false);
Expand Down
4 changes: 2 additions & 2 deletions Blink3.Bot/Services/DiscordAttachmentService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ private async Task<FileAttachment> CreateFileAttachmentFromUrlAsync(

// Copy the content of the response stream to a new MemoryStream
Stream responseStream = await response.Content.ReadAsStreamAsync();
MemoryStream ms = new MemoryStream();
MemoryStream ms = new();
await responseStream.CopyToAsync(ms);
ms.Position = 0; // Reset the MemoryStream position
ms.Position = 0; // Reset the MemoryStream position

return new FileAttachment(
ms,
Expand Down
6 changes: 3 additions & 3 deletions Blink3.Bot/Services/TempVcCleanService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ private async Task DoWorkAsync()
using IServiceScope scope = scopeFactory.CreateScope();
ITempVcRepository tempVcRepository = scope.ServiceProvider.GetRequiredService<ITempVcRepository>();
IReadOnlyCollection<TempVc> tempVcs = await tempVcRepository.GetAllAsync();

Dictionary<ulong, List<TempVc>> guilds = tempVcs.GroupBy(tempVc => tempVc.GuildId)
.ToDictionary(group => group.Key, group => group.ToList());

_logger.LogInformation("Cleaning {count} unique VCs in {guildCount} guilds",
tempVcs.Count, guilds.Count);

foreach (KeyValuePair<ulong, List<TempVc>> guild in guilds)
await HandleGuild(guild.Key, guild.Value, tempVcRepository);
}
Expand All @@ -65,7 +65,7 @@ private async Task HandleChannel(SocketGuild guild, TempVc tempVc, ITempVcReposi
{
// If the VC was created less than 2 minutes ago, skip it
if (tempVc.CreatedAt.AddMinutes(2) > DateTime.UtcNow) return;

// If the VC is missing, delete it from the database
if (guild.GetVoiceChannel(tempVc.ChannelId) is not { } channel)
{
Expand Down
22 changes: 11 additions & 11 deletions Blink3.Core/Blink3.Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,33 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Discord.Net.Core" Version="3.14.1" />
<PackageReference Include="Discord.Net.Core" Version="3.14.1"/>
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="8.0.0"/>
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0"/>
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="8.0.2"/>
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0"/>
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.1"/>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0"/>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0"/>
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0"/>
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0"/>
<PackageReference Include="Microsoft.Extensions.Options.DataAnnotations" Version="8.0.0"/>
<PackageReference Include="SixLabors.Fonts" Version="2.0.3" />
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.3" />
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.2" />
<PackageReference Include="SixLabors.Fonts" Version="2.0.3"/>
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.3"/>
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="2.1.2"/>
</ItemGroup>

<ItemGroup>
<Folder Include="Repositories\"/>
</ItemGroup>

<ItemGroup>
<None Update="Fonts\Geologica.ttf">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Fonts\Icons.ttf">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Fonts\Geologica.ttf">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Fonts\Icons.ttf">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
3 changes: 2 additions & 1 deletion Blink3.Core/Caching/Memory/MemoryCachingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ namespace Blink3.Core.Caching.Memory;
/// <inheritdoc />
public class MemoryCachingService(IMemoryCache cache) : ICachingService
{
public async Task SetAsync(string key, object value, TimeSpan? absoluteExpireTime = null, CancellationToken cancellationToken = default)
public async Task SetAsync(string key, object value, TimeSpan? absoluteExpireTime = null,
CancellationToken cancellationToken = default)
{
MemoryCacheEntryOptions cacheEntryOptions = new()
{
Expand Down
Loading

0 comments on commit abc7b80

Please sign in to comment.