mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-11 01:38:27 -04:00
Global usings and file scoped namespaces
This commit is contained in:
@@ -1,30 +1,29 @@
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Common;
|
||||
|
||||
namespace NadekoBot.Modules.CustomReactions
|
||||
{
|
||||
public class ExportedExpr
|
||||
{
|
||||
public string Res { get; set; }
|
||||
public string Id { get; set; }
|
||||
public bool Ad { get; set; }
|
||||
public bool Dm { get; set; }
|
||||
public bool At { get; set; }
|
||||
public bool Ca { get; set; }
|
||||
public string[] React;
|
||||
namespace NadekoBot.Modules.CustomReactions;
|
||||
|
||||
public static ExportedExpr FromModel(CustomReaction cr)
|
||||
=> new ExportedExpr()
|
||||
{
|
||||
Res = cr.Response,
|
||||
Id = ((kwum)cr.Id).ToString(),
|
||||
Ad = cr.AutoDeleteTrigger,
|
||||
At = cr.AllowTarget,
|
||||
Ca = cr.ContainsAnywhere,
|
||||
Dm = cr.DmResponse,
|
||||
React = string.IsNullOrWhiteSpace(cr.Reactions)
|
||||
? null
|
||||
: cr.GetReactions(),
|
||||
};
|
||||
}
|
||||
public class ExportedExpr
|
||||
{
|
||||
public string Res { get; set; }
|
||||
public string Id { get; set; }
|
||||
public bool Ad { get; set; }
|
||||
public bool Dm { get; set; }
|
||||
public bool At { get; set; }
|
||||
public bool Ca { get; set; }
|
||||
public string[] React;
|
||||
|
||||
public static ExportedExpr FromModel(CustomReaction cr)
|
||||
=> new ExportedExpr()
|
||||
{
|
||||
Res = cr.Response,
|
||||
Id = ((kwum)cr.Id).ToString(),
|
||||
Ad = cr.AutoDeleteTrigger,
|
||||
At = cr.AllowTarget,
|
||||
Ca = cr.ContainsAnywhere,
|
||||
Dm = cr.DmResponse,
|
||||
React = string.IsNullOrWhiteSpace(cr.Reactions)
|
||||
? null
|
||||
: cr.GetReactions(),
|
||||
};
|
||||
}
|
@@ -1,362 +1,358 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using NadekoBot.Common.Attributes;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Modules.CustomReactions.Services;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Common;
|
||||
|
||||
namespace NadekoBot.Modules.CustomReactions
|
||||
namespace NadekoBot.Modules.CustomReactions;
|
||||
|
||||
public class CustomReactions : NadekoModule<CustomReactionsService>
|
||||
{
|
||||
public class CustomReactions : NadekoModule<CustomReactionsService>
|
||||
private readonly IBotCredentials _creds;
|
||||
private readonly IHttpClientFactory _clientFactory;
|
||||
|
||||
public CustomReactions(IBotCredentials creds, IHttpClientFactory clientFactory)
|
||||
{
|
||||
private readonly IBotCredentials _creds;
|
||||
private readonly IHttpClientFactory _clientFactory;
|
||||
_creds = creds;
|
||||
_clientFactory = clientFactory;
|
||||
}
|
||||
|
||||
public CustomReactions(IBotCredentials creds, IHttpClientFactory clientFactory)
|
||||
private bool AdminInGuildOrOwnerInDm() => (ctx.Guild is null && _creds.IsOwner(ctx.User))
|
||||
|| (ctx.Guild != null && ((IGuildUser)ctx.User).GuildPermissions.Administrator);
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
public async Task AddCustReact(string key, [Leftover] string message)
|
||||
{
|
||||
var channel = ctx.Channel as ITextChannel;
|
||||
if (string.IsNullOrWhiteSpace(message) || string.IsNullOrWhiteSpace(key))
|
||||
return;
|
||||
|
||||
if (!AdminInGuildOrOwnerInDm())
|
||||
{
|
||||
_creds = creds;
|
||||
_clientFactory = clientFactory;
|
||||
await ReplyErrorLocalizedAsync(strs.insuff_perms).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
private bool AdminInGuildOrOwnerInDm() => (ctx.Guild is null && _creds.IsOwner(ctx.User))
|
||||
|| (ctx.Guild != null && ((IGuildUser)ctx.User).GuildPermissions.Administrator);
|
||||
var cr = await _service.AddAsync(ctx.Guild?.Id, key, message);
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
public async Task AddCustReact(string key, [Leftover] string message)
|
||||
await ctx.Channel.EmbedAsync(_eb.Create().WithOkColor()
|
||||
.WithTitle(GetText(strs.new_cust_react))
|
||||
.WithDescription($"#{(kwum)cr.Id}")
|
||||
.AddField(GetText(strs.trigger), key)
|
||||
.AddField(GetText(strs.response), message.Length > 1024 ? GetText(strs.redacted_too_long) : message)
|
||||
).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
public async Task EditCustReact(kwum id, [Leftover] string message)
|
||||
{
|
||||
var channel = ctx.Channel as ITextChannel;
|
||||
if (string.IsNullOrWhiteSpace(message) || id < 0)
|
||||
return;
|
||||
|
||||
if ((channel is null && !_creds.IsOwner(ctx.User)) || (channel != null && !((IGuildUser)ctx.User).GuildPermissions.Administrator))
|
||||
{
|
||||
var channel = ctx.Channel as ITextChannel;
|
||||
if (string.IsNullOrWhiteSpace(message) || string.IsNullOrWhiteSpace(key))
|
||||
return;
|
||||
|
||||
if (!AdminInGuildOrOwnerInDm())
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.insuff_perms).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var cr = await _service.AddAsync(ctx.Guild?.Id, key, message);
|
||||
await ReplyErrorLocalizedAsync(strs.insuff_perms).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var cr = await _service.EditAsync(ctx.Guild?.Id, (int)id, message).ConfigureAwait(false);
|
||||
if (cr != null)
|
||||
{
|
||||
await ctx.Channel.EmbedAsync(_eb.Create().WithOkColor()
|
||||
.WithTitle(GetText(strs.new_cust_react))
|
||||
.WithDescription($"#{(kwum)cr.Id}")
|
||||
.AddField(GetText(strs.trigger), key)
|
||||
.WithTitle(GetText(strs.edited_cust_react))
|
||||
.WithDescription($"#{id}")
|
||||
.AddField(GetText(strs.trigger), cr.Trigger)
|
||||
.AddField(GetText(strs.response), message.Length > 1024 ? GetText(strs.redacted_too_long) : message)
|
||||
).ConfigureAwait(false);
|
||||
).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
public async Task EditCustReact(kwum id, [Leftover] string message)
|
||||
else
|
||||
{
|
||||
var channel = ctx.Channel as ITextChannel;
|
||||
if (string.IsNullOrWhiteSpace(message) || id < 0)
|
||||
return;
|
||||
|
||||
if ((channel is null && !_creds.IsOwner(ctx.User)) || (channel != null && !((IGuildUser)ctx.User).GuildPermissions.Administrator))
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.insuff_perms).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var cr = await _service.EditAsync(ctx.Guild?.Id, (int)id, message).ConfigureAwait(false);
|
||||
if (cr != null)
|
||||
{
|
||||
await ctx.Channel.EmbedAsync(_eb.Create().WithOkColor()
|
||||
.WithTitle(GetText(strs.edited_cust_react))
|
||||
.WithDescription($"#{id}")
|
||||
.AddField(GetText(strs.trigger), cr.Trigger)
|
||||
.AddField(GetText(strs.response), message.Length > 1024 ? GetText(strs.redacted_too_long) : message)
|
||||
).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.edit_fail).ConfigureAwait(false);
|
||||
}
|
||||
await ReplyErrorLocalizedAsync(strs.edit_fail).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[Priority(1)]
|
||||
public async Task ListCustReact(int page = 1)
|
||||
[NadekoCommand, Aliases]
|
||||
[Priority(1)]
|
||||
public async Task ListCustReact(int page = 1)
|
||||
{
|
||||
if (--page < 0 || page > 999)
|
||||
return;
|
||||
|
||||
var customReactions = _service.GetCustomReactionsFor(ctx.Guild?.Id);
|
||||
|
||||
if (customReactions is null || !customReactions.Any())
|
||||
{
|
||||
if (--page < 0 || page > 999)
|
||||
return;
|
||||
|
||||
var customReactions = _service.GetCustomReactionsFor(ctx.Guild?.Id);
|
||||
|
||||
if (customReactions is null || !customReactions.Any())
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.no_found).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
await ctx.SendPaginatedConfirmAsync(page, pageFunc: curPage =>
|
||||
{
|
||||
var desc = customReactions.OrderBy(cr => cr.Trigger)
|
||||
.Skip(curPage * 20)
|
||||
.Take(20)
|
||||
.Select(cr => $"{(cr.ContainsAnywhere ? "🗯" : "◾")}" +
|
||||
$"{(cr.DmResponse ? "✉" : "◾")}" +
|
||||
$"{(cr.AutoDeleteTrigger ? "❌" : "◾")}" +
|
||||
$"`{(kwum) cr.Id}` {cr.Trigger}"
|
||||
+ (string.IsNullOrWhiteSpace(cr.Reactions)
|
||||
? string.Empty
|
||||
: " // " + string.Join(" ", cr.GetReactions())))
|
||||
.JoinWith('\n');
|
||||
|
||||
return _eb.Create().WithOkColor()
|
||||
.WithTitle(GetText(strs.custom_reactions))
|
||||
.WithDescription(desc);
|
||||
|
||||
}, customReactions.Length, 20);
|
||||
await ReplyErrorLocalizedAsync(strs.no_found).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
public enum All
|
||||
await ctx.SendPaginatedConfirmAsync(page, pageFunc: curPage =>
|
||||
{
|
||||
All
|
||||
}
|
||||
var desc = customReactions.OrderBy(cr => cr.Trigger)
|
||||
.Skip(curPage * 20)
|
||||
.Take(20)
|
||||
.Select(cr => $"{(cr.ContainsAnywhere ? "🗯" : "◾")}" +
|
||||
$"{(cr.DmResponse ? "✉" : "◾")}" +
|
||||
$"{(cr.AutoDeleteTrigger ? "❌" : "◾")}" +
|
||||
$"`{(kwum) cr.Id}` {cr.Trigger}"
|
||||
+ (string.IsNullOrWhiteSpace(cr.Reactions)
|
||||
? string.Empty
|
||||
: " // " + string.Join(" ", cr.GetReactions())))
|
||||
.JoinWith('\n');
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[Priority(0)]
|
||||
public async Task ListCustReact(All _)
|
||||
return _eb.Create().WithOkColor()
|
||||
.WithTitle(GetText(strs.custom_reactions))
|
||||
.WithDescription(desc);
|
||||
|
||||
}, customReactions.Length, 20);
|
||||
}
|
||||
|
||||
public enum All
|
||||
{
|
||||
All
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[Priority(0)]
|
||||
public async Task ListCustReact(All _)
|
||||
{
|
||||
await ReplyPendingLocalizedAsync(strs.obsolete_use(Format.Code($"{Prefix}crsexport")));
|
||||
await CrsExport();
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
public async Task ListCustReactG(int page = 1)
|
||||
{
|
||||
await ReplyPendingLocalizedAsync(strs.obsolete_use(Format.Code($"{Prefix}crsexport")));
|
||||
await CrsExport();
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
public async Task ShowCustReact(kwum id)
|
||||
{
|
||||
var found = _service.GetCustomReaction(ctx.Guild?.Id, (int)id);
|
||||
|
||||
if (found is null)
|
||||
{
|
||||
await ReplyPendingLocalizedAsync(strs.obsolete_use(Format.Code($"{Prefix}crsexport")));
|
||||
await CrsExport();
|
||||
await ReplyErrorLocalizedAsync(strs.no_found_id).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
public async Task ListCustReactG(int page = 1)
|
||||
else
|
||||
{
|
||||
await ReplyPendingLocalizedAsync(strs.obsolete_use(Format.Code($"{Prefix}crsexport")));
|
||||
await CrsExport();
|
||||
await ctx.Channel.EmbedAsync(_eb.Create().WithOkColor()
|
||||
.WithDescription($"#{id}")
|
||||
.AddField(GetText(strs.trigger), found.Trigger.TrimTo(1024))
|
||||
.AddField(GetText(strs.response), found.Response.TrimTo(1000).Replace("](", "]\\("))
|
||||
).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
public async Task ShowCustReact(kwum id)
|
||||
[NadekoCommand, Aliases]
|
||||
public async Task DelCustReact(kwum id)
|
||||
{
|
||||
if (!AdminInGuildOrOwnerInDm())
|
||||
{
|
||||
var found = _service.GetCustomReaction(ctx.Guild?.Id, (int)id);
|
||||
|
||||
if (found is null)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.no_found_id).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
await ctx.Channel.EmbedAsync(_eb.Create().WithOkColor()
|
||||
.WithDescription($"#{id}")
|
||||
.AddField(GetText(strs.trigger), found.Trigger.TrimTo(1024))
|
||||
.AddField(GetText(strs.response), found.Response.TrimTo(1000).Replace("](", "]\\("))
|
||||
).ConfigureAwait(false);
|
||||
}
|
||||
await ReplyErrorLocalizedAsync(strs.insuff_perms).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
public async Task DelCustReact(kwum id)
|
||||
var cr = await _service.DeleteAsync(ctx.Guild?.Id, (int)id);
|
||||
|
||||
if (cr != null)
|
||||
{
|
||||
if (!AdminInGuildOrOwnerInDm())
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.insuff_perms).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var cr = await _service.DeleteAsync(ctx.Guild?.Id, (int)id);
|
||||
|
||||
if (cr != null)
|
||||
{
|
||||
await ctx.Channel.EmbedAsync(_eb.Create().WithOkColor()
|
||||
.WithTitle(GetText(strs.deleted))
|
||||
.WithDescription($"#{id}")
|
||||
.AddField(GetText(strs.trigger), cr.Trigger.TrimTo(1024))
|
||||
.AddField(GetText(strs.response), cr.Response.TrimTo(1024))).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.no_found_id).ConfigureAwait(false);
|
||||
}
|
||||
await ctx.Channel.EmbedAsync(_eb.Create().WithOkColor()
|
||||
.WithTitle(GetText(strs.deleted))
|
||||
.WithDescription($"#{id}")
|
||||
.AddField(GetText(strs.trigger), cr.Trigger.TrimTo(1024))
|
||||
.AddField(GetText(strs.response), cr.Response.TrimTo(1024))).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
public async Task CrReact(kwum id, params string[] emojiStrs)
|
||||
else
|
||||
{
|
||||
if (!AdminInGuildOrOwnerInDm())
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.insuff_perms).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var cr = _service.GetCustomReaction(ctx.Guild?.Id, id);
|
||||
if (cr is null)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.no_found).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (emojiStrs.Length == 0)
|
||||
{
|
||||
await _service.ResetCrReactions(ctx.Guild?.Id, id);
|
||||
await ReplyConfirmLocalizedAsync(strs.crr_reset(Format.Bold(id.ToString()))).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
List<string> succ = new List<string>();
|
||||
foreach (var emojiStr in emojiStrs)
|
||||
{
|
||||
|
||||
var emote = emojiStr.ToIEmote();
|
||||
|
||||
// i should try adding these emojis right away to the message, to make sure the bot can react with these emojis. If it fails, skip that emoji
|
||||
try
|
||||
{
|
||||
await ctx.Message.AddReactionAsync(emote).ConfigureAwait(false);
|
||||
await Task.Delay(100).ConfigureAwait(false);
|
||||
succ.Add(emojiStr);
|
||||
|
||||
if (succ.Count >= 3)
|
||||
break;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
if(succ.Count == 0)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.invalid_emojis).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
await _service.SetCrReactions(ctx.Guild?.Id, id, succ);
|
||||
|
||||
|
||||
await ReplyConfirmLocalizedAsync(strs.crr_set(Format.Bold(id.ToString()), string.Join(", ", succ.Select(x => x.ToString())))).ConfigureAwait(false);
|
||||
await ReplyErrorLocalizedAsync(strs.no_found_id).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
public async Task CrReact(kwum id, params string[] emojiStrs)
|
||||
{
|
||||
if (!AdminInGuildOrOwnerInDm())
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.insuff_perms).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
public Task CrCa(kwum id)
|
||||
=> InternalCrEdit(id, CustomReactionsService.CrField.ContainsAnywhere);
|
||||
var cr = _service.GetCustomReaction(ctx.Guild?.Id, id);
|
||||
if (cr is null)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.no_found).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
public Task CrDm(kwum id)
|
||||
=> InternalCrEdit(id, CustomReactionsService.CrField.DmResponse);
|
||||
if (emojiStrs.Length == 0)
|
||||
{
|
||||
await _service.ResetCrReactions(ctx.Guild?.Id, id);
|
||||
await ReplyConfirmLocalizedAsync(strs.crr_reset(Format.Bold(id.ToString()))).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
public Task CrAd(kwum id)
|
||||
=> InternalCrEdit(id, CustomReactionsService.CrField.AutoDelete);
|
||||
List<string> succ = new List<string>();
|
||||
foreach (var emojiStr in emojiStrs)
|
||||
{
|
||||
|
||||
var emote = emojiStr.ToIEmote();
|
||||
|
||||
// i should try adding these emojis right away to the message, to make sure the bot can react with these emojis. If it fails, skip that emoji
|
||||
try
|
||||
{
|
||||
await ctx.Message.AddReactionAsync(emote).ConfigureAwait(false);
|
||||
await Task.Delay(100).ConfigureAwait(false);
|
||||
succ.Add(emojiStr);
|
||||
|
||||
if (succ.Count >= 3)
|
||||
break;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
if(succ.Count == 0)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.invalid_emojis).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
await _service.SetCrReactions(ctx.Guild?.Id, id, succ);
|
||||
|
||||
|
||||
await ReplyConfirmLocalizedAsync(strs.crr_set(Format.Bold(id.ToString()), string.Join(", ", succ.Select(x => x.ToString())))).ConfigureAwait(false);
|
||||
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
public Task CrCa(kwum id)
|
||||
=> InternalCrEdit(id, CustomReactionsService.CrField.ContainsAnywhere);
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
public Task CrDm(kwum id)
|
||||
=> InternalCrEdit(id, CustomReactionsService.CrField.DmResponse);
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
public Task CrAd(kwum id)
|
||||
=> InternalCrEdit(id, CustomReactionsService.CrField.AutoDelete);
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
public Task CrAt(kwum id)
|
||||
=> InternalCrEdit(id, CustomReactionsService.CrField.AllowTarget);
|
||||
[NadekoCommand, Aliases]
|
||||
public Task CrAt(kwum id)
|
||||
=> InternalCrEdit(id, CustomReactionsService.CrField.AllowTarget);
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task CrsReload()
|
||||
[NadekoCommand, Aliases]
|
||||
[OwnerOnly]
|
||||
public async Task CrsReload()
|
||||
{
|
||||
await _service.TriggerReloadCustomReactions();
|
||||
|
||||
await ctx.OkAsync();
|
||||
}
|
||||
|
||||
private async Task InternalCrEdit(kwum id, CustomReactionsService.CrField option)
|
||||
{
|
||||
var cr = _service.GetCustomReaction(ctx.Guild?.Id, id);
|
||||
if (!AdminInGuildOrOwnerInDm())
|
||||
{
|
||||
await _service.TriggerReloadCustomReactions();
|
||||
|
||||
await ctx.OkAsync();
|
||||
await ReplyErrorLocalizedAsync(strs.insuff_perms).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var (success, newVal) = await _service.ToggleCrOptionAsync(id, option).ConfigureAwait(false);
|
||||
if (!success)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.no_found_id).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
private async Task InternalCrEdit(kwum id, CustomReactionsService.CrField option)
|
||||
if (newVal)
|
||||
{
|
||||
var cr = _service.GetCustomReaction(ctx.Guild?.Id, id);
|
||||
if (!AdminInGuildOrOwnerInDm())
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.insuff_perms).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var (success, newVal) = await _service.ToggleCrOptionAsync(id, option).ConfigureAwait(false);
|
||||
if (!success)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.no_found_id).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (newVal)
|
||||
{
|
||||
await ReplyConfirmLocalizedAsync(strs.option_enabled(Format.Code(option.ToString()), Format.Code(id.ToString()))).ConfigureAwait(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
await ReplyConfirmLocalizedAsync(strs.option_disabled(Format.Code(option.ToString()), Format.Code(id.ToString()))).ConfigureAwait(false);
|
||||
}
|
||||
await ReplyConfirmLocalizedAsync(strs.option_enabled(Format.Code(option.ToString()), Format.Code(id.ToString()))).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
public async Task CrClear()
|
||||
else
|
||||
{
|
||||
if (await PromptUserConfirmAsync(_eb.Create()
|
||||
await ReplyConfirmLocalizedAsync(strs.option_disabled(Format.Code(option.ToString()), Format.Code(id.ToString()))).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[UserPerm(GuildPerm.Administrator)]
|
||||
public async Task CrClear()
|
||||
{
|
||||
if (await PromptUserConfirmAsync(_eb.Create()
|
||||
.WithTitle("Custom reaction clear")
|
||||
.WithDescription("This will delete all custom reactions on this server.")).ConfigureAwait(false))
|
||||
{
|
||||
var count = _service.DeleteAllCustomReactions(ctx.Guild.Id);
|
||||
await ReplyConfirmLocalizedAsync(strs.cleared(count));
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
public async Task CrsExport()
|
||||
{
|
||||
if (!AdminInGuildOrOwnerInDm())
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.insuff_perms).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
_ = ctx.Channel.TriggerTypingAsync();
|
||||
|
||||
var serialized = _service.ExportCrs(ctx.Guild?.Id);
|
||||
await using var stream = await serialized.ToStream();
|
||||
await ctx.Channel.SendFileAsync(stream, "crs-export.yml", text: null);
|
||||
var count = _service.DeleteAllCustomReactions(ctx.Guild.Id);
|
||||
await ReplyConfirmLocalizedAsync(strs.cleared(count));
|
||||
}
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
[NadekoCommand, Aliases]
|
||||
public async Task CrsExport()
|
||||
{
|
||||
if (!AdminInGuildOrOwnerInDm())
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.insuff_perms).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
_ = ctx.Channel.TriggerTypingAsync();
|
||||
|
||||
var serialized = _service.ExportCrs(ctx.Guild?.Id);
|
||||
await using var stream = await serialized.ToStream();
|
||||
await ctx.Channel.SendFileAsync(stream, "crs-export.yml", text: null);
|
||||
}
|
||||
|
||||
[NadekoCommand, Aliases]
|
||||
#if GLOBAL_NADEKO
|
||||
[OwnerOnly]
|
||||
#endif
|
||||
public async Task CrsImport([Leftover]string input = null)
|
||||
public async Task CrsImport([Leftover]string input = null)
|
||||
{
|
||||
if (!AdminInGuildOrOwnerInDm())
|
||||
{
|
||||
if (!AdminInGuildOrOwnerInDm())
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.insuff_perms).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
input = input?.Trim();
|
||||
|
||||
_ = ctx.Channel.TriggerTypingAsync();
|
||||
|
||||
if (input is null)
|
||||
{
|
||||
var attachment = ctx.Message.Attachments.FirstOrDefault();
|
||||
if (attachment is null)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.expr_import_no_input);
|
||||
return;
|
||||
}
|
||||
|
||||
using var client = _clientFactory.CreateClient();
|
||||
input = await client.GetStringAsync(attachment.Url);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(input))
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.expr_import_no_input);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var succ = await _service.ImportCrsAsync(ctx.Guild?.Id, input);
|
||||
if (!succ)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.expr_import_invalid_data);
|
||||
return;
|
||||
}
|
||||
|
||||
await ctx.OkAsync();
|
||||
await ReplyErrorLocalizedAsync(strs.insuff_perms).ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
||||
input = input?.Trim();
|
||||
|
||||
_ = ctx.Channel.TriggerTypingAsync();
|
||||
|
||||
if (input is null)
|
||||
{
|
||||
var attachment = ctx.Message.Attachments.FirstOrDefault();
|
||||
if (attachment is null)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.expr_import_no_input);
|
||||
return;
|
||||
}
|
||||
|
||||
using var client = _clientFactory.CreateClient();
|
||||
input = await client.GetStringAsync(attachment.Url);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(input))
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.expr_import_no_input);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var succ = await _service.ImportCrsAsync(ctx.Guild?.Id, input);
|
||||
if (!succ)
|
||||
{
|
||||
await ReplyErrorLocalizedAsync(strs.expr_import_invalid_data);
|
||||
return;
|
||||
}
|
||||
|
||||
await ctx.OkAsync();
|
||||
}
|
||||
}
|
||||
}
|
@@ -3,94 +3,92 @@ using Discord.WebSocket;
|
||||
using NadekoBot.Common.Replacements;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NadekoBot.Extensions;
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.CustomReactions.Extensions
|
||||
namespace NadekoBot.Modules.CustomReactions.Extensions;
|
||||
|
||||
public static class CustomReactionExtensions
|
||||
{
|
||||
public static class CustomReactionExtensions
|
||||
private static string ResolveTriggerString(this string str, DiscordSocketClient client)
|
||||
=> str.Replace("%bot.mention%", client.CurrentUser.Mention, StringComparison.Ordinal);
|
||||
|
||||
public static async Task<IUserMessage> Send(this CustomReaction cr, IUserMessage ctx,
|
||||
DiscordSocketClient client, bool sanitize)
|
||||
{
|
||||
private static string ResolveTriggerString(this string str, DiscordSocketClient client)
|
||||
=> str.Replace("%bot.mention%", client.CurrentUser.Mention, StringComparison.Ordinal);
|
||||
var channel = cr.DmResponse
|
||||
? await ctx.Author.GetOrCreateDMChannelAsync().ConfigureAwait(false)
|
||||
: ctx.Channel;
|
||||
|
||||
public static async Task<IUserMessage> Send(this CustomReaction cr, IUserMessage ctx,
|
||||
DiscordSocketClient client, bool sanitize)
|
||||
var trigger = cr.Trigger.ResolveTriggerString(client);
|
||||
var substringIndex = trigger.Length;
|
||||
if (cr.ContainsAnywhere)
|
||||
{
|
||||
var channel = cr.DmResponse
|
||||
? await ctx.Author.GetOrCreateDMChannelAsync().ConfigureAwait(false)
|
||||
: ctx.Channel;
|
||||
|
||||
var trigger = cr.Trigger.ResolveTriggerString(client);
|
||||
var substringIndex = trigger.Length;
|
||||
if (cr.ContainsAnywhere)
|
||||
{
|
||||
var pos = ctx.Content.AsSpan().GetWordPosition(trigger);
|
||||
if (pos == WordPosition.Start)
|
||||
substringIndex += 1;
|
||||
else if (pos == WordPosition.End)
|
||||
substringIndex = ctx.Content.Length;
|
||||
else if (pos == WordPosition.Middle)
|
||||
substringIndex += ctx.Content.IndexOf(trigger, StringComparison.InvariantCulture);
|
||||
}
|
||||
|
||||
var canMentionEveryone = (ctx.Author as IGuildUser)?.GuildPermissions.MentionEveryone ?? true;
|
||||
|
||||
var rep = new ReplacementBuilder()
|
||||
.WithDefault(ctx.Author, ctx.Channel, (ctx.Channel as ITextChannel)?.Guild as SocketGuild, client)
|
||||
.WithOverride("%target%", () => canMentionEveryone
|
||||
? ctx.Content.Substring(substringIndex).Trim()
|
||||
: ctx.Content.Substring(substringIndex).Trim().SanitizeMentions(true))
|
||||
.Build();
|
||||
|
||||
var text = SmartText.CreateFrom(cr.Response);
|
||||
text = rep.Replace(text);
|
||||
|
||||
return await channel.SendAsync(text, sanitize);
|
||||
var pos = ctx.Content.AsSpan().GetWordPosition(trigger);
|
||||
if (pos == WordPosition.Start)
|
||||
substringIndex += 1;
|
||||
else if (pos == WordPosition.End)
|
||||
substringIndex = ctx.Content.Length;
|
||||
else if (pos == WordPosition.Middle)
|
||||
substringIndex += ctx.Content.IndexOf(trigger, StringComparison.InvariantCulture);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static WordPosition GetWordPosition(this ReadOnlySpan<char> str, in ReadOnlySpan<char> word)
|
||||
{
|
||||
var wordIndex = str.IndexOf(word, StringComparison.OrdinalIgnoreCase);
|
||||
if (wordIndex == -1)
|
||||
return WordPosition.None;
|
||||
var canMentionEveryone = (ctx.Author as IGuildUser)?.GuildPermissions.MentionEveryone ?? true;
|
||||
|
||||
if (wordIndex == 0)
|
||||
{
|
||||
if (word.Length < str.Length && str.isValidWordDivider(word.Length))
|
||||
return WordPosition.Start;
|
||||
}
|
||||
else if ((wordIndex + word.Length) == str.Length)
|
||||
{
|
||||
if (str.isValidWordDivider(wordIndex - 1))
|
||||
return WordPosition.End;
|
||||
}
|
||||
else if (str.isValidWordDivider(wordIndex - 1) && str.isValidWordDivider(wordIndex + word.Length))
|
||||
return WordPosition.Middle;
|
||||
var rep = new ReplacementBuilder()
|
||||
.WithDefault(ctx.Author, ctx.Channel, (ctx.Channel as ITextChannel)?.Guild as SocketGuild, client)
|
||||
.WithOverride("%target%", () => canMentionEveryone
|
||||
? ctx.Content.Substring(substringIndex).Trim()
|
||||
: ctx.Content.Substring(substringIndex).Trim().SanitizeMentions(true))
|
||||
.Build();
|
||||
|
||||
var text = SmartText.CreateFrom(cr.Response);
|
||||
text = rep.Replace(text);
|
||||
|
||||
return await channel.SendAsync(text, sanitize);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static WordPosition GetWordPosition(this ReadOnlySpan<char> str, in ReadOnlySpan<char> word)
|
||||
{
|
||||
var wordIndex = str.IndexOf(word, StringComparison.OrdinalIgnoreCase);
|
||||
if (wordIndex == -1)
|
||||
return WordPosition.None;
|
||||
}
|
||||
|
||||
private static bool isValidWordDivider(this in ReadOnlySpan<char> str, int index)
|
||||
if (wordIndex == 0)
|
||||
{
|
||||
var ch = str[index];
|
||||
if (ch >= 'a' && ch <= 'z')
|
||||
return false;
|
||||
if (ch >= 'A' && ch <= 'Z')
|
||||
return false;
|
||||
if (ch >= '1' && ch <= '9')
|
||||
return false;
|
||||
|
||||
return true;
|
||||
if (word.Length < str.Length && str.isValidWordDivider(word.Length))
|
||||
return WordPosition.Start;
|
||||
}
|
||||
else if ((wordIndex + word.Length) == str.Length)
|
||||
{
|
||||
if (str.isValidWordDivider(wordIndex - 1))
|
||||
return WordPosition.End;
|
||||
}
|
||||
else if (str.isValidWordDivider(wordIndex - 1) && str.isValidWordDivider(wordIndex + word.Length))
|
||||
return WordPosition.Middle;
|
||||
|
||||
return WordPosition.None;
|
||||
}
|
||||
|
||||
public enum WordPosition
|
||||
private static bool isValidWordDivider(this in ReadOnlySpan<char> str, int index)
|
||||
{
|
||||
None,
|
||||
Start,
|
||||
Middle,
|
||||
End,
|
||||
var ch = str[index];
|
||||
if (ch >= 'a' && ch <= 'z')
|
||||
return false;
|
||||
if (ch >= 'A' && ch <= 'Z')
|
||||
return false;
|
||||
if (ch >= '1' && ch <= '9')
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public enum WordPosition
|
||||
{
|
||||
None,
|
||||
Start,
|
||||
Middle,
|
||||
End,
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user