Skip to content

Commit 7d5a443

Browse files
committed
feat: add /admin reset-database command
1 parent 9f74d73 commit 7d5a443

4 files changed

Lines changed: 72 additions & 0 deletions

File tree

src/RustPlusBot.Features.Commands/CommandServiceCollectionExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public static IServiceCollection AddCommands(this IServiceCollection services)
2323

2424
services.AddSingleton<CommandCooldown>();
2525
services.AddSingleton<BotUptime>();
26+
services.AddOptions<MaintenanceOptions>();
2627
services.AddRustPlusBotLocalization();
2728
services.AddItemData();
2829

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace RustPlusBot.Features.Commands;
2+
3+
/// <summary>
4+
/// Gates the dangerous maintenance command (/admin reset-database). Bound to the same "Workspace"
5+
/// config section as WorkspaceOptions, so a single EnableDangerCommands flag governs all danger commands.
6+
/// </summary>
7+
public sealed class MaintenanceOptions
8+
{
9+
/// <summary>Enables the dangerous /admin reset-database command.</summary>
10+
public bool EnableDangerCommands { get; set; }
11+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
using Discord;
2+
using Discord.Interactions;
3+
using Microsoft.Extensions.DependencyInjection;
4+
using Microsoft.Extensions.Options;
5+
using RustPlusBot.Persistence.Maintenance;
6+
7+
namespace RustPlusBot.Features.Commands.Modules;
8+
9+
/// <summary>Dangerous, danger-gated bot maintenance commands.</summary>
10+
/// <param name="scopeFactory">Creates a short-lived DI scope per interaction.</param>
11+
/// <param name="options">Gates the command behind the danger flag.</param>
12+
[Group("admin", "Bot maintenance (dangerous)")]
13+
[RequireUserPermission(GuildPermission.ManageGuild)]
14+
public sealed class MaintenanceModule(
15+
IServiceScopeFactory scopeFactory,
16+
IOptions<MaintenanceOptions> options) : InteractionModuleBase<SocketInteractionContext>
17+
{
18+
/// <summary>Wipes all bot data across all guilds after a typed confirmation.</summary>
19+
/// <param name="confirm">Must equal the literal "RESET" to proceed.</param>
20+
[SlashCommand("reset-database", "Wipe ALL bot data across ALL servers (dangerous)")]
21+
public async Task ResetDatabaseAsync(
22+
[Summary("confirm", "Type RESET to confirm")]
23+
string confirm)
24+
{
25+
if (Context.Guild is null)
26+
{
27+
await RespondAsync("This command must be used in a server.", ephemeral: true).ConfigureAwait(false);
28+
return;
29+
}
30+
31+
if (!options.Value.EnableDangerCommands)
32+
{
33+
await RespondAsync("Developer commands are disabled.", ephemeral: true).ConfigureAwait(false);
34+
return;
35+
}
36+
37+
if (!string.Equals(confirm, "RESET", StringComparison.Ordinal))
38+
{
39+
await RespondAsync("Type `RESET` exactly to confirm the database wipe.", ephemeral: true)
40+
.ConfigureAwait(false);
41+
return;
42+
}
43+
44+
await DeferAsync(ephemeral: true).ConfigureAwait(false);
45+
var scope = scopeFactory.CreateAsyncScope();
46+
try
47+
{
48+
var maintenance = scope.ServiceProvider.GetRequiredService<IDatabaseMaintenanceService>();
49+
await maintenance.ClearAllAsync().ConfigureAwait(false);
50+
await FollowupAsync("Database cleared. **Restart the bot** for a clean state.", ephemeral: true)
51+
.ConfigureAwait(false);
52+
}
53+
finally
54+
{
55+
await scope.DisposeAsync().ConfigureAwait(false);
56+
}
57+
}
58+
}

src/RustPlusBot.Host/Program.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@
7171
.Validate(static o => o.Cooldown > TimeSpan.Zero, "Commands:Cooldown must be positive.")
7272
.ValidateOnStart();
7373
builder.Services.AddCommands();
74+
builder.Services.AddOptions<MaintenanceOptions>()
75+
.Bind(builder.Configuration.GetSection("Workspace"));
7476
builder.Services.AddEvents();
7577
builder.Services.AddPlayers();
7678
builder.Services.AddOptions<MapOptions>()

0 commit comments

Comments
 (0)