Skip to content

Commit

Permalink
Add the ability to toggle message counts, set the minimum length for …
Browse files Browse the repository at this point in the history
…a message, and add new commands and more info to each command instead of the bare minimum
  • Loading branch information
SylveonDeko committed Aug 15, 2024
1 parent fe22ea0 commit 80b5815
Show file tree
Hide file tree
Showing 10 changed files with 4,677 additions and 67 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace Mewdeko.Database.Migrations.PostgreSql
{
/// <inheritdoc />
public partial class MessageCountsAddition1 : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "MinMessageLength",
table: "GuildConfigs",
type: "integer",
nullable: false,
defaultValue: 0);
}

/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "MinMessageLength",
table: "GuildConfigs");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1318,6 +1318,9 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.Property<decimal>("MemberRole")
.HasColumnType("numeric(20,0)");

b.Property<int>("MinMessageLength")
.HasColumnType("integer");

b.Property<int>("MinSuggestLength")
.HasColumnType("integer");

Expand Down
5 changes: 5 additions & 0 deletions src/Mewdeko/Database/Models/GuildConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ public class GuildConfig : DbEntity
[DefaultValue(true)]
public bool UseMessageCount { get; set; } = true;

/// <summary>
/// The minimum length before a message gets counted
/// </summary>
public int MinMessageLength { get; set; } = 1;

/// <summary>
/// Gets or sets the channel ID for command logs.
/// </summary>
Expand Down
18 changes: 18 additions & 0 deletions src/Mewdeko/Extensions/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,24 @@ public static IServiceScope GetScopedService<T>(this IServiceScopeFactory scopeF
return scope;
}

/// <summary>
/// Implementation that should already have existed in c# but doesnt for some reason
/// </summary>
/// <param name="source"></param>
/// <param name="summer"></param>
/// <typeparam name="TSource"></typeparam>
/// <returns></returns>
public static ulong SumUlong<TSource>(
this IEnumerable<TSource> source, Func<TSource, ulong> summer)
{
ulong total = 0;

foreach(var item in source)
total += summer(item);

return total;
}

/// <summary>
/// Sends a confirmation message asynchronously.
/// </summary>
Expand Down
171 changes: 146 additions & 25 deletions src/Mewdeko/Modules/Utility/MessageCountCommands.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using Discord.Commands;
using Mewdeko.Common.Attributes.TextCommands;
using Mewdeko.Modules.Utility.Services;
using Swan;

namespace Mewdeko.Modules.Utility;

Expand All @@ -8,42 +10,161 @@ public partial class Utility
/// <summary>
/// Commands for message counts
/// </summary>
public class MessageCountCommands : MewdekoSubmodule<MessageCountService>
public class MessageCountCommands(GuildSettingsService guildSettingsService) : MewdekoSubmodule<MessageCountService>
{
/// <summary>
/// Gets the count of messages for that query type
/// Retrieves message statistics for a specific user.
/// </summary>
/// <param name="queryType"></param>
/// <param name="snowflakeId"></param>
[Cmd, Aliases]
public async Task Messages(
MessageCountService.CountQueryType queryType = MessageCountService.CountQueryType.User,
ulong snowflakeId = 0)
/// <param name="user">The user to get message statistics for. If null, uses the command invoker.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
[Cmd, Aliases, RequireContext(ContextType.Guild)]
public async Task UserMessages(IUser? user = null)
{
snowflakeId = queryType switch
user ??= ctx.User;
var (cnt, enabled) = await Service.GetAllCountsForEntity(MessageCountService.CountQueryType.User, user.Id,
ctx.Guild.Id);

if (!enabled)
{
MessageCountService.CountQueryType.Guild => ctx.Guild.Id,
MessageCountService.CountQueryType.User when snowflakeId == 0 => ctx.User.Id,
MessageCountService.CountQueryType.Channel when snowflakeId == 0 => ctx.Channel.Id,
_ => snowflakeId
};
await ReplyErrorLocalizedAsync("message_count_disabled");
return;
}

var mostActive = cnt.MaxBy(x => x.Count);
var leastActive = cnt.MinBy(x => x.Count);

var count = await Service.GetMessageCount(queryType, ctx.Guild.Id, snowflakeId);
var eb = new EmbedBuilder()
.WithTitle(GetText("user_message_count_title", user))
.WithDescription(GetText("user_message_count_description",
cnt.SumUlong(x => x.Count),
mostActive.ChannelId, mostActive.Count,
leastActive.ChannelId, leastActive.Count))
.WithOkColor();

switch (queryType)
await ctx.Channel.SendMessageAsync(embed: eb.Build());
}

/// <summary>
/// Retrieves message statistics for a specific channel.
/// </summary>
/// <param name="channel">The channel to get message statistics for. If null, uses the current channel.</param>
/// <returns>A task that represents the asynchronous operation.</returns>
[Cmd, Aliases, RequireContext(ContextType.Guild)]
public async Task ChannelMessages(IGuildChannel? channel = null)
{
channel ??= ctx.Channel as IGuildChannel;
var (cnt, enabled) = await Service.GetAllCountsForEntity(MessageCountService.CountQueryType.Channel, channel.Id,
ctx.Guild.Id);

if (!enabled)
{
case MessageCountService.CountQueryType.User:
await ctx.Channel.SendConfirmAsync($"The message count for that user is {count}");
break;
case MessageCountService.CountQueryType.Guild:
await ctx.Channel.SendConfirmAsync($"The total message count in this server is {count}");
break;
case MessageCountService.CountQueryType.Channel:
await ctx.Channel.SendConfirmAsync($"The total message count in that channel is {count}");
await ReplyErrorLocalizedAsync("message_count_disabled");
return;
}

var mostActive = cnt.MaxBy(x => x.Count);
var leastActive = cnt.MinBy(x => x.Count);

var eb = new EmbedBuilder()
.WithTitle(GetText("channel_message_count_title", channel.Name))
.WithDescription(GetText("channel_message_count_description",
cnt.SumUlong(x => x.Count),
mostActive.UserId, mostActive.Count,
leastActive.UserId, leastActive.Count))
.WithOkColor();

await ctx.Channel.SendMessageAsync(embed: eb.Build());
}

/// <summary>
/// Retrieves message statistics for the entire server.
/// </summary>
/// <returns>A task that represents the asynchronous operation.</returns>
[Cmd, Aliases, RequireContext(ContextType.Guild)]
public async Task ServerMessages()
{
var (cnt, enabled) = await Service.GetAllCountsForEntity(MessageCountService.CountQueryType.Guild, ctx.Guild.Id,
ctx.Guild.Id);

if (!enabled)
{
await ReplyErrorLocalizedAsync("message_count_disabled");
return;
}

var userGroups = cnt.GroupBy(x => x.UserId)
.Select(g => new
{
UserId = g.Key,
Count = g.SumUlong(x => x.Count)
})
.ToList();

var channelGroups = cnt.GroupBy(x => x.ChannelId)
.Select(g => new
{
ChannelId = g.Key,
Count = g.SumUlong(x => x.Count)
})
.ToList();

var mostActiveUser = userGroups.MaxBy(x => x.Count);
var leastActiveUser = userGroups.MinBy(x => x.Count);
var mostActiveChannel = channelGroups.MaxBy(x => x.Count);
var leastActiveChannel = channelGroups.MinBy(x => x.Count);

var totalMessages = channelGroups.SumUlong(x => x.Count);

var eb = new EmbedBuilder()
.WithTitle(GetText("server_message_stats_title", ctx.Guild.Name))
.WithDescription(GetText("server_message_stats_description",
totalMessages,
mostActiveUser.UserId, mostActiveUser.Count,
leastActiveUser.UserId, leastActiveUser.Count,
mostActiveChannel.ChannelId, mostActiveChannel.Count,
leastActiveChannel.ChannelId, leastActiveChannel.Count))
.WithOkColor();

await ctx.Channel.SendMessageAsync(embed: eb.Build());
}

/// <summary>
/// Sets the minimum length for a message to count
/// </summary>
/// <param name="minLength"></param>
[Cmd, Aliases, RequireContext(ContextType.Guild), UserPerm(GuildPermission.ManageGuild)]
public async Task MinMessageCountLength(int minLength = 0)
{
var config = await guildSettingsService.GetGuildConfig(ctx.Guild.Id);

switch (minLength)
{
case > 4098:
await ReplyErrorLocalizedAsync("max_count_reached");
return;
case 0:
await ReplyConfirmLocalizedAsync("current_min_message_setting", config.MinMessageLength);
break;
default:
throw new ArgumentOutOfRangeException(nameof(queryType), queryType, null);
config.MinMessageLength = minLength;
await guildSettingsService.UpdateGuildConfig(ctx.Guild.Id, config);
await ReplyConfirmLocalizedAsync("min_message_length_set", minLength);
break;
}
}

/// <summary>
/// Toggles message counting in the server
/// </summary>
[Cmd, Aliases, RequireContext(ContextType.Guild), UserPerm(GuildPermission.Administrator)]
public async Task ToggleMessageCount()
{
var toggled = await Service.ToggleGuildMessageCount(ctx.Guild.Id);

if (toggled)
await ReplyConfirmLocalizedAsync("message_counting_enabled");
else
await ReplyConfirmLocalizedAsync("message_counting_disabled");
}
}
}
Loading

0 comments on commit 80b5815

Please sign in to comment.