mirror of
https://github.com/TeamOctolings/Octobot.git
synced 2025-04-20 00:43:36 +03:00
Add /ban command v1
Signed-off-by: Octol1ttle <l1ttleofficial@outlook.com>
This commit is contained in:
parent
a83aa03cf0
commit
806746925e
10 changed files with 275 additions and 81 deletions
26
Boyfriend.cs
26
Boyfriend.cs
|
@ -1,8 +1,11 @@
|
|||
using Boyfriend.Data.Services;
|
||||
using Boyfriend.Commands;
|
||||
using Boyfriend.Services;
|
||||
using Boyfriend.Services.Data;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Remora.Commands.Extensions;
|
||||
using Remora.Discord.API.Abstractions.Gateway.Commands;
|
||||
using Remora.Discord.API.Abstractions.Objects;
|
||||
using Remora.Discord.API.Gateway.Commands;
|
||||
|
@ -26,16 +29,10 @@ public class Boyfriend {
|
|||
public static async Task Main(string[] args) {
|
||||
var host = CreateHostBuilder(args).UseConsoleLifetime().Build();
|
||||
var services = host.Services;
|
||||
var configuration = services.GetRequiredService<IConfiguration>();
|
||||
|
||||
|
||||
|
||||
|
||||
var slashService = services.GetRequiredService<SlashService>();
|
||||
var updateSlash = await slashService.UpdateSlashCommandsAsync(new Snowflake(1115043975573811250));
|
||||
if (!updateSlash.IsSuccess) {
|
||||
Console.WriteLine("Failed to update slash commands: {Reason}", updateSlash.Error.Message);
|
||||
}
|
||||
_ = await slashService.UpdateSlashCommandsAsync();
|
||||
|
||||
await host.RunAsync();
|
||||
}
|
||||
|
||||
|
@ -71,10 +68,13 @@ public class Boyfriend {
|
|||
|
||||
services.AddTransient<IConfigurationBuilder, ConfigurationBuilder>()
|
||||
.AddDiscordCaching()
|
||||
.AddDiscordCommands()
|
||||
.AddDiscordCommands(true)
|
||||
.AddInteractivity()
|
||||
.AddInteractionGroup<InteractionResponders>()
|
||||
.AddSingleton<GuildDataService>();
|
||||
.AddSingleton<GuildDataService>()
|
||||
.AddSingleton<UtilityService>()
|
||||
.AddCommandTree()
|
||||
.WithCommandGroup<BanCommand>();
|
||||
var responderTypes = typeof(Boyfriend).Assembly
|
||||
.GetExportedTypes()
|
||||
.Where(t => t.IsResponder());
|
||||
|
@ -86,8 +86,4 @@ public class Boyfriend {
|
|||
.AddFilter("System.Net.Http.HttpClient.*.ClientHandler", LogLevel.Warning)
|
||||
);
|
||||
}
|
||||
|
||||
public static string GetLocalized(string key) {
|
||||
return Messages.ResourceManager.GetString(key, Messages.Culture) ?? key;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,36 +1,123 @@
|
|||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using Boyfriend.Services;
|
||||
using Boyfriend.Services.Data;
|
||||
using Remora.Commands.Attributes;
|
||||
using Remora.Commands.Groups;
|
||||
using Remora.Discord.API.Abstractions.Objects;
|
||||
using Remora.Discord.API.Gateway.Events;
|
||||
using Remora.Discord.API.Abstractions.Rest;
|
||||
using Remora.Discord.API.Objects;
|
||||
using Remora.Discord.Commands.Attributes;
|
||||
using Remora.Discord.Commands.Conditions;
|
||||
using Remora.Discord.Commands.Contexts;
|
||||
using Remora.Discord.Commands.Extensions;
|
||||
using Remora.Discord.Commands.Feedback.Services;
|
||||
using Remora.Rest.Core;
|
||||
using Remora.Discord.Extensions.Embeds;
|
||||
using Remora.Results;
|
||||
|
||||
namespace Boyfriend.Commands;
|
||||
|
||||
public class BanCommand : CommandGroup{
|
||||
public class BanCommand : CommandGroup {
|
||||
private readonly IDiscordRestChannelAPI _channelApi;
|
||||
private readonly ICommandContext _context;
|
||||
private readonly GuildDataService _dataService;
|
||||
private readonly FeedbackService _feedbackService;
|
||||
private readonly IDiscordRestGuildAPI _guildApi;
|
||||
private readonly IDiscordRestUserAPI _userApi;
|
||||
private readonly UtilityService _utility;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HttpCatCommands"/> class.
|
||||
/// </summary>
|
||||
/// <param name="feedbackService">The feedback service.</param>
|
||||
public BanCommand(FeedbackService feedbackService)
|
||||
{
|
||||
public BanCommand(
|
||||
ICommandContext context, IDiscordRestChannelAPI channelApi, GuildDataService dataService,
|
||||
FeedbackService feedbackService, IDiscordRestGuildAPI guildApi, IDiscordRestUserAPI userApi,
|
||||
UtilityService utility) {
|
||||
_context = context;
|
||||
_channelApi = channelApi;
|
||||
_dataService = dataService;
|
||||
_feedbackService = feedbackService;
|
||||
_guildApi = guildApi;
|
||||
_userApi = userApi;
|
||||
_utility = utility;
|
||||
}
|
||||
|
||||
|
||||
[Command("ban")]
|
||||
[RequireContext(ChannelContext.Guild)]
|
||||
[RequireDiscordPermission(DiscordPermission.BanMembers)]
|
||||
[RequireBotDiscordPermissions(DiscordPermission.BanMembers)]
|
||||
[Description("банит пидора")]
|
||||
public async Task<IResult> BanAsync([Description("Юзер, кого банить")] IUser user, string reason) {
|
||||
var banan = new Ban(reason, user);
|
||||
var embed = new Embed(Colour: _feedbackService.Theme.Secondary, Description: "забанен нахуй");
|
||||
public async Task<Result> BanUserAsync([Description("Юзер, кого банить")] IUser target, string reason) {
|
||||
if (!_context.TryGetGuildID(out var guildId))
|
||||
return Result.FromError(new ArgumentNullError(nameof(guildId)));
|
||||
if (!_context.TryGetUserID(out var userId))
|
||||
return Result.FromError(new ArgumentNullError(nameof(userId)));
|
||||
if (!_context.TryGetChannelID(out var channelId))
|
||||
return Result.FromError(new ArgumentNullError(nameof(channelId)));
|
||||
|
||||
return (Result)await _feedbackService.SendContextualEmbedAsync(embed, ct: this.CancellationToken);
|
||||
var currentUserResult = await _userApi.GetCurrentUserAsync(CancellationToken);
|
||||
if (!currentUserResult.IsDefined(out var currentUser))
|
||||
return Result.FromError(currentUserResult);
|
||||
|
||||
var existingBanResult = await _guildApi.GetGuildBanAsync(guildId.Value, target.ID, CancellationToken);
|
||||
if (existingBanResult.IsDefined(out _)) {
|
||||
var embed = new EmbedBuilder().WithSmallTitle(Messages.UserAlreadyBanned, currentUser)
|
||||
.WithColour(Color.Firebrick).Build();
|
||||
|
||||
if (!embed.IsDefined(out var alreadyBuilt))
|
||||
return Result.FromError(embed);
|
||||
|
||||
return (Result)await _feedbackService.SendContextualEmbedAsync(alreadyBuilt, ct: CancellationToken);
|
||||
}
|
||||
|
||||
var interactionResult
|
||||
= await _utility.CheckInteractionsAsync(guildId.Value, userId.Value, target.ID, "Ban", CancellationToken);
|
||||
if (!interactionResult.IsSuccess)
|
||||
return Result.FromError(interactionResult);
|
||||
|
||||
Result<Embed> responseEmbed;
|
||||
if (interactionResult.Entity is not null) {
|
||||
responseEmbed = new EmbedBuilder().WithSmallTitle(interactionResult.Entity, currentUser)
|
||||
.WithColour(Color.Firebrick).Build();
|
||||
} else {
|
||||
var userResult = await _userApi.GetUserAsync(userId.Value, CancellationToken);
|
||||
if (!userResult.IsDefined(out var user))
|
||||
return Result.FromError(userResult);
|
||||
|
||||
var banResult = await _guildApi.CreateGuildBanAsync(
|
||||
guildId.Value, target.ID, reason: $"({user.GetTag()}) {reason}", ct: CancellationToken);
|
||||
if (!banResult.IsSuccess)
|
||||
return Result.FromError(banResult.Error);
|
||||
|
||||
responseEmbed = new EmbedBuilder().WithSmallTitle(
|
||||
string.Format(Messages.UserBanned, target.GetTag()), target)
|
||||
.WithColour(Color.LawnGreen).Build();
|
||||
|
||||
var cfg = await _dataService.GetConfiguration(guildId.Value, CancellationToken);
|
||||
if ((cfg.PublicFeedbackChannel is not 0 && cfg.PublicFeedbackChannel != channelId.Value)
|
||||
|| (cfg.PrivateFeedbackChannel is not 0 && cfg.PrivateFeedbackChannel != channelId.Value)) {
|
||||
var logEmbed = new EmbedBuilder().WithSmallTitle(
|
||||
string.Format(Messages.UserBanned, target.GetTag()), target)
|
||||
.WithDescription(string.Format(Messages.DescriptionUserBanned, reason))
|
||||
.WithActionFooter(user)
|
||||
.WithCurrentTimestamp()
|
||||
.WithColour(Color.Firebrick)
|
||||
.Build();
|
||||
|
||||
if (!logEmbed.IsDefined(out var logBuilt))
|
||||
return Result.FromError(logEmbed);
|
||||
|
||||
var builtArray = new[] { logBuilt };
|
||||
if (cfg.PrivateFeedbackChannel != channelId.Value)
|
||||
_ = _channelApi.CreateMessageAsync(
|
||||
cfg.PrivateFeedbackChannel.ToDiscordSnowflake(), embeds: builtArray,
|
||||
ct: CancellationToken);
|
||||
if (cfg.PublicFeedbackChannel != channelId.Value)
|
||||
_ = _channelApi.CreateMessageAsync(
|
||||
cfg.PublicFeedbackChannel.ToDiscordSnowflake(), embeds: builtArray,
|
||||
ct: CancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
if (!responseEmbed.IsDefined(out var built))
|
||||
return Result.FromError(responseEmbed);
|
||||
|
||||
return (Result)await _feedbackService.SendContextualEmbedAsync(built, ct: CancellationToken);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using System.Drawing;
|
||||
using System.Text;
|
||||
using Boyfriend.Data;
|
||||
using Boyfriend.Data.Services;
|
||||
using Boyfriend.Services.Data;
|
||||
using DiffPlex;
|
||||
using DiffPlex.DiffBuilder;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
@ -56,7 +56,7 @@ public class GuildCreateResponder : IResponder<IGuildCreate> {
|
|||
var i = Random.Shared.Next(1, 4);
|
||||
|
||||
var embed = new EmbedBuilder()
|
||||
.WithTitle(Boyfriend.GetLocalized($"Beep{i}"))
|
||||
.WithTitle($"Beep{i}".Localized())
|
||||
.WithDescription(Messages.Ready)
|
||||
.WithUserFooter(currentUser)
|
||||
.WithCurrentTimestamp()
|
||||
|
@ -120,7 +120,7 @@ public class MessageDeletedResponder : IResponder<IMessageDelete> {
|
|||
$"{Mention.Channel(gatewayEvent.ChannelID)}\n{Markdown.BlockCode(message.Content.SanitizeForBlockCode())}")
|
||||
.WithActionFooter(user)
|
||||
.WithTimestamp(message.Timestamp)
|
||||
.WithColour(Color.Crimson)
|
||||
.WithColour(Color.Firebrick)
|
||||
.Build();
|
||||
if (!embed.IsDefined(out var built)) return Result.FromError(embed);
|
||||
|
||||
|
@ -153,13 +153,13 @@ public class MessageEditedResponder : IResponder<IMessageUpdate> {
|
|||
return Result.FromSuccess();
|
||||
if (!gatewayEvent.Content.IsDefined(out var newContent))
|
||||
return Result.FromSuccess();
|
||||
if (!gatewayEvent.EditedTimestamp.IsDefined(out var timestamp))
|
||||
return Result.FromSuccess();
|
||||
|
||||
if (!gatewayEvent.ChannelID.IsDefined(out var channelId))
|
||||
return Result.FromError(new ArgumentNullError(nameof(gatewayEvent.ChannelID)));
|
||||
if (!gatewayEvent.ID.IsDefined(out var messageId))
|
||||
return Result.FromError(new ArgumentNullError(nameof(gatewayEvent.ID)));
|
||||
if (!gatewayEvent.EditedTimestamp.IsDefined(out var timestamp))
|
||||
return Result.FromError(new ArgumentNullError(nameof(gatewayEvent.EditedTimestamp)));
|
||||
|
||||
var cacheKey = new KeyHelpers.MessageCacheKey(channelId, messageId);
|
||||
var messageResult = await _cacheService.TryGetValueAsync<IMessage>(
|
||||
|
@ -286,7 +286,7 @@ public class GuildScheduledEventCreateResponder : IResponder<IGuildScheduledEven
|
|||
|
||||
embedDescription = $"{eventDescription}\n\n{Markdown.BlockQuote(
|
||||
string.Format(
|
||||
Messages.LocalEventCreatedDescription,
|
||||
Messages.DescriptionLocalEventCreated,
|
||||
Markdown.Timestamp(gatewayEvent.ScheduledStartTime),
|
||||
Mention.Channel(channelId)
|
||||
))}";
|
||||
|
@ -301,7 +301,7 @@ public class GuildScheduledEventCreateResponder : IResponder<IGuildScheduledEven
|
|||
|
||||
embedDescription = $"{eventDescription}\n\n{Markdown.BlockQuote(
|
||||
string.Format(
|
||||
Messages.ExternalEventCreatedDescription,
|
||||
Messages.DescriptionExternalEventCreated,
|
||||
Markdown.Timestamp(gatewayEvent.ScheduledStartTime),
|
||||
Markdown.Timestamp(endTime),
|
||||
Markdown.InlineCode(location)
|
||||
|
@ -365,14 +365,14 @@ public class GuildScheduledEventUpdateResponder : IResponder<IGuildScheduledEven
|
|||
case GuildScheduledEventStatus.Active:
|
||||
guildData.ScheduledEvents[gatewayEvent.ID.Value].ActualStartTime = DateTimeOffset.UtcNow;
|
||||
|
||||
string embedDescription; // what the fuck is this
|
||||
string embedDescription;
|
||||
switch (gatewayEvent.EntityType) {
|
||||
case GuildScheduledEventEntityType.StageInstance or GuildScheduledEventEntityType.Voice:
|
||||
if (!gatewayEvent.ChannelID.AsOptional().IsDefined(out var channelId))
|
||||
return Result.FromError(new ArgumentNullError(nameof(gatewayEvent.ChannelID)));
|
||||
|
||||
embedDescription = string.Format(
|
||||
Messages.LocalEventStartedDescription,
|
||||
Messages.DescriptionLocalEventStarted,
|
||||
Mention.Channel(channelId)
|
||||
);
|
||||
break;
|
||||
|
@ -385,7 +385,7 @@ public class GuildScheduledEventUpdateResponder : IResponder<IGuildScheduledEven
|
|||
return Result.FromError(new ArgumentNullError(nameof(metadata.Location)));
|
||||
|
||||
embedDescription = string.Format(
|
||||
Messages.ExternalEventStartedDescription,
|
||||
Messages.DescriptionExternalEventStarted,
|
||||
Markdown.InlineCode(location),
|
||||
Markdown.Timestamp(endTime)
|
||||
);
|
||||
|
@ -462,7 +462,7 @@ public class GuildScheduledEventResponder : IResponder<IGuildScheduledEventDelet
|
|||
var embed = new EmbedBuilder()
|
||||
.WithSmallTitle(string.Format(Messages.EventCancelled, gatewayEvent.Name))
|
||||
.WithDescription(":(")
|
||||
.WithColour(Color.DarkRed)
|
||||
.WithColour(Color.Firebrick)
|
||||
.WithCurrentTimestamp()
|
||||
.Build();
|
||||
|
||||
|
|
|
@ -65,6 +65,10 @@ public static class Extensions {
|
|||
return s.Replace("```", "```");
|
||||
}
|
||||
|
||||
public static string Localized(this string key) {
|
||||
return Messages.ResourceManager.GetString(key, Messages.Culture) ?? key;
|
||||
}
|
||||
|
||||
public static string AsMarkdown(this SideBySideDiffModel model) {
|
||||
var builder = new StringBuilder();
|
||||
foreach (var line in model.OldText.Lines.Where(piece => !string.IsNullOrWhiteSpace(piece.Text)))
|
||||
|
@ -78,13 +82,13 @@ public static class Extensions {
|
|||
return $"{user.Username}#{user.Discriminator:0000}";
|
||||
}
|
||||
|
||||
|
||||
public static Snowflake ToDiscordSnowflake(this ulong id) {
|
||||
return DiscordSnowflake.New(id);
|
||||
}
|
||||
|
||||
/*public static string AsDuration(this TimeSpan span) {
|
||||
return span.Humanize(
|
||||
2, minUnit: TimeUnit.Second, maxUnit: TimeUnit.Month,
|
||||
culture: Messages.Culture.Name.Contains("RU") ? GuildConfiguration.CultureInfoCache["ru"] : Messages.Culture);
|
||||
}*/
|
||||
public static TResult? MaxOrDefault<TSource, TResult>(
|
||||
this IEnumerable<TSource> source, Func<TSource, TResult> selector) {
|
||||
return source.Any() ? source.Max(selector) : default;
|
||||
}
|
||||
}
|
||||
|
|
32
Messages.Designer.cs
generated
32
Messages.Designer.cs
generated
|
@ -243,9 +243,9 @@ namespace Boyfriend {
|
|||
}
|
||||
}
|
||||
|
||||
internal static string FeedbackUserBanned {
|
||||
internal static string UserBanned {
|
||||
get {
|
||||
return ResourceManager.GetString("FeedbackUserBanned", resourceCulture);
|
||||
return ResourceManager.GetString("UserBanned", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -771,15 +771,15 @@ namespace Boyfriend {
|
|||
}
|
||||
}
|
||||
|
||||
internal static string LocalEventCreatedDescription {
|
||||
internal static string DescriptionLocalEventCreated {
|
||||
get {
|
||||
return ResourceManager.GetString("LocalEventCreatedDescription", resourceCulture);
|
||||
return ResourceManager.GetString("DescriptionLocalEventCreated", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string ExternalEventCreatedDescription {
|
||||
internal static string DescriptionExternalEventCreated {
|
||||
get {
|
||||
return ResourceManager.GetString("ExternalEventCreatedDescription", resourceCulture);
|
||||
return ResourceManager.GetString("DescriptionExternalEventCreated", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -795,15 +795,27 @@ namespace Boyfriend {
|
|||
}
|
||||
}
|
||||
|
||||
internal static string LocalEventStartedDescription {
|
||||
internal static string DescriptionLocalEventStarted {
|
||||
get {
|
||||
return ResourceManager.GetString("LocalEventStartedDescription", resourceCulture);
|
||||
return ResourceManager.GetString("DescriptionLocalEventStarted", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string ExternalEventStartedDescription {
|
||||
internal static string DescriptionExternalEventStarted {
|
||||
get {
|
||||
return ResourceManager.GetString("ExternalEventStartedDescription", resourceCulture);
|
||||
return ResourceManager.GetString("DescriptionExternalEventStarted", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string DescriptionUserBanned {
|
||||
get {
|
||||
return ResourceManager.GetString("DescriptionUserBanned", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
internal static string UserAlreadyBanned {
|
||||
get {
|
||||
return ResourceManager.GetString("UserAlreadyBanned", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -204,9 +204,9 @@
|
|||
<data name="ClearAmountInvalid" xml:space="preserve">
|
||||
<value>You need to specify an integer from {0} to {1} instead of {2}!</value>
|
||||
</data>
|
||||
<data name="FeedbackUserBanned" xml:space="preserve">
|
||||
<value>Banned {0} for{1}: {2}</value>
|
||||
</data>
|
||||
<data name="UserBanned" xml:space="preserve">
|
||||
<value>{0} was banned</value>
|
||||
</data>
|
||||
<data name="SettingDoesntExist" xml:space="preserve">
|
||||
<value>That setting doesn't exist!</value>
|
||||
</data>
|
||||
|
@ -468,22 +468,28 @@
|
|||
<data name="EventCreatedTitle" xml:space="preserve">
|
||||
<value>{0} has created a new event:</value>
|
||||
</data>
|
||||
<data name="LocalEventCreatedDescription" xml:space="preserve">
|
||||
<data name="DescriptionLocalEventCreated" xml:space="preserve">
|
||||
<value>The event will start at {0} in {1}</value>
|
||||
</data>
|
||||
<data name="ExternalEventCreatedDescription" xml:space="preserve">
|
||||
<data name="DescriptionExternalEventCreated" xml:space="preserve">
|
||||
<value>The event will start at {0} until {1} in {2}</value>
|
||||
</data>
|
||||
<data name="EventDetailsButton" xml:space="preserve">
|
||||
<value>Event details</value>
|
||||
</data>
|
||||
<data name="EventDuration" xml:space="preserve">
|
||||
<data name="EventDuration" xml:space="preserve">
|
||||
<value>The event has lasted for `{0}`</value>
|
||||
</data>
|
||||
<data name="LocalEventStartedDescription" xml:space="preserve">
|
||||
<data name="DescriptionLocalEventStarted" xml:space="preserve">
|
||||
<value>The event is happening at {0}</value>
|
||||
</data>
|
||||
<data name="ExternalEventStartedDescription" xml:space="preserve">
|
||||
<data name="DescriptionExternalEventStarted" xml:space="preserve">
|
||||
<value>The event is happening at {0} until {1}</value>
|
||||
</data>
|
||||
<data name="DescriptionUserBanned" xml:space="preserve">
|
||||
<value>Reason: {0}</value>
|
||||
</data>
|
||||
<data name="UserAlreadyBanned" xml:space="preserve">
|
||||
<value>This user is already banned!</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
|
@ -204,9 +204,9 @@
|
|||
<data name="ClearAmountInvalid" xml:space="preserve">
|
||||
<value>Надо указать целое число от {0} до {1} вместо {2}!</value>
|
||||
</data>
|
||||
<data name="FeedbackUserBanned" xml:space="preserve">
|
||||
<value>Забанен {0} на{1}: {2}</value>
|
||||
</data>
|
||||
<data name="UserBanned" xml:space="preserve">
|
||||
<value>{0} был(-а) забанен(-а)</value>
|
||||
</data>
|
||||
<data name="SettingDoesntExist" xml:space="preserve">
|
||||
<value>Такая настройка не существует!</value>
|
||||
</data>
|
||||
|
@ -468,22 +468,28 @@
|
|||
<data name="EventCreatedTitle" xml:space="preserve">
|
||||
<value>{0} создаёт новое событие:</value>
|
||||
</data>
|
||||
<data name="LocalEventCreatedDescription" xml:space="preserve">
|
||||
<data name="DescriptionLocalEventCreated" xml:space="preserve">
|
||||
<value>Событие пройдёт {0} в канале {1}</value>
|
||||
</data>
|
||||
<data name="ExternalEventCreatedDescription" xml:space="preserve">
|
||||
<data name="DescriptionExternalEventCreated" xml:space="preserve">
|
||||
<value>Событие пройдёт с {0} до {1} в {2}</value>
|
||||
</data>
|
||||
<data name="EventDetailsButton" xml:space="preserve">
|
||||
<value>Подробнее о событии</value>
|
||||
</data>
|
||||
<data name="EventDuration" xml:space="preserve">
|
||||
<data name="EventDuration" xml:space="preserve">
|
||||
<value>Событие длилось `{0}`</value>
|
||||
</data>
|
||||
<data name="LocalEventStartedDescription" xml:space="preserve">
|
||||
<data name="DescriptionLocalEventStarted" xml:space="preserve">
|
||||
<value>Событие происходит в {0}</value>
|
||||
</data>
|
||||
<data name="ExternalEventStartedDescription" xml:space="preserve">
|
||||
<data name="DescriptionExternalEventStarted" xml:space="preserve">
|
||||
<value>Событие происходит в {0} до {1}</value>
|
||||
</data>
|
||||
<data name="DescriptionUserBanned" xml:space="preserve">
|
||||
<value>Причина: {0}</value>
|
||||
</data>
|
||||
<data name="UserAlreadyBanned" xml:space="preserve">
|
||||
<value>Этот пользователь уже забанен!</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
|
@ -204,9 +204,9 @@
|
|||
<data name="ClearAmountInvalid" xml:space="preserve">
|
||||
<value>выбери число от {0} до {1} вместо {2}!</value>
|
||||
</data>
|
||||
<data name="FeedbackUserBanned" xml:space="preserve">
|
||||
<value>забанен {0} на{1}: {2}</value>
|
||||
</data>
|
||||
<data name="UserBanned" xml:space="preserve">
|
||||
<value>{0} забанен</value>
|
||||
</data>
|
||||
<data name="SettingDoesntExist" xml:space="preserve">
|
||||
<value>такой прикол не существует</value>
|
||||
</data>
|
||||
|
@ -468,22 +468,28 @@
|
|||
<data name="EventCreatedTitle" xml:space="preserve">
|
||||
<value>{0} создает новое событие:</value>
|
||||
</data>
|
||||
<data name="LocalEventCreatedDescription" xml:space="preserve">
|
||||
<data name="DescriptionLocalEventCreated" xml:space="preserve">
|
||||
<value>движуха произойдет {0} в канале {1}</value>
|
||||
</data>
|
||||
<data name="ExternalEventCreatedDescription" xml:space="preserve">
|
||||
<data name="DescriptionExternalEventCreated" xml:space="preserve">
|
||||
<value>движуха будет происходить с {0} до {1} в {2}</value>
|
||||
</data>
|
||||
<data name="EventDetailsButton" xml:space="preserve">
|
||||
<value>побольше о движухе</value>
|
||||
</data>
|
||||
<data name="EventDuration" xml:space="preserve">
|
||||
<data name="EventDuration" xml:space="preserve">
|
||||
<value>все это длилось `{0}`</value>
|
||||
</data>
|
||||
<data name="LocalEventStartedDescription" xml:space="preserve">
|
||||
<data name="DescriptionLocalEventStarted" xml:space="preserve">
|
||||
<value>движуха происходит в {0}</value>
|
||||
</data>
|
||||
<data name="ExternalEventStartedDescription" xml:space="preserve">
|
||||
<data name="DescriptionExternalEventStarted" xml:space="preserve">
|
||||
<value>движуха происходит в {0} до {1}</value>
|
||||
</data>
|
||||
<data name="DescriptionUserBanned" xml:space="preserve">
|
||||
<value>причина: {0}</value>
|
||||
</data>
|
||||
<data name="UserAlreadyBanned" xml:space="preserve">
|
||||
<value>этот шизоид уже лежит в бане</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
using System.Text.Json;
|
||||
using Boyfriend.Data;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Remora.Rest.Core;
|
||||
|
||||
namespace Boyfriend.Data.Services;
|
||||
namespace Boyfriend.Services.Data;
|
||||
|
||||
public class GuildDataService : IHostedService {
|
||||
private readonly Dictionary<Snowflake, GuildData> _datas = new();
|
76
Services/UtilityService.cs
Normal file
76
Services/UtilityService.cs
Normal file
|
@ -0,0 +1,76 @@
|
|||
using Microsoft.Extensions.Hosting;
|
||||
using Remora.Discord.API.Abstractions.Rest;
|
||||
using Remora.Rest.Core;
|
||||
using Remora.Results;
|
||||
|
||||
namespace Boyfriend.Services;
|
||||
|
||||
public class UtilityService : IHostedService {
|
||||
private readonly IDiscordRestGuildAPI _guildApi;
|
||||
private readonly IDiscordRestUserAPI _userApi;
|
||||
|
||||
public UtilityService(IDiscordRestGuildAPI guildApi, IDiscordRestUserAPI userApi) {
|
||||
_guildApi = guildApi;
|
||||
_userApi = userApi;
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken ct) {
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken ct) {
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task<Result<string?>> CheckInteractionsAsync(
|
||||
Snowflake guildId, Snowflake interacterId, Snowflake targetId, string action, CancellationToken ct = default) {
|
||||
if (interacterId == targetId)
|
||||
return Result<string?>.FromSuccess($"UserCannot{action}Themselves".Localized());
|
||||
|
||||
var guildResult = await _guildApi.GetGuildAsync(guildId, ct: ct);
|
||||
if (!guildResult.IsDefined(out var guild))
|
||||
return Result<string?>.FromError(guildResult);
|
||||
|
||||
if (targetId == guild.OwnerID) return Result<string?>.FromSuccess($"UserCannot{action}Owner".Localized());
|
||||
|
||||
var currentUserResult = await _userApi.GetCurrentUserAsync(ct);
|
||||
if (!currentUserResult.IsDefined(out var currentUser))
|
||||
return Result<string?>.FromError(currentUserResult);
|
||||
|
||||
if (currentUser.ID == targetId)
|
||||
return Result<string?>.FromSuccess($"UserCannot{action}Bot".Localized());
|
||||
|
||||
if (interacterId == guild.OwnerID) return Result<string?>.FromSuccess(null);
|
||||
|
||||
var targetMemberResult = await _guildApi.GetGuildMemberAsync(guildId, targetId, ct);
|
||||
if (!targetMemberResult.IsDefined(out var targetMember))
|
||||
return Result<string?>.FromSuccess(null);
|
||||
|
||||
var currentMemberResult = await _guildApi.GetGuildMemberAsync(guildId, currentUser.ID, ct);
|
||||
if (!currentMemberResult.IsDefined(out var currentMember))
|
||||
return Result<string?>.FromError(currentMemberResult);
|
||||
|
||||
var rolesResult = await _guildApi.GetGuildRolesAsync(guildId, ct);
|
||||
if (!rolesResult.IsDefined(out var roles))
|
||||
return Result<string?>.FromError(rolesResult);
|
||||
|
||||
var interacterResult = await _guildApi.GetGuildMemberAsync(guildId, interacterId, ct);
|
||||
if (!interacterResult.IsDefined(out var interacter))
|
||||
return Result<string?>.FromError(interacterResult);
|
||||
|
||||
var targetRoles = roles.Where(r => targetMember.Roles.Contains(r.ID));
|
||||
var interacterRoles = roles.Where(r => interacter.Roles.Contains(r.ID));
|
||||
var botRoles = roles.Where(r => currentMember.Roles.Contains(r.ID));
|
||||
|
||||
var targetBotRoleDiff = targetRoles.MaxOrDefault(r => r.Position) - botRoles.Max(r => r.Position);
|
||||
var targetInteracterRoleDiff = targetRoles.MaxOrDefault(r => r.Position) - interacterRoles.Max(r => r.Position);
|
||||
|
||||
if (targetInteracterRoleDiff >= 0)
|
||||
return Result<string?>.FromSuccess($"UserCannot{action}Target".Localized());
|
||||
|
||||
if (targetBotRoleDiff >= 0)
|
||||
return Result<string?>.FromSuccess($"BotCannot{action}Target".Localized());
|
||||
|
||||
return Result<string?>.FromSuccess(null);
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue