public async ValueTask <AdminCommandResult> EditMessageAsync(CachedTextChannel channel, ulong messageId,
                                                                     [Remainder] string text)
        {
            if (!(await channel.GetMessageAsync(messageId) is RestUserMessage message))
            {
                return(CommandErrorLocalized("utility_edit_nomessage"));
            }

            if (message.Author.Id != Context.Client.CurrentUser.Id)
            {
                return(CommandErrorLocalized("utility_edit_nonowner"));
            }

            text = await text.FormatPlaceHoldersAsync(Context, random : Random);

            await message.ModifyAsync(x =>
            {
                if (JsonEmbed.TryParse(text, out var embed))
                {
                    x.Content = embed.Text;
                    x.Embed   = embed.ToLocalEmbed();
                    return;
                }

                x.Content = text;
            });

            await Context.Message.AddReactionAsync(EmojiTools.Checkmark);

            return(CommandSuccess());
        }
Exemple #2
0
 public async ValueTask <AdminCommandResult> SetSuggestionChannel(CachedTextChannel newChannel)
 {
     if (await Context.Database.LoggingChannels.FindAsync(Context.Guild.Id.RawValue, LogType.Suggestion) is { } channel)
     {
         channel.Id = newChannel.Id;
         Context.Database.LoggingChannels.Update(channel);
     }
Exemple #3
0
 public override DiscordCommandContext CreateCommandContext(
     IPrefix prefix,
     string input,
     IGatewayUserMessage message,
     CachedTextChannel channel)
 {
     return(new MilkmanCommandContext(message, input, this, prefix));
 }
        public async Task SignupChannelAsync(CachedTextChannel channel = null)
        {
            ulong?channelId = DbContext.Guild.RaidSignupChannelId;

            if (channel is null && channelId is null)
            {
                await ReplyAsync("No raid signup channel exists.");
            }
Exemple #5
0
 public async ValueTask <AdminCommandResult> SetChannelAsync(CachedTextChannel newChannel)
 {
     if (!(await Context.Database.LoggingChannels.FindAsync(Context.Guild.Id.RawValue, LogType.Greeting)
           is { } channel))
     {
         Context.Database.LoggingChannels.Add(new LoggingChannel(newChannel.Id, Context.Guild.Id,
                                                                 LogType.Greeting));
     }
 internal ReactionsClearedEventArgs(
     CachedTextChannel channel,
     FetchableSnowflakeOptional <IMessage> message,
     IReadOnlyDictionary <IEmoji, ReactionData> reactions) : base(channel.Client)
 {
     Channel   = channel;
     Message   = message;
     Reactions = reactions;
 }
        public async ValueTask <AdminCommandResult> DeconstructMessageAsync(CachedTextChannel channel, ulong messageId)
        {
            if (!(await channel.GetMessageAsync(messageId) is RestUserMessage message))
            {
                return(CommandErrorLocalized("utility_deconstruct_nomessage"));
            }

            return(await DeconstructMessageAsync(message));
        }
Exemple #8
0
 internal EmojiReactionsClearedEventArgs(
     CachedTextChannel channel,
     FetchableSnowflakeOptional <IMessage> message,
     IEmoji emoji,
     ReactionData data) : base(channel.Client)
 {
     Channel = channel;
     Message = message;
     Emoji   = emoji;
     Data    = data;
 }
 public EspeonCommandContext(IServiceScope scope, EspeonBot bot, IPrefix prefix, CachedUserMessage message)
     : base(bot, prefix, message, scope.ServiceProvider)
 {
     if (!(message.Author is CachedMember member && message.Channel is CachedTextChannel channel))
     {
         throw new InvalidOperationException("Bot should not be used in dms");
     }
     ServiceScope = scope;
     Bot          = bot;
     Member       = member;
     Channel      = channel;
 }
Exemple #10
0
        public async Task HandleAsync(MemberUpdatedEventArgs args)
        {
            var oldMember = args.OldMember;
            var newMember = args.NewMember;

            using var ctx = new AdminDatabaseContext(_provider);
            var language = (await ctx.GetOrCreateGuildAsync(args.NewMember.Guild.Id)).Language;
            var builder  = new LocalEmbedBuilder()
                           .WithSuccessColor()
                           .WithDescription(newMember.Format(false))
                           .WithTimestamp(DateTimeOffset.UtcNow);

            CachedTextChannel channel = null;

            // nickname
            if (!(newMember.Nick ?? string.Empty).Equals(oldMember.Nick ?? string.Empty,
                                                         StringComparison.OrdinalIgnoreCase))
            {
                channel = await ctx.GetLoggingChannelAsync(oldMember.Guild.Id, LogType.NicknameUpdate);

                builder.WithTitle(_localization.Localize(language, "logging_member_nickname"))
                .AddField(_localization.Localize(language, "logging_member_prevnick"),
                          oldMember.Nick?.Sanitize() ??
                          Markdown.Italics(_localization.Localize(language, "logging_member_noprevnick")))
                .AddField(_localization.Localize(language, "logging_member_newnick"),
                          newMember.Nick?.Sanitize() ??
                          Markdown.Italics(_localization.Localize(language, "logging_member_nonewnick")));
            }
            // role update
            else if (newMember.Roles.Count != oldMember.Roles.Count)
            {
                channel = await ctx.GetLoggingChannelAsync(oldMember.Guild.Id, LogType.UserRoleUpdate);

                var removedRoles = oldMember.Roles.Values.Where(x => !newMember.Roles.ContainsKey(x.Id)).ToList();
                var addedRoles   = newMember.Roles.Values.Where(x => !oldMember.Roles.ContainsKey(x.Id)).ToList();

                builder.WithTitle(_localization.Localize(language, "logging_member_roleupdate"));

                if (addedRoles.Count > 0)
                {
                    builder.AddField(_localization.Localize(language, "logging_member_addedroles"),
                                     string.Join('\n', addedRoles.Select(x => x.Format(false))));
                }

                if (removedRoles.Count > 0)
                {
                    builder.AddField(_localization.Localize(language, "logging_member_removedroles"),
                                     string.Join('\n', removedRoles.Select(x => x.Format(false))));
                }
            }

            if (channel is { })
            public async Task DeleteTextChannelAsync([Remainder] CachedTextChannel channel)
            {
                if (!ChannelExtensions.CheckViewChannelPermission(Context.CurrentMember !, channel))
                {
                    await ReplyErrorAsync(Localization.AdministrationTextChannelNoViewPermission);

                    return;
                }

                await channel.DeleteAsync();

                if (channel.Id != Context.Channel.Id)
                {
                    await ReplyConfirmationAsync(Localization.AdministrationTextChannelDeleted, channel.Name);
                }
            }
        public async ValueTask <AdminCommandResult> SendMessageAsync(CachedTextChannel channel, [Remainder] string text = null)
        {
            if (string.IsNullOrWhiteSpace(text) && Context.Message.Attachments.Count == 0)
            {
                return(CommandErrorLocalized("utility_send_empty"));
            }

            if (!string.IsNullOrWhiteSpace(text))
            {
                text = await text.FormatPlaceHoldersAsync(Context, random : Random);
            }

            var file     = new MemoryStream();
            var filename = string.Empty;

            if (Context.Message.Attachments.FirstOrDefault() is { } attachment)
            {
                await using var stream = await Http.GetStreamAsync(attachment.Url);

                await stream.CopyToAsync(file);

                file.Seek(0, SeekOrigin.Begin);
                filename = attachment.FileName;
            }

            if (JsonEmbed.TryParse(text, out var embed))
            {
                await channel.SendMessageAsync(
                    !string.IsNullOrWhiteSpace(filename)?new LocalAttachment(file, filename) : null, embed.Text,
                    embed : embed.ToLocalEmbed());

                return(CommandSuccess());
            }

            if (!string.IsNullOrWhiteSpace(filename))
            {
                await channel.SendMessageAsync(new LocalAttachment(file, filename), text);
            }
            else
            {
                await channel.SendMessageAsync(text);
            }
            return(CommandSuccess());
        }
        public override ValueTask <ChannelPinsUpdatedEventArgs> HandleDispatchAsync(IGatewayApiClient shard, ChannelPinsUpdateJsonModel model)
        {
            CachedTextChannel channel = null;

            if (model.GuildId.HasValue)
            {
                if (CacheProvider.TryGetChannels(model.GuildId.Value, out var cache))
                {
                    channel = cache.GetValueOrDefault(model.ChannelId) as CachedTextChannel;
                    if (channel != null)
                    {
                        channel.LastPinTimestamp = model.LastPinTimestamp.GetValueOrDefault();
                    }
                }
            }

            var e = new ChannelPinsUpdatedEventArgs(model.GuildId.GetValueOrNullable(), model.ChannelId, channel);

            return(new(e));
        }
        public async ValueTask <AdminCommandResult> AddReactionRoleAsync(CachedTextChannel channel, ulong messageId,
                                                                         [RequireUsableEmoji] IEmoji emoji, [Remainder, RequireHierarchy] CachedRole role)
        {
            var guild = await Context.Database.GetOrCreateGuildAsync(Context.Guild.Id);

            if (await Context.Database.ReactionRoles.CountAsync(x => x.GuildId == guild.Id) >=
                guild.MaximumReactionRoles)
            {
                return(CommandErrorLocalized("reactionrole_add_maximum", args: guild.MaximumReactionRoles));
            }

            var id = 0;

            if (await Context.Database.ReactionRoles.FirstOrDefaultAsync(x =>
                                                                         x.MessageId == messageId && x.Emoji.Equals(emoji)) is { } reactionRole)
            {
                reactionRole.RoleId = role.Id;
                Context.Database.ReactionRoles.Update(reactionRole);
                await Context.Database.SaveChangesAsync();

                id = reactionRole.Id;
            }
Exemple #15
0
        public override ValueTask <CheckResult> CheckAsync(DiscordGuildCommandContext context)
        {
            if (context.Channel is null)
            {
                throw new InvalidOperationException($"{nameof(RequireNsfwAttribute)} requires the context channel.");
            }

            var isNsfw = context.Channel switch
            {
                CachedTextChannel textChannel => textChannel.IsNsfw,
                CachedThreadChannel threadChannel => threadChannel.GetChannel()?.IsNsfw ?? false,
                _ => false
            };

            if (isNsfw)
            {
                return(Success());
            }

            return(Failure("This can only be executed in a NSFW channel."));
        }
    }
        public AdminCommandResult GetChannelInfo([Remainder] CachedGuildChannel channel = null)
        {
            channel ??= (CachedTextChannel)Context.Channel;

            var builder = new LocalEmbedBuilder()
                          .WithSuccessColor()
                          .AddField(Localize("info_id"), channel.Id)
                          .AddField(Localize("info_created"), string.Join('\n', channel.Id.CreatedAt.ToString("g", Context.Language.Culture),
                                                                          (DateTimeOffset.UtcNow - channel.Id.CreatedAt).HumanizeFormatted(Localization, Context.Language, TimeUnit.Minute, true)));

            builder = channel switch
            {
                CachedTextChannel textChannel => builder
                .WithTitle(Localize(textChannel.IsNews
                        ? "channel_info_news"
                        : "channel_info_text", textChannel))
                .WithDescription(Markdown.Italics(textChannel.Topic))
                .AddField(Localize("info_mention"), textChannel.Mention)
                .AddField(Localize("channel_info_slowmode"),
                          textChannel.Slowmode == 0
                            ? Localize("info_none")
                            : TimeSpan.FromSeconds(textChannel.Slowmode).HumanizeFormatted(Localization, Context.Language, TimeUnit.Second))
                .WithFooter(textChannel.Category is { }
        public async Task SendLoggingRevocationEmbedAsync(RevocablePunishment punishment, IUser target, IUser moderator,
                                                          CachedTextChannel logChannel, LocalizedLanguage language)
        {
            var typeName = punishment.GetType().Name.ToLower();
            var builder  = new LocalEmbedBuilder().WithWarnColor()
                           .WithTitle(_localization.Localize(language, $"punishment_{typeName}") +
                                      $" - {_localization.Localize(language, "punishment_case", punishment.Id)}")
                           .WithDescription(_localization.Localize(language, $"punishment_{typeName}_revoke_description_guild",
                                                                   $"**{target}** (`{target.Id}`)"))
                           .AddField(_localization.Localize(language, "title_reason"),
                                     punishment.RevocationReason ?? _localization.Localize(language, "punishment_noreason"))
                           .WithFooter(_localization.Localize(language, "punishment_moderator", moderator.Tag),
                                       moderator.GetAvatarUrl())
                           .WithTimestamp(punishment.RevokedAt ?? DateTimeOffset.UtcNow);

            if (punishment is Mute channelMute && channelMute.ChannelId.HasValue)
            {
                builder.AddField(_localization.Localize(language, "punishment_mute_channel"),
                                 _client.GetGuild(punishment.GuildId).GetTextChannel(channelMute.ChannelId.Value)?.Mention ?? "???");
            }

            await logChannel.SendMessageAsync(embed : builder.Build());
        }
Exemple #18
0
 protected override DiscordCommandContext CreateCommandContext(IPrefix prefix, IGatewayUserMessage message, CachedTextChannel channel)
 => new VCommandContext(this, prefix, message, channel, Services);
        private async Task <IUserMessage> SendLoggingEmbedAsync(Punishment punishment, IUser target, IUser moderator, Punishment additionalPunishment, CachedTextChannel logChannel, LocalizedLanguage language)
        {
            var typeName = punishment.GetType().Name.ToLower();
            var builder  = new LocalEmbedBuilder()
                           .WithErrorColor()
                           .WithTitle(_localization.Localize(language, $"punishment_{typeName}") +
                                      $" - {_localization.Localize(language, "punishment_case", punishment.Id)}")
                           .AddField(_localization.Localize(language, "title_reason"),
                                     punishment.Reason ?? _localization.Localize(language, "punishment_needsreason",
                                                                                 Markdown.Code(
                                                                                     $"{_config.DefaultPrefix}reason {punishment.Id} [{_localization.Localize(language, "title_reason").ToLower()}]")))
                           .WithFooter(_localization.Localize(language, "punishment_moderator", moderator.Tag),
                                       moderator.GetAvatarUrl())
                           .WithTimestamp(punishment.CreatedAt);

            builder = punishment switch
            {
                Ban ban => builder.AddField(
                    _localization.Localize(language, "punishment_duration"), ban.Duration.HasValue
                        ? ban.Duration.Value.Humanize(minUnit: TimeUnit.Second, culture: language.Culture)
                        : _localization.Localize(language, "punishment_permanent")),
                Mute mute => builder.AddField(
                    _localization.Localize(language, "punishment_duration"), mute.Duration.HasValue
                        ? mute.Duration.Value.Humanize(minUnit: TimeUnit.Second, culture: language.Culture)
                        : _localization.Localize(language, "punishment_permanent")),
                _ => builder
            };

            if (punishment is Mute channelMute && channelMute.ChannelId.HasValue)
            {
                builder.AddField(_localization.Localize(language, "punishment_mute_channel"),
                                 _client.GetGuild(punishment.GuildId).GetTextChannel(channelMute.ChannelId.Value).Mention);
            }

            if (punishment is Warning)
            {
                using var ctx = new AdminDatabaseContext(_provider);

                var warningCount = await ctx.Punishments.OfType <Warning>().CountAsync(x =>
                                                                                       x.TargetId == target.Id && x.GuildId == punishment.GuildId && !x.RevokedAt.HasValue);

                builder.WithDescription(_localization.Localize(language, "punishment_warning_description_guild", $"**{target}** (`{target.Id}`)",
                                                               Markdown.Bold(warningCount.ToOrdinalWords(language.Culture))));

                if (!(additionalPunishment is null))
                {
                    builder.AddField(FormatAdditionalPunishment(additionalPunishment, language));
                }
            }
            else
            {
                builder.WithDescription(_localization.Localize(language, $"punishment_{typeName}_description_guild",
                                                               $"**{target}** (`{target.Id}`)"));
            }

            if (punishment.Format != ImageFormat.Default)
            {
                // TODO: Copying stream - is it necessary?
                var image = new MemoryStream(punishment.Image.ToArray());
                builder.WithImageUrl($"attachment://attachment.{punishment.Format.ToString().ToLower()}");
                return(await logChannel.SendMessageAsync(new LocalAttachment(image,
                                                                             $"attachment.{punishment.Format.ToString().ToLower()}"), embed : builder.Build()));
            }

            return(await logChannel.SendMessageAsync(embed : builder.Build()));
        }
        public async ValueTask <AdminCommandResult> ReplyToModmailAsync(int id,
                                                                        [Remainder, MustBe(StringLength.ShorterThan, LocalEmbedBuilder.MAX_DESCRIPTION_LENGTH)] string message)
        {
            var modmail = await Context.Database.Modmails.FindAsync(id);

            if (modmail is null)
            {
                return(CommandErrorLocalized("modmail_notfound"));
            }

            if (Context.IsPrivate && modmail.UserId != Context.User.Id)
            {
                return(CommandErrorLocalized("modmail_notfound"));
            }

            if (!Context.IsPrivate && modmail.GuildId != Context.Guild.Id)
            {
                return(CommandErrorLocalized("modmail_notfound"));
            }

            CachedTextChannel loggingChannel = null;

            if (Context.IsPrivate)
            {
                if (!(await Context.Database.GetLoggingChannelAsync(modmail.GuildId, LogType.Modmail) is CachedTextChannel
                      logChannel))
                {
                    return(CommandErrorLocalized("requireloggingchannel_notfound", args: LogType.Modmail));
                }

                if (modmail.ClosedBy.HasValue)
                {
                    return(modmail.ClosedBy.Value == ModmailTarget.User
                        ? CommandErrorLocalized("modmail_closed_user")
                        : CommandErrorLocalized("modmail_closed_guild"));
                }

                loggingChannel = logChannel;
            }
            else
            {
                if (modmail.ClosedBy.HasValue)
                {
                    return(modmail.ClosedBy.Value == ModmailTarget.User
                        ? CommandErrorLocalized("modmail_closed_user_guild")
                        : CommandErrorLocalized("modmail_closed_guild"));
                }
            }


            Context.Database.ModmailMessages.Add(new ModmailMessage(Context.IsPrivate ? ModmailTarget.User : ModmailTarget.Modteam, message, modmail));
            await Context.Database.SaveChangesAsync();

            if (Context.IsPrivate)
            {
                await loggingChannel.SendMessageAsync(embed : new LocalEmbedBuilder()
                                                      .WithColor(new Color(0x8ED0FF))
                                                      .WithAuthor(new LocalEmbedAuthorBuilder
                {
                    IconUrl =
                        modmail.IsAnonymous ? Discord.GetDefaultUserAvatarUrl(Context.User.Discriminator) : Context.User.GetAvatarUrl(),
                    Name = modmail.IsAnonymous ? Context.Localize("modmail_anonymous") : Context.User.Tag.Sanitize()
                })
                                                      .WithDescription(message)
                                                      .WithTitle(Context.Localize("modmail_title", modmail.Id))
                                                      .WithFooter(Context.Localize("modmail_reply_command",
                                                                                   Markdown.Code($"{Context.Prefix}mm reply {modmail.Id} [...]"),
                                                                                   Markdown.Code($"{Context.Prefix}mm close {modmail.Id}")))
                                                      .WithTimestamp(DateTimeOffset.UtcNow)
                                                      .Build());
            }
            else
            {
                _ = Task.Run(async() =>
                {
                    var user = await Context.Client.GetOrDownloadUserAsync(modmail.UserId);
                    _        = user.SendMessageAsync(embed: new LocalEmbedBuilder()
                                                     .WithColor(new Color(0x8ED0FF))
                                                     .WithAuthor(new LocalEmbedAuthorBuilder
                    {
                        IconUrl = Context.Guild.GetIconUrl(),
                        Name    = $"{Context.Guild.Name} modteam"
                    })
                                                     .WithDescription(message)
                                                     .WithTitle(Context.Localize("modmail_title", modmail.Id))
                                                     .WithFooter(Context.Localize("modmail_reply_command",
                                                                                  Markdown.Code($"{Context.Prefix}mm reply {modmail.Id} [...]"),
                                                                                  Markdown.Code($"{Context.Prefix}mm close {modmail.Id}")))
                                                     .WithTimestamp(DateTimeOffset.UtcNow)
                                                     .Build());
                });
            }

            return(CommandSuccessLocalized("modmail_reply_success"));
        }
Exemple #21
0
 public ValueTask <AdminCommandResult> AddPermission([Remainder] CachedTextChannel channel)
 => AddPermissionAsync(null, Context.Path[1].Equals("enable"), PermissionFilter.Channel, channel.Id);
Exemple #22
0
 public ValueTask <AdminCommandResult> BlockUser([RequireHierarchy] CachedMember target,
                                                 CachedTextChannel channel, TimeSpan duration, [Remainder] string reason = null)
 => BlockUserAsync(target, channel, duration, reason);
            public async ValueTask <AdminCommandResult> UnblacklistChannelHighlightsAsync([Remainder] CachedTextChannel channel)
            {
                if (channel.Guild.GetMember(Context.User.Id) is null)
                {
                    return(CommandErrorLocalized("highlight_blacklist_notmember"));
                }

                var user = await Context.Database.GetOrCreateGlobalUserAsync(Context.User.Id);

                user.HighlightBlacklist.Remove(channel.Id);

                Context.Database.GlobalUsers.Update(user);
                await Context.Database.SaveChangesAsync();

                return(CommandSuccessLocalized("highlight_blacklist_remove", args: channel.Format()));
            }
Exemple #24
0
            private async ValueTask <AdminCommandResult> BlockUserAsync(CachedMember target, CachedTextChannel channel,
                                                                        TimeSpan?duration, string reason)
            {
                channel ??= (CachedTextChannel)Context.Channel;

                if (channel.Overwrites.Any(x => x.TargetId == target.Id))
                {
                    return(CommandErrorLocalized("moderation_alreadyblocked", args: Markdown.Bold(target.Tag)));
                }

                var guild = await Context.Database.GetOrCreateGuildAsync(Context.Guild.Id);

                Mute mute = null;

                if (guild.Settings.HasFlag(GuildSettings.Punishments))
                {
                    var image  = new MemoryStream();
                    var format = ImageFormat.Default;
                    if (Context.Message.Attachments.FirstOrDefault() is { } attachment&&
                        attachment.FileName.HasImageExtension(out format))
                    {
                        var stream = await Http.GetStreamAsync(attachment.Url);

                        await stream.CopyToAsync(image);

                        image.Seek(0, SeekOrigin.Begin);
                    }

                    mute = new Mute(Context.Guild.Id, target.Id, Context.User.Id, reason, duration, channel.Id, image, format);
                    if (channel.Overwrites.FirstOrDefault(x => x.TargetId == target.Id) is CachedOverwrite overwrite)
                    {
                        mute.StoreOverwrite(overwrite);
                        await channel.DeleteOverwriteAsync(target.Id);
                    }
                    mute = Context.Database.Punishments.Add(mute).Entity as Mute;
                    await Context.Database.SaveChangesAsync();

                    await Punishments.LogMuteAsync(target, Context.Guild, Context.User, mute);
                }

                await channel.AddOrModifyOverwriteAsync(new LocalOverwrite(target,
                                                                           new OverwritePermissions().Deny(Permission.SendMessages).Deny(Permission.AddReactions)));

                return(duration.HasValue
                    ? CommandSuccessLocalized("moderation_block_temporary", args: new object[]
                {
                    (mute is { } ? $"`[#{mute.Id}]` " : string.Empty) + target.Format(),
Exemple #25
0
 public VCommandContext(VerificationBot bot, IPrefix prefix, IGatewayUserMessage message, CachedTextChannel channel, IServiceProvider services)
     : base(bot, prefix, message, channel, services)
     => Bot = bot;
 internal MessagesBulkDeletedEventArgs(CachedTextChannel channel,
                                       IReadOnlyList <SnowflakeOptional <CachedUserMessage> > messages) : base(channel.Client)
 {
     Channel  = channel;
     Messages = messages;
 }
 public ValueTask <AdminCommandResult> RemoveFromBlacklistAsync(CachedTextChannel channel)
 => RemoveFromBlacklistAsync(channel.Id, false);