public static Task GuildAvailableEventHandlerAsync(TheGodfatherBot bot, GuildCreateEventArgs e)
        {
            LogExt.Information(bot.GetId(e.Guild.Id), "Available: {AvailableGuild}", e.Guild);
            GuildConfigService gcs = bot.Services.GetRequiredService <GuildConfigService>();

            return(gcs.IsGuildRegistered(e.Guild.Id) ? Task.CompletedTask : gcs.RegisterGuildAsync(e.Guild.Id));
        }
        public Dictionary <int, Set> LoadData()
        {
            var fileSets = Path.Combine(folderData, "sets.json");

            LogExt.LogReadFile(fileSets);
            var content = File.ReadAllText(fileSets);
            var data    = JsonConvert.DeserializeObject <ICollection <dynamic> >(content);

            var dataCurated = data
                              .Where(i => string.IsNullOrWhiteSpace(i.Code?.ToString()) == false)
                              .Where(i => Convert.ToInt32(i.MtgaId ?? 0) > 0)
                              .Select(i => new Set
            {
                Arenacode   = i.CodeArena,
                Collation   = i.MtgaId,
                Code        = i.Code,
                ReleaseDate = i.ReleaseDate,
                Scryfall    = i.CodeScryfall,
                Tile        = 0
            })
                              .ToArray();

            var ret = dataCurated.ToDictionary(i => i.Collation, i => i);

            return(ret);
        }
Beispiel #3
0
        public static async Task MessageCreateEventHandlerAsync(TheGodfatherBot bot, MessageCreateEventArgs e)
        {
            if (e.Author.IsBot)
            {
                return;
            }

            if (e.Guild is null)
            {
                LogExt.Debug(bot.GetId(null), new[] { "DM message received from {User}:", "{Message}" }, e.Author, e.Message);
                return;
            }

            if (bot.Services.GetRequiredService <BlockingService>().IsBlocked(e.Guild.Id, e.Channel.Id, e.Author.Id))
            {
                return;
            }

            if (string.IsNullOrWhiteSpace(e.Message?.Content))
            {
                return;
            }

            if (!e.Message.Content.StartsWith(bot.Services.GetRequiredService <GuildConfigService>().GetGuildPrefix(e.Guild.Id)))
            {
                short rank = bot.Services.GetRequiredService <UserRanksService>().ChangeXp(e.Guild.Id, e.Author.Id);
                if (rank != 0)
                {
                    LocalizationService ls = bot.Services.GetRequiredService <LocalizationService>();
                    LevelRole?          lr = await bot.Services.GetRequiredService <LevelRoleService>().GetAsync(e.Guild.Id, rank);

                    DiscordRole?levelRole = lr is { } ? e.Guild.GetRole(lr.RoleId) : null;
Beispiel #4
0
        public static string GetScalarString_pro(string StoredProcedure, params SqlParameter[] values)
        {
            SqlConnection con = new SqlConnection(conString);
            SqlCommand    cmd = new SqlCommand();

            cmd.Connection  = con;
            cmd.CommandText = StoredProcedure;
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Parameters.AddRange(values);
            string result = string.Empty;

            try
            {
                con.Open();
                result = cmd.ExecuteScalar().ToString();
            }
            catch (Exception ex)
            {
                LogExt.WriteLogFile("GetScalarString_pro出错。存储过程:" + StoredProcedure + "。提示:" + ex.Message);
                throw new Exception(ex.Message);
            }
            finally
            {
                con.Close();
            }
            return(result);
        }
Beispiel #5
0
        /// <summary>
        /// 测试数据库连接
        /// </summary>
        /// <param name="isShowTip">是否弹出提示</param>
        /// <returns></returns>
        public bool TestDB(bool isShowTip)
        {
            if (!CheckData(isShowTip))
            {
                return(false);
            }

            Func <bool> error = () =>
            {
                if (isShowTip)
                {
                    MsgBox.Error("测试连接失败,请检查后重试!");
                }
                return(false);
            };

            return(LogExt.Exec(() =>
            {
                if (!DBExt.TestSqlServerDB(DB))
                {
                    return error();
                }
                return true;
            }, error));
        }
        public override Task <bool> ExecuteCheckAsync(CommandContext ctx, bool help)
        {
            if (!ctx.Services.GetRequiredService <BotActivityService>().IsBotListening)
            {
                return(Task.FromResult(false));
            }
            if (ctx.Services.GetRequiredService <BlockingService>().IsBlocked(ctx.Guild?.Id, ctx.Channel.Id, ctx.User.Id))
            {
                return(Task.FromResult(false));
            }
            if (BlockingCommandRuleExists())
            {
                return(Task.FromResult(false));
            }

            if (!help)
            {
                LogExt.Debug(ctx, "Executing {Command} in message: {Message}", ctx.Command?.QualifiedName ?? "<unknown cmd>", ctx.Message.Content);
            }

            return(Task.FromResult(true));


            bool BlockingCommandRuleExists()
            {
                if (ctx.Guild is null || ctx.Command is null)
                {
                    return(false);
                }
                CommandRulesService?crs = ctx.Services.GetRequiredService <CommandRulesService>();

                return(crs?.IsBlocked(ctx.Command.QualifiedName, ctx.Guild.Id, ctx.Channel.Id, ctx.Channel.Parent?.Id) ?? false);
            }
        }
Beispiel #7
0
        public async Task ListAsync(CommandContext ctx)
        {
            IReadOnlyList <PrivilegedUser> privileged = await this.Service.GetAsync();

            var notFound = new List <PrivilegedUser>();
            var valid    = new List <DiscordUser>();

            foreach (PrivilegedUser pu in privileged)
            {
                try {
                    DiscordUser user = await ctx.Client.GetUserAsync(pu.UserId);

                    valid.Add(user);
                } catch (NotFoundException) {
                    LogExt.Debug(ctx, "Found 404 privileged user: {UserId}", pu.UserId);
                    notFound.Add(pu);
                }
            }

            if (!valid.Any())
            {
                throw new CommandFailedException(ctx, "cmd-err-choice-none");
            }

            await ctx.PaginateAsync(
                "str-priv",
                valid,
                user => user.ToString(),
                this.ModuleColor,
                10
                );

            LogExt.Information(ctx, "Removing {Count} not found privileged users", notFound.Count);
            await this.Service.RemoveAsync(notFound);
        }
Beispiel #8
0
        /// <summary>
        /// 调用存储过程,传递参数,返回受影响的行数
        /// </summary>
        /// <param name="StoredProcedure">存储过程名</param>
        /// <param name="values">参数列表</param>
        /// <returns>返回受影响的行数</returns>
        public static int ExecuteCommandPro(string StoredProcedure, params SqlParameter[] values)
        {
            int           result = -1;
            SqlCommand    cmd    = new SqlCommand();
            SqlConnection con    = new SqlConnection(conString);

            cmd.Connection  = con;
            cmd.CommandText = StoredProcedure;
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Parameters.AddRange(values);
            try
            {
                con.Open();
                result = cmd.ExecuteNonQuery();
            }
            catch (Exception ex)
            {
                LogExt.WriteLogFile("ExecuteCommandPro出错。存储过程:" + StoredProcedure + "。提示:" + ex.Message);
                throw;
            }
            finally
            {
                con.Close();
            }
            return(result);
        }
        internal static async Task Main(string[] _)
        {
            PrintBuildInformation();

            try {
                BotConfigService cfg = await LoadBotConfigAsync();

                Log.Logger = LogExt.CreateLogger(cfg.CurrentConfiguration);
                Log.Information("Logger created.");

                DbContextBuilder dbb = await InitializeDatabaseAsync(cfg);

                await StartAsync(cfg, dbb);

                Log.Information("Booting complete!");

                CancellationToken token = Bot?.Services.GetRequiredService <BotActivityService>().MainLoopCts.Token
                                          ?? throw new InvalidOperationException("Bot not initialized");
                await Task.Delay(Timeout.Infinite, token);
            } catch (TaskCanceledException) {
                Log.Information("Shutdown signal received!");
            } catch (Exception e) {
                Log.Fatal(e, "Critical exception occurred");
                Environment.ExitCode = 1;
            } finally {
                await DisposeAsync();
            }

            Log.Information("Powering off");
            Log.CloseAndFlush();
            Environment.Exit(Environment.ExitCode);
        }
Beispiel #10
0
        public async Task BaseAddAsync(CommandContext ctx, string?reason, params T[] entities)
        {
            if (reason?.Length >= 60)
            {
                throw new InvalidCommandUsageException(ctx, "cmd-err-rsn", BlockedEntity.ReasonLimit);
            }

            if (entities is null || !entities.Any())
            {
                throw new InvalidCommandUsageException(ctx, "cmd-err-block-none");
            }

            int blocked = await this.BlockAsync(entities.Select(c => c.Id), reason);

            await ctx.InfoAsync(this.ModuleColor, "fmt-block-add", blocked);

            if (typeof(T) == typeof(DiscordGuild))
            {
                foreach (T entity in entities)
                {
                    try {
                        DiscordGuild g = await ctx.Client.GetGuildAsync(entity.Id);

                        await g.LeaveAsync();
                    } catch {
                        LogExt.Debug(ctx, "Failed to find/leave guild: {Id}", entity.Id);
                    }
                }
            }
        }
 public void LoadEventsFromDisk()
 {
     if (File.Exists(path))
     {
         LogExt.LogReadFile(path);
         var eventCollection =
             JsonConvert.DeserializeObject <ICollection <GetActiveEventsV2Raw> >(File.ReadAllText(path));
         cache.AddEvents(eventCollection);
     }
 }
Beispiel #12
0
        public Dictionary <string, DraftRatings> LoadData()
        {
            var fileSets = Path.Combine(folderData, "draftRatings.json");

            LogExt.LogReadFile(fileSets);
            var content         = File.ReadAllText(fileSets);
            var ratingsBySource = JsonConvert.DeserializeObject <Dictionary <string, DraftRatings> >(content);

            return(ratingsBySource);
        }
Beispiel #13
0
        public Dictionary <int, Card> LoadData()
        {
            var fileSets = Path.Combine(folderData, "AllCardsCached2.json");

            LogExt.LogReadFile(fileSets);
            var content = File.ReadAllText(fileSets);
            var data    = JsonConvert.DeserializeObject <ICollection <Card2> >(content);

            var dataOldFormat = data.Select(c => new Card(c)).ToDictionary(i => i.grpId);

            return(dataOldFormat);
        }
Beispiel #14
0
        /// <summary>
        /// 刷新数据库列表
        /// </summary>
        public async void RefreshDB(string defaultDB = null)
        {
            if (!CheckData())
            {
                cmbDatabase.DataSource = null;
                return;
            }

            // 记录默认值
            string defaultValue = defaultDB ?? Database;

            DataTable dtDBName = new DataTable();

            // 查询所有数据库
            await Task.Run(() =>
            {
                LogExt.Exec(() =>
                {
                    DBInfo dbMaster = new DBInfo(Server, "master", UserName, Password);

                    var adapter = new SqlDataAdapter(@"
                        SELECT '' AS name, 0 AS OrderID 
                        UNION 
                        SELECT name, 1
                        FROM master..sysdatabases 
				        WHERE dbid <= 4
				        UNION
				        SELECT name, 2
                        FROM master..sysdatabases 
				        WHERE dbid > 4
                        ORDER BY OrderID, name", dbMaster.Conn);

                    lock (adapter)
                    {
                        adapter.Fill(dtDBName);
                    }
                });
            });

            // 绑定数据源
            if (dtDBName.Rows.Count > 1)
            {
                cmbDatabase.DisplayMember = "name";
                cmbDatabase.ValueMember   = "name";
                cmbDatabase.DataSource    = dtDBName;

                cmbDatabase.SelectedValue = defaultValue;
            }
            else
            {
                cmbDatabase.DataSource = null;
            }
        }
Beispiel #15
0
 public static Task CommandExecutionEventHandler(TheGodfatherBot bot, CommandExecutionEventArgs e)
 {
     if (e.Command is null || e.Command.QualifiedName.StartsWith("help"))
     {
         return(Task.CompletedTask);
     }
     LogExt.Information(
         bot.GetId(e.Context.Guild?.Id),
         new[] { "Executed: {ExecutedCommand}", "{User}", "{Guild}", "{Channel}" },
         e.Command.QualifiedName, e.Context.User, e.Context.Guild?.ToString() ?? "DM", e.Context.Channel
         );
     return(Task.CompletedTask);
 }
        public static async Task GuildCreateEventHandlerAsync(TheGodfatherBot bot, GuildCreateEventArgs e)
        {
            LogExt.Information(bot.GetId(e.Guild.Id), "Joined {NewGuild}", e.Guild);

            if (bot.Services.GetRequiredService <BlockingService>().IsGuildBlocked(e.Guild.Id))
            {
                LogExt.Information(bot.GetId(e.Guild.Id), "{Guild} is blocked. Leaving...", e.Guild);
                await e.Guild.LeaveAsync();

                return;
            }

            IReadOnlyCollection <DiscordMember> members = await e.Guild.GetAllMembersAsync();

            int botCount = members.Where(m => m.IsBot).Count();

            if (botCount > 25 || (members.Count - botCount < 0))
            {
                LogExt.Information(bot.GetId(e.Guild.Id), "{Guild} is most likely a bot farm. Leaving and blocking...", e.Guild);
                await e.Guild.LeaveAsync();

                await bot.Services.GetRequiredService <BlockingService>().BlockGuildAsync(e.Guild.Id, "Bot farm");

                return;
            }

            await bot.Services.GetRequiredService <GuildConfigService>().RegisterGuildAsync(e.Guild.Id);

            DiscordChannel defChannel = e.Guild.GetDefaultChannel();

            if (!defChannel.PermissionsFor(e.Guild.CurrentMember).HasPermission(Permissions.SendMessages))
            {
                return;
            }

            string prefix = bot.Services.GetRequiredService <BotConfigService>().CurrentConfiguration.Prefix;
            string owners = bot.Client.CurrentApplication.Owners.Select(o => o.ToDiscriminatorString()).Humanize(", ");
            await defChannel.EmbedAsync(
                $"{Formatter.Bold("Thank you for adding me!")}\n\n" +
                $"{Emojis.SmallBlueDiamond} The default prefix for commands is {Formatter.Bold(prefix)}, but it can be changed " +
                $"via {Formatter.Bold("prefix")} command.\n" +
                $"{Emojis.SmallBlueDiamond} I advise you to run the configuration wizard for this guild in order to quickly configure " +
                $"functions like logging, notifications etc. The wizard can be invoked using {Formatter.Bold("config setup")} command.\n" +
                $"{Emojis.SmallBlueDiamond} You can use the {Formatter.Bold("help")} command as a guide, though it is recommended to " +
                $"read the documentation @ https://github.com/ivan-ristovic/the-godfather \n" +
                $"{Emojis.SmallBlueDiamond} If you have any questions or problems, feel free to use the {Formatter.Bold("report")} " +
                $"command in order to send a message to the bot owners ({owners}). Alternatively, you can create an issue on " +
                $"GitHub or join WorldMafia Discord server for quick support (https://worldmafia.net/discord)."
                , Emojis.Wave
                );
        }
Beispiel #17
0
        /// <summary>
        /// 保存填写的数据库信息
        /// </summary>
        public void SaveConfig()
        {
            RefreshHistoryDic();

            // 新增当前信息
            _dicHistory.SafeAdd($"{DB.Server}@{DB.Database}", (DataBase)DB);

            // 序列化保存
            List <DataBase> dbList = _dicHistory.Select(e => e.Value).ToList();

            LogExt.Exec(() =>
            {
                SerializeExt.ToXml(dbList, ConfigFilePath);
            });
        }
        public Dictionary <int, Set> LoadData()
        {
            var fileSets = Path.Combine(folderData, "sets.json");

            LogExt.LogReadFile(fileSets);
            var content = File.ReadAllText(fileSets);
            var data    = JsonConvert.DeserializeObject <Dictionary <string, dynamic> >(content);

            var dataCurated = data
                              .Where(i => string.IsNullOrWhiteSpace(i.Key) == false)
                              .Where(i => Convert.ToInt32(i.Value.collation) > 0)
                              .Select(i => JsonConvert.DeserializeObject <Set>(JsonConvert.SerializeObject(i.Value)))
                              .Cast <Set>()
                              .ToArray();

            return(dataCurated.ToDictionary(i => i.Collation, i => i));
        }
 public void LoadEventsFromDisk()
 {
     if (File.Exists(path))
     {
         LogExt.LogReadFile(path);
         var fileText = File.ReadAllText(path);
         ICollection <GetActiveEventsV3Raw> eventCollection;
         try
         {
             eventCollection = JsonConvert.DeserializeObject <ICollection <GetActiveEventsV3Raw> >(fileText) ?? new GetActiveEventsV3Raw[0];
         }
         catch (Exception)
         {
             eventCollection = new GetActiveEventsV3Raw[0];
         }
         cache.AddEvents(eventCollection);
     }
 }
Beispiel #20
0
        private void RefreshHistoryDic()
        {
            // 反序列化
            var dbList = LogExt.Exec
                         (
                () => SerializeExt.XmlTo <List <DataBase> >(GetConfigXml().InnerXml),
                () => new List <DataBase>()
                         );

            // 绑定
            _dicHistory.Clear();
            if (dbList.Count > 0)
            {
                dbList.OrderByDescending(db => db.UpdateTime)
                .Take(10)
                .ForEach(db => _dicHistory.Add($"{db.Server}@{db.Database}", db));
            }
        }
Beispiel #21
0
        /// <summary>
        /// 执行sql语句,不传递其他参数,返回第一行第一列的值
        /// </summary>
        /// <param name="safeSql">sql语句</param>
        /// <returns>string类型</returns>
        public static string ReturnStringScalar(string safeSql)
        {
            SqlCommand cmd = new SqlCommand(safeSql, Connection);

            try
            {
                string result = cmd.ExecuteScalar().ToString();
                return(result);
            }
            catch (Exception e)
            {
                LogExt.WriteLogFile("ReturnStringScalar出错。sql:" + safeSql + "。提示:" + e.Message);
                throw new Exception(e.Message);
            }
            finally
            {
                connection.Close();
            }
        }
        public static async Task MessageReactionAddedEventHandlerAsync(TheGodfatherBot bot, MessageReactionAddEventArgs e)
        {
            if (e.Guild is null || e.Channel is null || e.Message is null)
            {
                return;
            }

            StarboardService ss = bot.Services.GetRequiredService <StarboardService>();

            if (ss.IsStarboardEnabled(e.Guild.Id, out ulong cid, out string star) && cid != e.Channel.Id && e.Emoji.GetDiscordName() == star)
            {
                LogExt.Debug(bot.GetId(e.Guild.Id), "Reacted with star emoji: Message {MessageId}, {Guild}", e.Message.Id, e.Guild);
                ss.RegisterModifiedMessage(e.Guild.Id, e.Channel.Id, e.Message.Id);
            }

            ReactionRoleService rrs = bot.Services.GetRequiredService <ReactionRoleService>();
            ReactionRole?       rr  = await rrs.GetAsync(e.Guild.Id, e.Emoji.GetDiscordName());

            if (rr is { })
        public Dictionary <int, Card> LoadData()
        {
            var fileSets = Path.Combine(folderData, "AllCardsCached2.json");

            LogExt.LogReadFile(fileSets);
            var content       = File.ReadAllText(fileSets);
            var dataOldFormat = JsonConvert.DeserializeObject <ICollection <Card2> >(content)
                                .Select(c => new Card(c))
                                .ToArray();

            // Patch to support multiple cards with an Arena Id of 0
            var iNewId = dataOldFormat.Max(i => i.grpId) + 1;

            foreach (var cardMissingId in dataOldFormat.Where(i => i.grpId == 0).Skip(1))
            {
                cardMissingId.grpId = iNewId++;
            }

            return(dataOldFormat.ToDictionary(i => i.grpId));
        }
Beispiel #24
0
        /// <summary>
        /// 执行sql语句,返回受影响的行数
        /// </summary>
        /// <param name="safeSql">sql语句</param>
        /// <returns>返回受影响的行数</returns>
        public static int ExecuteCommand(string safeSql)
        {
            SqlConnection con    = new SqlConnection(conString);
            SqlCommand    cmd    = new SqlCommand(safeSql, con);
            int           result = -1;

            try
            {
                con.Open();
                result = cmd.ExecuteNonQuery();
            }
            catch (Exception ex)
            {
                LogExt.WriteLogFile("ExecuteCommand出错。sql:" + safeSql + "。提示:" + ex.Message);
                throw new Exception(ex.Message);
            }
            finally
            {
                con.Close();
            }
            return(result);
        }
Beispiel #25
0
        /// <summary>
        /// 执行sql语句,不传递其他参数,返回第一行第一列的值,int类型
        /// </summary>
        /// <param name="safeSql">sql语句</param>
        /// <returns>返回第一行第一列的值</returns>
        public static int GetScalar(string safeSql)
        {
            SqlConnection con    = new SqlConnection(conString);
            SqlCommand    cmd    = new SqlCommand(safeSql, con);
            int           result = -1;

            try
            {
                con.Open();
                result = Convert.ToInt32(cmd.ExecuteScalar());
            }
            catch (Exception ex)
            {
                LogExt.WriteLogFile("GetScalar出错。sql:" + safeSql + "。提示:" + ex.Message);
                throw new Exception(ex.Message);
            }
            finally
            {
                con.Close();
            }
            return(result);
        }
        public static async Task GuildMemberJoinEventHandlerAsync(TheGodfatherBot bot, GuildMemberAddEventArgs e)
        {
            if (e.Guild is null)
            {
                return;
            }

            LogExt.Debug(bot.GetId(e.Guild.Id), "Member added: {Member} {Guild}", e.Member, e.Guild);

            GuildConfigService gcs  = bot.Services.GetRequiredService <GuildConfigService>();
            GuildConfig        gcfg = await gcs.GetConfigAsync(e.Guild.Id);

            await Task.Delay(TimeSpan.FromSeconds(gcfg.AntiInstantLeaveSettings.Cooldown + 1));

            if (e.Member.Guild is null)     // User left in meantime
            {
                return;
            }

            // TODO move to service
            DiscordChannel?wchn = e.Guild.GetChannel(gcfg.WelcomeChannelId);

            if (wchn is { })
Beispiel #27
0
        /// <summary>
        /// 执行sql语句,传递其他参数,返回第一行和第一列的值,string类型
        /// </summary>
        /// <param name="sql">sql语句</param>
        /// <param name="values">参数列表</param>
        /// <returns>返回第一行和第一列的值</returns>
        public static string GetScalarByString(string sql, params SqlParameter[] values)
        {
            SqlConnection con = new SqlConnection(conString);
            SqlCommand    cmd = new SqlCommand(sql, con);

            cmd.Parameters.AddRange(values);
            string result = null;

            try
            {
                con.Open();
                result = Convert.ToString(cmd.ExecuteScalar());
            }
            catch (Exception ex)
            {
                LogExt.WriteLogFile("GetScalarByString出错。sql:" + sql + "。提示:" + ex.Message);
                throw new Exception(ex.Message);
            }
            finally
            {
                con.Close();
            }
            return(result);
        }
 public static Task GuildUnvailableEventHandlerAsync(TheGodfatherBot bot, GuildDeleteEventArgs e)
 {
     LogExt.Warning(bot.GetId(e.Guild.Id), "Unvailable: {UnvailableGuild}", e.Guild);
     return(Task.CompletedTask);
 }
 private void WriteLogExt(string msg)
 {
     LogExt?.Invoke(msg);
 }
        public override BaseHelpFormatter WithCommand(Command cmd)
        {
            this.name = cmd is CommandGroup?this.GetS("fmt-group", cmd.QualifiedName) : cmd.QualifiedName;

            CommandService cs = this.Context.Services.GetRequiredService <CommandService>();

            try {
                this.desc = cs.GetCommandDescription(this.GuildId, cmd.QualifiedName);
            } catch (Exception e) when(e is LocalizationException or KeyNotFoundException)
            {
                LogExt.Warning(this.Context, e, "Failed to find description for: {Command}", cmd.QualifiedName);
                this.desc = this.GetS("h-desc-none");
            }

            if (cmd.Aliases?.Any() ?? false)
            {
                this.emb.AddLocalizedTitleField("str-aliases", cmd.Aliases.Select(a => Formatter.InlineCode(a)).JoinWith(", "), inline: true);
            }

            this.emb.AddLocalizedTitleField("str-category", ModuleAttribute.AttachedTo(cmd).Module.ToString(), inline: true);

            IEnumerable <CheckBaseAttribute> checks = cmd.ExecutionChecks
                                                      .Union(cmd.Parent?.ExecutionChecks ?? Enumerable.Empty <CheckBaseAttribute>());
            IEnumerable <string> perms = checks
                                         .OfType <RequirePermissionsAttribute>()
                                         .Select(chk => chk.Permissions.ToPermissionString())
                                         .Union(checks
                                                .OfType <RequirePermissionsAttribute>()
                                                .Select(chk => chk.Permissions.ToPermissionString())
                                                );
            IEnumerable <string> uperms = checks
                                          .OfType <RequireUserPermissionsAttribute>()
                                          .Select(chk => chk.Permissions.ToPermissionString());
            IEnumerable <string> bperms = checks
                                          .OfType <RequireBotPermissionsAttribute>()
                                          .Select(chk => chk.Permissions.ToPermissionString());

            var pb = new StringBuilder();

            if (checks.Any(chk => chk is RequireOwnerAttribute))
            {
                pb.AppendLine(Formatter.Bold(this.GetS("str-owner-only")));
            }
            if (checks.Any(chk => chk is RequirePrivilegedUserAttribute))
            {
                pb.AppendLine(Formatter.Bold(this.GetS("str-priv-only")));
            }
            if (perms.Any())
            {
                pb.AppendLine(Formatter.InlineCode(perms.JoinWith(", ")));
            }
            if (uperms.Any())
            {
                pb.Append(this.GetS("str-perms-user")).Append(' ').AppendLine(Formatter.InlineCode(uperms.JoinWith(", ")));
            }
            if (bperms.Any())
            {
                pb.Append(this.GetS("str-perms-bot")).Append(' ').AppendLine(Formatter.InlineCode(bperms.JoinWith(", ")));
            }

            string pstr = pb.ToString();

            if (!string.IsNullOrWhiteSpace(pstr))
            {
                this.emb.AddLocalizedTitleField("str-perms-req", pstr);
            }

            if (cmd.Overloads?.Any() ?? false)
            {
                foreach (CommandOverload overload in cmd.Overloads.OrderByDescending(o => o.Priority))
                {
                    var ab = new StringBuilder();

                    foreach (CommandArgument arg in overload.Arguments)
                    {
                        if (arg.IsOptional)
                        {
                            ab.Append(this.GetS("str-optional")).Append(' ');
                        }

                        ab.Append("[`").Append(this.CommandsNext.GetUserFriendlyTypeName(arg.Type));
                        if (arg.IsCatchAll)
                        {
                            ab.Append("...");
                        }
                        ab.Append("`] ");

                        ab.Append(Formatter.Bold(this.GetS(string.IsNullOrWhiteSpace(arg.Description) ? "h-desc-none" : arg.Description)));

                        if (arg.IsOptional)
                        {
                            ab.Append(" (")
                            .Append(this.GetS("str-def"))
                            .Append(' ')
                            .Append(Formatter.InlineCode(arg.DefaultValue is null ? this.GetS("str-none") : arg.DefaultValue.ToString()))
                            .Append(')');
                        }

                        ab.AppendLine();
                    }

                    string args = ab.Length > 0 ? ab.ToString() : this.GetS("str-args-none");

                    if (cmd.Overloads.Count > 1)
                    {
                        this.emb.AddLocalizedTitleField("str-overload", args, inline: true, titleArgs: overload.Priority);
                    }
                    else
                    {
                        this.emb.AddLocalizedTitleField("str-args", args, inline: true);
                    }
                }
            }

            if (cmd is CommandGroup {
                IsExecutableWithoutSubcommands : false
            })