Skip to content

Commit

Permalink
Add bot management role support
Browse files Browse the repository at this point in the history
  • Loading branch information
th0mk committed May 30, 2023
1 parent edc0163 commit d4f0bce
Show file tree
Hide file tree
Showing 9 changed files with 189 additions and 28 deletions.
36 changes: 22 additions & 14 deletions src/FMBot.Bot/Builders/GuildSettingBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,8 @@ public static ResponseModel CrownSeederRunning(ContextModel context)
response.Embed.WithColor(DiscordConstants.InformationColorBlue);
response.Embed.WithDescription($"<a:loading:821676038102056991> Seeding crowns... ");

response.Embed.WithFooter($"Crownseeder initiated by {context.DiscordUser.Username}");

return response;
}

Expand All @@ -464,14 +466,14 @@ public async Task<ResponseModel> CrownSeederDone(ContextModel context, int amoun
description.AppendLine($"- `{prefix}killallcrowns` (All crowns)");
description.AppendLine($"- `{prefix}killallseededcrowns` (Only seeded crowns)");

response.Embed.WithFooter($"Last crownseeder initiated by {context.ContextUser}");
response.Embed.WithFooter($"Crownseeder initiated by {context.DiscordUser.Username}");

response.Embed.WithDescription(description.ToString());

return response;
}

public async Task<bool> UserIsAllowed(IInteractionContext context)
public async Task<bool> UserIsAllowed(IInteractionContext context, bool managersAllowed = true)
{
if (context.Guild == null)
{
Expand All @@ -491,28 +493,34 @@ public async Task<bool> UserIsAllowed(IInteractionContext context)
return true;
}

//var fmbotManagerRole = context.Guild.Roles
// .FirstOrDefault(f => f.Name?.ToLower() == ".fmbot manager");
//if (fmbotManagerRole != null &&
// guildUser.RoleIds.Any(a => a == fmbotManagerRole.Id))
//{
// return true;
//}
if (managersAllowed)
{
var guild = await this._guildService.GetGuildAsync(context.Guild.Id);
if (guild.BotManagementRoles != null &&
guild.BotManagementRoles.Any() &&
guildUser.RoleIds.Any(a => guild.BotManagementRoles.Contains(a)))
{
return true;
}
}

return false;
}

public async Task<bool> UserNotAllowedResponse(IInteractionContext context)
public static async Task UserNotAllowedResponse(IInteractionContext context, bool managersAllowed = true)
{
var response = new StringBuilder();
response.AppendLine("You are not authorized to change this .fmbot setting.");
response.AppendLine();
response.AppendLine("To change .fmbot settings, you must have the `Ban Members` permission or be an administrator.");
//response.AppendLine("- A role with the name `.fmbot manager`");
response.AppendLine("To change .fmbot settings, you have at least one of the following:");
response.AppendLine("- `Administrator` permission");
response.AppendLine("- `Ban Members` permission");
if (managersAllowed)
{
response.AppendLine("- A role that is allowed to manage the bot");
}

await context.Interaction.RespondAsync(response.ToString(), ephemeral: true);

return false;
}

public async Task<ResponseModel> BlockedUsersAsync(
Expand Down
62 changes: 62 additions & 0 deletions src/FMBot.Bot/Builders/PremiumSettingBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,4 +131,66 @@ public async Task<ResponseModel> BlockedRoles(ContextModel context, IUser lastMo

return response;
}

public async Task<ResponseModel> BotManagementRoles(ContextModel context, IUser lastModifier = null)
{
var response = new ResponseModel
{
ResponseType = ResponseType.Embed,
};

var guild = await this._guildService.GetGuildAsync(context.DiscordGuild.Id);

var fmType = new SelectMenuBuilder()
.WithPlaceholder("Pick bot management roles")
.WithCustomId(InteractionConstants.SetBotManagementRoleMenu)
.WithType(ComponentType.RoleSelect)
.WithMinValues(0)
.WithMaxValues(25);

response.Embed.WithTitle("Set bot management roles");

var description = new StringBuilder();
description.AppendLine("Select the roles that are allowed to change .fmbot settings on this server.");
description.AppendLine();
description.AppendLine("Users with these roles will be able to:");
description.AppendLine("- Change all bot settings (except for this one)");
description.AppendLine("- Block and unblock users");
description.AppendLine("- Run crownseeder");
description.AppendLine("- Manage crowns");
description.AppendLine();

if (guild.BotManagementRoles != null && guild.BotManagementRoles.Any())
{
description.AppendLine($"**Picked roles:**");
foreach (var roleId in guild.BotManagementRoles)
{
var role = context.DiscordGuild.GetRole(roleId);
if (role != null)
{
description.AppendLine($"- <@&{roleId}>");
}
}
}
else
{
description.AppendLine($"Picked roles: None");
}

response.Embed.WithDescription(description.ToString());

var footer = new StringBuilder();
footer.AppendLine("✨ Premium server");
if (lastModifier != null)
{
footer.AppendLine($"Last modified by {lastModifier.Username}");
}
response.Embed.WithFooter(footer.ToString());

response.Embed.WithColor(DiscordConstants.InformationColorBlue);

response.Components = new ComponentBuilder().WithSelectMenu(fmType);

return response;
}
}
2 changes: 1 addition & 1 deletion src/FMBot.Bot/Handlers/InteractionHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ private async Task<bool> CheckAttributes(ShardedInteractionContext context, IRea
{
if (!await this._guildSettingBuilder.UserIsAllowed(context))
{
await this._guildSettingBuilder.UserNotAllowedResponse(context);
await GuildSettingBuilder.UserNotAllowedResponse(context);
context.LogCommandUsed(CommandResponse.NoPermission);
return false;
}
Expand Down
1 change: 1 addition & 0 deletions src/FMBot.Bot/Resources/InteractionConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public static class InteractionConstants

public const string SetAllowedRoleMenu = "guild-allowed-roles-menu";
public const string SetBlockedRoleMenu = "guild-blocked-roles-menu";
public const string SetBotManagementRoleMenu = "guild-bot-management-roles-menu";


public const string CensorTypes = "admin-censor-*";
Expand Down
19 changes: 17 additions & 2 deletions src/FMBot.Bot/Services/Guild/GuildService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,6 @@ public async Task<Persistence.Domain.Models.Guild> GetGuildWithGuildUsers(ulong?
"gu.guild_id, " +
"gu.user_name, " +
"gu.bot, " +
"gu.who_knows_whitelisted, " +
"gu.who_knows_blocked, " +
"gu.last_message, " +
"gu.roles AS dto_roles, " +
"u.user_name_last_fm, " +
Expand Down Expand Up @@ -297,6 +295,23 @@ public async Task ChangeGuildBlockedRoles(IGuild discordGuild, ulong[] blockedRo
await RemoveGuildFromCache(discordGuild.Id);
}

public async Task ChangeGuildBotManagementRoles(IGuild discordGuild, ulong[] botManagementRoles)
{
await using var db = await this._contextFactory.CreateDbContextAsync();
var existingGuild = await db.Guilds
.AsQueryable()
.FirstAsync(f => f.DiscordGuildId == discordGuild.Id);

existingGuild.Name = discordGuild.Name;
existingGuild.BotManagementRoles = botManagementRoles;

db.Entry(existingGuild).State = EntityState.Modified;

await db.SaveChangesAsync();

await RemoveGuildFromCache(discordGuild.Id);
}

public async Task ChangeGuildSettingAsync(IGuild discordGuild, FmEmbedType? embedType)
{
await using var db = await this._contextFactory.CreateDbContextAsync();
Expand Down
50 changes: 49 additions & 1 deletion src/FMBot.Bot/SlashCommands/PremiumSettingSlashCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using FMBot.Bot.Resources;
using FMBot.Bot.Services;
using FMBot.Bot.Services.Guild;
using FMBot.Domain.Models;

namespace FMBot.Bot.SlashCommands;

Expand All @@ -18,20 +19,30 @@ public class PremiumSettingSlashCommands : InteractionModuleBase
private readonly GuildService _guildService;

private readonly PremiumSettingBuilder _premiumSettingBuilder;
private readonly GuildSettingBuilder _guildSettingBuilder;

public PremiumSettingSlashCommands(UserService userService,
GuildService guildService,
PremiumSettingBuilder premiumSettingBuilder)
PremiumSettingBuilder premiumSettingBuilder,
GuildSettingBuilder guildSettingBuilder)
{
this._userService = userService;
this._guildService = guildService;
this._premiumSettingBuilder = premiumSettingBuilder;
this._guildSettingBuilder = guildSettingBuilder;
}

[ComponentInteraction(InteractionConstants.SetAllowedRoleMenu)]
[ServerStaffOnly]
public async Task SetGuildAllowedRoles(string[] inputs)
{
if (!await this._guildSettingBuilder.UserIsAllowed(this.Context))
{
await GuildSettingBuilder.UserNotAllowedResponse(this.Context);
this.Context.LogCommandUsed(CommandResponse.NoPermission);
return;
}

if (inputs != null)
{
var roleIds = new List<ulong>();
Expand All @@ -55,6 +66,13 @@ public async Task SetGuildAllowedRoles(string[] inputs)
[ServerStaffOnly]
public async Task SetGuildBlockedRoles(string[] inputs)
{
if (!await this._guildSettingBuilder.UserIsAllowed(this.Context))
{
await GuildSettingBuilder.UserNotAllowedResponse(this.Context);
this.Context.LogCommandUsed(CommandResponse.NoPermission);
return;
}

if (inputs != null)
{
var roleIds = new List<ulong>();
Expand All @@ -73,4 +91,34 @@ public async Task SetGuildBlockedRoles(string[] inputs)

await this.Context.UpdateInteractionEmbed(response);
}

[ComponentInteraction(InteractionConstants.SetBotManagementRoleMenu)]
[ServerStaffOnly]
public async Task SetBotManagementRoles(string[] inputs)
{
if (!await this._guildSettingBuilder.UserIsAllowed(this.Context, managersAllowed: false))
{
await GuildSettingBuilder.UserNotAllowedResponse(this.Context, managersAllowed: false);
this.Context.LogCommandUsed(CommandResponse.NoPermission);
return;
}

if (inputs != null)
{
var roleIds = new List<ulong>();
foreach (var input in inputs)
{
var roleId = ulong.Parse(input);
roleIds.Add(roleId);
}

await this._guildService.ChangeGuildBotManagementRoles(this.Context.Guild, roleIds.ToArray());
}

var response = await this._premiumSettingBuilder.BotManagementRoles(new ContextModel(this.Context), this.Context.User);

await this.DeferAsync();

await this.Context.UpdateInteractionEmbed(response);
}
}
4 changes: 2 additions & 2 deletions src/FMBot.Bot/SlashCommands/SettingSlashCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public async Task GetGuildSetting(string[] inputs)
{
if (!await this._guildSettingBuilder.UserIsAllowed(this.Context))
{
await this._guildSettingBuilder.UserNotAllowedResponse(this.Context);
await GuildSettingBuilder.UserNotAllowedResponse(this.Context);
return;
}

Expand Down Expand Up @@ -289,7 +289,7 @@ public async Task SetActivityThreshold(string messageId, SetActivityThresholdMod
{
if (!await this._guildSettingBuilder.UserIsAllowed(this.Context))
{
await this._guildSettingBuilder.UserNotAllowedResponse(this.Context);
await GuildSettingBuilder.UserNotAllowedResponse(this.Context);
return;
}

Expand Down
41 changes: 35 additions & 6 deletions src/FMBot.Bot/TextCommands/Guild/PremiumGuildCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ public class PremiumGuildCommands : BaseCommandModule

private InteractiveService Interactivity { get; }


public PremiumGuildCommands(
IOptions<BotSettings> botSettings,
InteractiveService interactivity,
Expand All @@ -55,9 +54,9 @@ public class PremiumGuildCommands : BaseCommandModule
[RequiresIndex]
public async Task SetAllowedRoles([Remainder] string unused = null)
{
if (!await this._adminService.HasCommandAccessAsync(this.Context.User, UserType.Admin))
if (!PublicProperties.PremiumServers.ContainsKey(this.Context.Guild.Id))
{
await ReplyAsync(Constants.FmbotStaffOnly);
await ReplyAsync("This command is not quite ready yet. Stay tuned!");
this.Context.LogCommandUsed(CommandResponse.NoPermission);
return;
}
Expand All @@ -78,16 +77,16 @@ public async Task SetAllowedRoles([Remainder] string unused = null)
}

[Command("blockedroles", RunMode = RunMode.Async)]
[Summary("Sets roles that are allowed to be in server-wide charts")]
[Summary("Sets roles that are blocked from server-wide charts")]
[Alias("wkwblacklist", "wkblocklist", "whoknowsblaccklist", "whoknowsblocklist")]
[GuildOnly]
[ExcludeFromHelp]
[RequiresIndex]
public async Task SetBlockedRoles([Remainder] string unused = null)
{
if (!await this._adminService.HasCommandAccessAsync(this.Context.User, UserType.Admin))
if (!PublicProperties.PremiumServers.ContainsKey(this.Context.Guild.Id))
{
await ReplyAsync(Constants.FmbotStaffOnly);
await ReplyAsync("This command is not quite ready yet. Stay tuned!");
this.Context.LogCommandUsed(CommandResponse.NoPermission);
return;
}
Expand All @@ -106,4 +105,34 @@ public async Task SetBlockedRoles([Remainder] string unused = null)
await this.Context.HandleCommandException(e);
}
}

[Command("botmanagementroles", RunMode = RunMode.Async)]
[Summary("Sets roles that are allowed to manage .fmbot in this server")]
[Alias("managementroles", "staffroles", "adminroles", "modroles", "botroles", "botmangementroles")]
[GuildOnly]
[ExcludeFromHelp]
[RequiresIndex]
public async Task SetBotManagementRoles([Remainder] string unused = null)
{
if (!PublicProperties.PremiumServers.ContainsKey(this.Context.Guild.Id))
{
await ReplyAsync("This command is not quite ready yet. Stay tuned!");
this.Context.LogCommandUsed(CommandResponse.NoPermission);
return;
}

try
{
var prfx = this._prefixService.GetPrefix(this.Context.Guild?.Id);

var response = await this._premiumSettingBuilder.BotManagementRoles(new ContextModel(this.Context, prfx));

await this.Context.SendResponse(this.Interactivity, response);
this.Context.LogCommandUsed(response.CommandResponse);
}
catch (Exception e)
{
await this.Context.HandleCommandException(e);
}
}
}
2 changes: 0 additions & 2 deletions src/FMBot.Domain/Models/FullGuildUser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ public class FullGuildUser
public int GuildId { get; set; }
public string UserName { get; set; }
public bool? Bot { get; set; }
public bool? WhoKnowsWhitelisted { get; set; }
public bool? WhoKnowsBlocked { get; set; }
public DateTime? LastMessage { get; set; }

public ulong[] Roles { get; set; }
Expand Down

0 comments on commit d4f0bce

Please sign in to comment.