Added .qdelauth - Delete all quotes by the specified author on this server. If you target yourself - no permission required

This commit is contained in:
Kwoth
2022-08-30 15:46:10 +02:00
parent b69e25edf4
commit fb4f470b44
7 changed files with 100 additions and 32 deletions

View File

@@ -3,14 +3,12 @@ using Microsoft.Extensions.DependencyInjection;
using NadekoBot.Common.Configs; using NadekoBot.Common.Configs;
using NadekoBot.Common.ModuleBehaviors; using NadekoBot.Common.ModuleBehaviors;
using NadekoBot.Db; using NadekoBot.Db;
using NadekoBot.Modules.Administration;
using NadekoBot.Modules.Utility; using NadekoBot.Modules.Utility;
using NadekoBot.Services.Database.Models; using NadekoBot.Services.Database.Models;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Diagnostics; using System.Diagnostics;
using System.Net; using System.Net;
using System.Reflection; using System.Reflection;
using Nadeko.Common;
using RunMode = Discord.Commands.RunMode; using RunMode = Discord.Commands.RunMode;
namespace NadekoBot; namespace NadekoBot;

View File

@@ -0,0 +1,6 @@
namespace NadekoBot.Modules.Utility;
public interface IQuoteService
{
Task<int> DeleteAllAuthorQuotesAsync(ulong guildId, ulong userId);
}

View File

@@ -1,5 +1,4 @@
#nullable disable warnings #nullable disable warnings
using Nadeko.Common;
using NadekoBot.Common.Yml; using NadekoBot.Common.Yml;
using NadekoBot.Db; using NadekoBot.Db;
using NadekoBot.Services.Database.Models; using NadekoBot.Services.Database.Models;
@@ -22,23 +21,25 @@ public partial class Utility
"; ";
private static readonly ISerializer _exportSerializer = new SerializerBuilder() private static readonly ISerializer _exportSerializer = new SerializerBuilder()
.WithEventEmitter(args .WithEventEmitter(args
=> new MultilineScalarFlowStyleEmitter(args)) => new MultilineScalarFlowStyleEmitter(args))
.WithNamingConvention( .WithNamingConvention(
CamelCaseNamingConvention.Instance) CamelCaseNamingConvention.Instance)
.WithIndentedSequences() .WithIndentedSequences()
.ConfigureDefaultValuesHandling(DefaultValuesHandling .ConfigureDefaultValuesHandling(DefaultValuesHandling
.OmitDefaults) .OmitDefaults)
.DisableAliases() .DisableAliases()
.Build(); .Build();
private readonly DbService _db; private readonly DbService _db;
private readonly IHttpClientFactory _http; private readonly IHttpClientFactory _http;
private readonly IQuoteService _qs;
public QuoteCommands(DbService db, IHttpClientFactory http) public QuoteCommands(DbService db, IQuoteService qs, IHttpClientFactory http)
{ {
_db = db; _db = db;
_http = http; _http = http;
_qs = qs;
} }
[Cmd] [Cmd]
@@ -108,7 +109,7 @@ public partial class Utility
[RequireContext(ContextType.Guild)] [RequireContext(ContextType.Guild)]
public async Task QuoteShow(int id) public async Task QuoteShow(int id)
{ {
Quote quote; Quote? quote;
await using (var uow = _db.GetDbContext()) await using (var uow = _db.GetDbContext())
{ {
quote = uow.Quotes.GetById(id); quote = uow.Quotes.GetById(id);
@@ -127,13 +128,13 @@ public partial class Utility
private async Task ShowQuoteData(Quote data) private async Task ShowQuoteData(Quote data)
=> await ctx.Channel.EmbedAsync(_eb.Create(ctx) => await ctx.Channel.EmbedAsync(_eb.Create(ctx)
.WithOkColor() .WithOkColor()
.WithTitle(GetText(strs.quote_id($"#{data.Id}"))) .WithTitle(GetText(strs.quote_id($"#{data.Id}")))
.AddField(GetText(strs.trigger), data.Keyword) .AddField(GetText(strs.trigger), data.Keyword)
.AddField(GetText(strs.response), .AddField(GetText(strs.response),
Format.Sanitize(data.Text).Replace("](", "]\\(")) Format.Sanitize(data.Text).Replace("](", "]\\("))
.WithFooter( .WithFooter(
GetText(strs.created_by($"{data.AuthorName} ({data.AuthorId})")))); GetText(strs.created_by($"{data.AuthorName} ({data.AuthorId})"))));
private async Task QuoteSearchinternalAsync(string? keyword, string textOrAuthor) private async Task QuoteSearchinternalAsync(string? keyword, string textOrAuthor)
{ {
@@ -256,6 +257,28 @@ public partial class Utility
await SendErrorAsync(response); await SendErrorAsync(response);
} }
[Cmd]
[RequireContext(ContextType.Guild)]
public Task QuoteDeleteAuthor(IUser user)
=> QuoteDeleteAuthor(user.Id);
[Cmd]
[RequireContext(ContextType.Guild)]
public async Task QuoteDeleteAuthor(ulong userId)
{
var hasManageMessages = ((IGuildUser)ctx.Message.Author).GuildPermissions.ManageMessages;
if (userId == ctx.User.Id || hasManageMessages)
{
var deleted = await _qs.DeleteAllAuthorQuotesAsync(ctx.Guild.Id, ctx.User.Id);
await ReplyConfirmLocalizedAsync(strs.quotes_deleted_count(deleted));
}
else
{
await ReplyErrorLocalizedAsync(strs.insuf_perms_u);
}
}
[Cmd] [Cmd]
[RequireContext(ContextType.Guild)] [RequireContext(ContextType.Guild)]
[UserPerm(GuildPerm.ManageMessages)] [UserPerm(GuildPerm.ManageMessages)]
@@ -288,7 +311,7 @@ public partial class Utility
} }
var exprsDict = quotes.GroupBy(x => x.Keyword) var exprsDict = quotes.GroupBy(x => x.Keyword)
.ToDictionary(x => x.Key, x => x.Select(ExportedQuote.FromModel)); .ToDictionary(x => x.Key, x => x.Select(ExportedQuote.FromModel));
var text = PREPEND_EXPORT + _exportSerializer.Serialize(exprsDict).UnescapeUnicodeCodePoints(); var text = PREPEND_EXPORT + _exportSerializer.Serialize(exprsDict).UnescapeUnicodeCodePoints();
@@ -303,7 +326,7 @@ public partial class Utility
#if GLOBAL_NADEKO #if GLOBAL_NADEKO
[OwnerOnly] [OwnerOnly]
#endif #endif
public async Task QuotesImport([Leftover] string input = null) public async Task QuotesImport([Leftover] string? input = null)
{ {
input = input?.Trim(); input = input?.Trim();
@@ -357,14 +380,14 @@ public partial class Utility
{ {
var keyword = entry.Key; var keyword = entry.Key;
await uow.Quotes.AddRangeAsync(entry.Value.Where(quote => !string.IsNullOrWhiteSpace(quote.Txt)) await uow.Quotes.AddRangeAsync(entry.Value.Where(quote => !string.IsNullOrWhiteSpace(quote.Txt))
.Select(quote => new Quote .Select(quote => new Quote
{ {
GuildId = guildId, GuildId = guildId,
Keyword = keyword, Keyword = keyword,
Text = quote.Txt, Text = quote.Txt,
AuthorId = quote.Aid, AuthorId = quote.Aid,
AuthorName = quote.An AuthorName = quote.An
})); }));
} }
await uow.SaveChangesAsync(); await uow.SaveChangesAsync();

View File

@@ -0,0 +1,33 @@
#nullable disable warnings
using LinqToDB;
using LinqToDB.EntityFrameworkCore;
using Nadeko.Common;
using NadekoBot.Services.Database.Models;
namespace NadekoBot.Modules.Utility;
public sealed class QuoteService : IQuoteService, INService
{
private readonly DbService _db;
public QuoteService(DbService db)
{
_db = db;
}
/// <summary>
/// Delete all quotes created by the author in a guild
/// </summary>
/// <param name="guildId">ID of the guild</param>
/// <param name="userId">ID of the user</param>
/// <returns>Number of deleted qutoes</returns>
public async Task<int> DeleteAllAuthorQuotesAsync(ulong guildId, ulong userId)
{
await using var ctx = _db.GetDbContext();
var deleted = await ctx.GetTable<Quote>()
.Where(x => x.GuildId == guildId && x.AuthorId == userId)
.DeleteAsync();
return deleted;
}
}

View File

@@ -342,6 +342,9 @@ quoteid:
quotedelete: quotedelete:
- quotedelete - quotedelete
- qdel - qdel
quotedeleteauthor:
- quotedeleteauthor
- qdelauth
draw: draw:
- draw - draw
drawnew: drawnew:

View File

@@ -628,6 +628,10 @@ quotedelete:
desc: "Deletes a quote with the specified ID. You have to either have the Manage Messages permission or be the creator of the quote to delete it." desc: "Deletes a quote with the specified ID. You have to either have the Manage Messages permission or be the creator of the quote to delete it."
args: args:
- "123456" - "123456"
quotedeleteauthor:
desc: "Deletes all quotes by the specified author. If the author is not you, then ManageMessage server permission is required."
args:
- "@QuoteSpammer"
draw: draw:
desc: "Draws a card from this server's deck. You can draw up to 10 cards by supplying a number of cards to draw." desc: "Draws a card from this server's deck. You can draw up to 10 cards by supplying a number of cards to draw."
args: args:

View File

@@ -595,6 +595,7 @@
"presence": "Presence", "presence": "Presence",
"presence_txt": "{0} Servers\n{1} Text Channels\n{2} Voice Channels", "presence_txt": "{0} Servers\n{1} Text Channels\n{2} Voice Channels",
"quotes_deleted": "Deleted all quotes with {0} keyword.", "quotes_deleted": "Deleted all quotes with {0} keyword.",
"quotes_deleted_count": "Deleted {0} quotes.",
"quotes_page": "Page {0} of quotes", "quotes_page": "Page {0} of quotes",
"quotes_page_none": "No quotes found on that page.", "quotes_page_none": "No quotes found on that page.",
"quotes_remove_none": "No quotes found which you can remove.", "quotes_remove_none": "No quotes found which you can remove.",