Esempio n. 1
0
        public async Task ExecutePunishment(ModCase modCase)
        {
            using var scope = _serviceProvider.CreateScope();
            Database database = scope.ServiceProvider.GetRequiredService <Database>();

            GuildConfig guildConfig;

            try
            {
                guildConfig = await GuildConfigRepository.CreateDefault(scope.ServiceProvider).GetGuildConfig(modCase.GuildId);
            }
            catch (ResourceNotFoundException)
            {
                _logger.LogError($"Cannot execute punishment in guild {modCase.GuildId} - guildconfig not found.");
                return;
            }

            string reason = null;

            try
            {
                Translator translator = scope.ServiceProvider.GetRequiredService <Translator>();
                reason = translator.T(guildConfig).NotificationDiscordAuditLogPunishmentsExecute(modCase.CaseId, modCase.LastEditedByModId, modCase.Title.Truncate(400));
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Failed to resolve audit log reason string for case {modCase.GuildId}/{modCase.CaseId}");
            }
            switch (modCase.PunishmentType)
            {
            case PunishmentType.Mute:
                if (guildConfig.MutedRoles.Length != 0)
                {
                    _logger.LogInformation($"Mute User {modCase.UserId} in guild {modCase.GuildId} with roles " + string.Join(',', guildConfig.MutedRoles.Select(x => x.ToString())));
                    foreach (ulong role in guildConfig.MutedRoles)
                    {
                        await _discord.GrantGuildUserRole(modCase.GuildId, modCase.UserId, role, reason);
                    }
                }
                else
                {
                    _logger.LogInformation($"Cannot Mute User {modCase.UserId} in guild {modCase.GuildId} - mute role undefined.");
                }
                break;

            case PunishmentType.Ban:
                _logger.LogInformation($"Ban User {modCase.UserId} in guild {modCase.GuildId}.");
                await _discord.BanUser(modCase.GuildId, modCase.UserId, reason);

                await _discord.GetGuildUserBan(modCase.GuildId, modCase.UserId, CacheBehavior.IgnoreCache);      // refresh ban cache

                break;

            case PunishmentType.Kick:
                _logger.LogInformation($"Kick User {modCase.UserId} in guild {modCase.GuildId}.");
                await _discord.KickGuildUser(modCase.GuildId, modCase.UserId, reason);

                break;
            }
        }
Esempio n. 2
0
        /// <summary>
        ///     Mutes specified user.
        ///     <para>Prevents the user from sending chat messages.</para>
        /// </summary>
        public async Task <Embed> MuteAsync(SocketCommandContext context, IGuildUser user, string reason)
        {
            //Get Muted role if it exists or create it if it doesn't exist
            var muteRole = Helper.DoesRoleExist(context.Guild, "Muted") ??
                           await context.Guild.CreateRoleAsync("Muted", GuildPermissions.None, Color.DarkGrey, false,
                                                               null);

            if (user.RoleIds.Any(role => role == muteRole.Id))
            {
                return(CustomFormats.CreateErrorEmbed($"{user} is already muted!"));
            }

            //Add muted role to the user
            await user.AddRoleAsync(muteRole);

            //Loop through every channel in the guild and deny the user from sending messages
            foreach (var channel in context.Guild.TextChannels)
            {
                await channel.AddPermissionOverwriteAsync(user, new OverwritePermissions(sendMessages : PermValue.Deny));
            }

            var caseId = await GenerateModCaseId(context.Guild.Id);

            //Create modCase
            var modCase = new ModCase(context, user, caseId, PunishmentType.Mute, reason);
            await _botContext.ModCases.AddAsync(modCase);

            await _botContext.SaveChangesAsync();

            await SendModLog(context.Guild, modCase);

            return(ModerationFormats.CreateModerationEmbed(user, $"{user} muted",
                                                           $"{user} has been muted for: {reason ?? "_No reason_"}.", Color.DarkGrey));
        }
Esempio n. 3
0
        /// <summary>
        ///     Voice mutes specified user.
        ///     <para>Prevents the user from talking on voice channels.</para>
        /// </summary>
        public async Task <Embed> VoiceMuteAsync(SocketCommandContext context, IGuildUser user, string reason)
        {
            //If user is already muted, tell the command issuer that the specified user is already muted
            if (user.IsMuted)
            {
                return(CustomFormats.CreateErrorEmbed($"{user} is already voice muted."));
            }

            //If user isn't already muted, then mute him
            await user.ModifyAsync(x => x.Mute = true, new RequestOptions { AuditLogReason = reason });

            var caseId = await GenerateModCaseId(context.Guild.Id);

            //Create modCase
            var modCase = new ModCase(context, user, caseId, PunishmentType.VMute, reason);
            await _botContext.ModCases.AddAsync(modCase);

            await _botContext.SaveChangesAsync();

            await SendModLog(context.Guild, modCase);

            return(ModerationFormats.CreateModerationEmbed(user, $"{user} voice muted",
                                                           $"{user} has been voice muted for: {reason ?? "_No reason_"}.",
                                                           Color.DarkGrey));
        }
Esempio n. 4
0
        public async Task AnnounceModCase(ModCase modCase, RestAction action, User actor, bool announcePublic)
        {
            logger.LogInformation($"Announcing modcase {modCase.Id} in guild {modCase.GuildId}.");

            User caseUser = await discord.FetchUserInfo(modCase.UserId);

            GuildConfig guildConfig = await dbContext.SelectSpecificGuildConfig(modCase.GuildId);

            if (!string.IsNullOrEmpty(guildConfig.ModPublicNotificationWebhook) && announcePublic)
            {
                logger.LogInformation($"Sending public webhook to {guildConfig.ModPublicNotificationWebhook}.");

                EmbedBuilder embed = NotificationEmbedCreator.CreatePublicCaseEmbed(modCase, action, actor, caseUser, config.Value.ServiceBaseUrl);

                DiscordMessenger.SendEmbedWebhook(guildConfig.ModPublicNotificationWebhook, embed.Build(), $"<@{modCase.UserId}>");
                logger.LogInformation("Sent public webhook.");
            }

            if (!string.IsNullOrEmpty(guildConfig.ModInternalNotificationWebhook))
            {
                logger.LogInformation($"Sending internal webhook to {guildConfig.ModInternalNotificationWebhook}.");

                EmbedBuilder embed = NotificationEmbedCreator.CreateInternalCaseEmbed(modCase, action, actor, caseUser, config.Value.ServiceBaseUrl);

                DiscordMessenger.SendEmbedWebhook(guildConfig.ModInternalNotificationWebhook, embed.Build(), $"<@{modCase.UserId}>");
                logger.LogInformation("Sent internal webhook.");
            }
        }
        public async Task <IActionResult> PutSpecificItem([FromRoute] ulong guildId, [FromRoute] int caseId, [FromBody] ModCaseForPutDto newValue, [FromQuery] bool sendNotification = true, [FromQuery] bool handlePunishment = true)
        {
            await RequirePermission(guildId, caseId, APIActionPermission.Edit);

            Identity currentIdentity = await GetIdentity();

            if (!await currentIdentity.HasPermissionToExecutePunishment(guildId, newValue.PunishmentType))
            {
                throw new UnauthorizedException();
            }

            var repo = ModCaseRepository.CreateDefault(_serviceProvider, currentIdentity);

            ModCase modCase = await repo.GetModCase(guildId, caseId);

            modCase.Title       = newValue.Title;
            modCase.Description = newValue.Description;
            modCase.UserId      = newValue.UserId;
            if (newValue.OccuredAt.HasValue)
            {
                modCase.OccuredAt = newValue.OccuredAt.Value;
            }
            modCase.Labels            = newValue.Labels.Distinct().ToArray();
            modCase.Others            = newValue.Others;
            modCase.PunishmentType    = newValue.PunishmentType;
            modCase.PunishedUntil     = newValue.PunishedUntil;
            modCase.LastEditedByModId = currentIdentity.GetCurrentUser().Id;

            modCase = await repo.UpdateModCase(modCase, handlePunishment, sendNotification);

            return(Ok(modCase));
        }
Esempio n. 6
0
        public async Task UndoPunishment(ModCase modCase)
        {
            using var scope = _serviceProvider.CreateScope();
            Database database = scope.ServiceProvider.GetRequiredService <Database>();

            List <ModCase> parallelCases = await database.SelectAllModCasesThatHaveParallelPunishment(modCase);

            if (parallelCases.Count != 0)
            {
                _logger.LogInformation("Cannot undo punishment. There exists a parallel punishment for this case");
                return;
            }

            GuildConfig guildConfig;

            try
            {
                guildConfig = await GuildConfigRepository.CreateDefault(scope.ServiceProvider).GetGuildConfig(modCase.GuildId);
            }
            catch (ResourceNotFoundException)
            {
                _logger.LogError($"Cannot execute punishment in guild {modCase.GuildId} - guildconfig not found.");
                return;
            }

            string reason = null;

            try
            {
                Translator translator = scope.ServiceProvider.GetRequiredService <Translator>();
                reason = translator.T(guildConfig).NotificationDiscordAuditLogPunishmentsUndone(modCase.CaseId, modCase.Title.Truncate(400));
            } catch (Exception ex)
            {
                _logger.LogError(ex, $"Failed to resolve audit log reason string for case {modCase.GuildId}/{modCase.CaseId}");
            }
            switch (modCase.PunishmentType)
            {
            case PunishmentType.Mute:
                if (guildConfig.MutedRoles.Length != 0)
                {
                    _logger.LogInformation($"Unmute User {modCase.UserId} in guild {modCase.GuildId} with roles " + string.Join(',', guildConfig.MutedRoles.Select(x => x.ToString())));
                    foreach (ulong role in guildConfig.MutedRoles)
                    {
                        await _discord.RemoveGuildUserRole(modCase.GuildId, modCase.UserId, role, reason);
                    }
                }
                else
                {
                    _logger.LogInformation($"Cannot Unmute User {modCase.UserId} in guild {modCase.GuildId} - mute role undefined.");
                }
                break;

            case PunishmentType.Ban:
                _logger.LogInformation($"Unban User {modCase.UserId} in guild {modCase.GuildId}.");
                await _discord.UnBanUser(modCase.GuildId, modCase.UserId, reason);

                _discord.RemoveFromCache(CacheKey.GuildBan(modCase.GuildId, modCase.UserId));      // refresh ban cache
                break;
            }
        }
        public async Task <IActionResult> CreateItem([FromRoute] ulong guildId, [FromRoute] int caseId, [FromBody] ModCaseCommentForCreateDto comment)
        {
            await RequirePermission(guildId, caseId, APIActionPermission.View);

            Identity currentIdentity = await GetIdentity();

            IUser currentUser = currentIdentity.GetCurrentUser();

            ModCase modCase = await ModCaseRepository.CreateDefault(_serviceProvider, currentIdentity).GetModCase(guildId, caseId);

            // suspects can only comment if last comment was not by him.
            if (!await currentIdentity.HasPermissionOnGuild(DiscordPermission.Moderator, guildId))
            {
                if (modCase.Comments.Any())
                {
                    if (modCase.Comments.Last().UserId == currentUser.Id)
                    {
                        throw new BaseAPIException("Already commented", APIError.LastCommentAlreadyFromSuspect);
                    }
                }
            }

            ModCaseComment createdComment = await ModCaseCommentRepository.CreateDefault(_serviceProvider, currentIdentity).CreateComment(guildId, caseId, comment.Message);

            return(StatusCode(201, new CommentsView(createdComment)));
        }
Esempio n. 8
0
        public async Task <IActionResult> RestoreModCase([FromRoute] ulong guildId, [FromRoute] int caseId)
        {
            await RequirePermission(guildId, DiscordPermission.Moderator);

            ModCase modCase = await ModCaseRepository.CreateDefault(_serviceProvider, await GetIdentity()).RestoreCase(guildId, caseId);

            return(Ok(modCase));
        }
        public async Task <IActionResult> DeleteSpecificItem([FromRoute] ulong guildId, [FromRoute] int caseId, [FromQuery] bool sendNotification = true, [FromQuery] bool handlePunishment = true, [FromQuery] bool forceDelete = false)
        {
            await RequirePermission(guildId, caseId, forceDelete?APIActionPermission.ForceDelete : APIActionPermission.Delete);

            Identity currentIdentity = await GetIdentity();

            ModCase modCase = await ModCaseRepository.CreateDefault(_serviceProvider, currentIdentity).DeleteModCase(guildId, caseId, forceDelete, handlePunishment, sendNotification);

            return(Ok(modCase));
        }
Esempio n. 10
0
        public async Task <IActionResult> DeactivateCase([FromRoute] ulong guildId, [FromRoute] int caseId)
        {
            await RequirePermission(guildId, caseId, APIActionPermission.Edit);

            Identity currentIdentity = await GetIdentity();

            ModCase modCase = await ModCaseRepository.CreateDefault(_serviceProvider, currentIdentity).DeactivateModCase(guildId, caseId);

            return(Ok(modCase));
        }
Esempio n. 11
0
        public async Task <IActionResult> GetSpecificItem([FromRoute] string guildid, [FromRoute] string caseid, [FromRoute] string filename)
        {
            logger.LogInformation($"{HttpContext.Request.Method} {HttpContext.Request.Path} | Incoming request.");
            Identity currentIdentity = await identityManager.GetIdentity(HttpContext);

            User currentUser = await currentIdentity.GetCurrentDiscordUser();

            if (currentUser == null)
            {
                logger.LogInformation($"{HttpContext.Request.Method} {HttpContext.Request.Path} | 401 Unauthorized.");
                return(Unauthorized());
            }
            ModCase modCase = await database.SelectSpecificModCase(guildid, caseid);

            if (!await currentIdentity.HasModRoleOrHigherOnGuild(guildid, this.database) && !config.Value.SiteAdminDiscordUserIds.Contains(currentUser.Id))
            {
                if (modCase == null)
                {
                    logger.LogInformation($"{HttpContext.Request.Method} {HttpContext.Request.Path} | 401 Unauthorized.");
                    return(Unauthorized());
                }
                else
                {
                    if (modCase.UserId != currentUser.Id)
                    {
                        logger.LogInformation($"{HttpContext.Request.Method} {HttpContext.Request.Path} | 401 Unauthorized.");
                        return(Unauthorized());
                    }
                }
            }
            // ========================================================

            var filePath = Path.Combine(config.Value.AbsolutePathToFileUpload, guildid, caseid, filename);

            byte[] fileData = filesHandler.ReadFile(filePath);
            if (fileData == null)
            {
                logger.LogInformation($"{HttpContext.Request.Method} {HttpContext.Request.Path} | 404 Not Found.");
                return(NotFound());
            }

            string contentType = filesHandler.GetContentType(filePath);
            var    cd          = new System.Net.Mime.ContentDisposition
            {
                FileName = filename,
                Inline   = true,
            };

            HttpContext.Response.Headers.Add("Content-Disposition", cd.ToString());
            HttpContext.Response.Headers.Add("Content-Type", contentType);

            return(File(fileData, contentType));
        }
Esempio n. 12
0
        public async Task Ban(
            [Summary("title", "The title of the modcase")] string title,
            [Summary("user", "User to punish")] IUser user,
            [Choice("None", 0)]
            [Choice("1 Hour", 1)]
            [Choice("1 Day", 24)]
            [Choice("1 Week", 168)]
            [Choice("1 Month", 672)]
            [Summary("hours", "How long the punishment should be")] long punishedForHours             = 0,
            [Summary("description", "The description of the modcase")] string description             = "",
            [Summary("dm-notification", "Whether to send a dm notification")] bool sendDmNotification = true,
            [Summary("public-notification", "Whether to send a public webhook notification")] bool sendPublicNotification    = true,
            [Summary("execute-punishment", "Whether to execute the punishment or just register it.")] bool executePunishment = true)
        {
            await Context.Interaction.DeferAsync(ephemeral : !sendPublicNotification);

            ModCase modCase = new()
            {
                Title   = title,
                GuildId = Context.Guild.Id,
                UserId  = user.Id,
                ModId   = CurrentIdentity.GetCurrentUser().Id
            };

            if (string.IsNullOrEmpty(description))
            {
                modCase.Description = title;
            }
            else
            {
                modCase.Description = description;
            }
            modCase.PunishmentType   = PunishmentType.Ban;
            modCase.PunishmentActive = executePunishment;
            modCase.PunishedUntil    = DateTime.UtcNow.AddHours(punishedForHours);
            if (punishedForHours == 0)
            {
                modCase.PunishedUntil = null; // Permanent ban.
            }
            modCase.CreationType = CaseCreationType.ByCommand;

            ModCase created = await ModCaseRepository.CreateDefault(ServiceProvider, CurrentIdentity).CreateModCase(modCase, executePunishment, sendPublicNotification, sendDmNotification);

            string url = $"{Config.GetBaseUrl()}/guilds/{created.GuildId}/cases/{created.CaseId}";
            await Context.Interaction.ModifyOriginalResponseAsync((MessageProperties msg) =>
            {
                msg.Content = Translator.T().CmdPunish(created.CaseId, url);
            });;
        }
    }
Esempio n. 13
0
        public async Task AnnounceFile(string filename, ModCase modCase, User actor, RestAction action)
        {
            logger.LogInformation($"Announcing file {filename} in case {modCase.CaseId} in guild {modCase.GuildId}.");

            GuildConfig guildConfig = await dbContext.SelectSpecificGuildConfig(modCase.GuildId);

            if (!string.IsNullOrEmpty(guildConfig.ModInternalNotificationWebhook))
            {
                logger.LogInformation($"Sending internal webhook to {guildConfig.ModInternalNotificationWebhook}.");

                EmbedBuilder embed = NotificationEmbedCreator.CreateInternalFilesEmbed(filename, modCase, action, actor, config.Value.ServiceBaseUrl);

                DiscordMessenger.SendEmbedWebhook(guildConfig.ModInternalNotificationWebhook, embed.Build());
                logger.LogInformation("Sent internal webhook.");
            }
        }
Esempio n. 14
0
        public async Task <IActionResult> DeleteSpecificItem([FromRoute] string guildid, [FromRoute] string caseid, [FromRoute] string filename)
        {
            logger.LogInformation($"{HttpContext.Request.Method} {HttpContext.Request.Path} | Incoming request.");
            Identity currentIdentity = await identityManager.GetIdentity(HttpContext);

            User currentUser = await currentIdentity.GetCurrentDiscordUser();

            if (currentUser == null)
            {
                logger.LogInformation($"{HttpContext.Request.Method} {HttpContext.Request.Path} | 401 Unauthorized.");
                return(Unauthorized());
            }
            if (!await currentIdentity.HasModRoleOrHigherOnGuild(guildid, this.database) && !config.Value.SiteAdminDiscordUserIds.Contains(currentUser.Id))
            {
                logger.LogInformation($"{HttpContext.Request.Method} {HttpContext.Request.Path} | 401 Unauthorized.");
                return(Unauthorized());
            }
            // ========================================================

            ModCase modCase = await database.SelectSpecificModCase(guildid, caseid);

            if (modCase == null)
            {
                logger.LogInformation($"{HttpContext.Request.Method} {HttpContext.Request.Path} | 400 Modcase not found.");
                return(BadRequest("Modcase not found."));
            }

            string filePath = Path.Combine(config.Value.AbsolutePathToFileUpload, guildid, caseid, filename);

            if (!filesHandler.FileExists(filePath))
            {
                logger.LogInformation($"{HttpContext.Request.Method} {HttpContext.Request.Path} | 404 File not found.");
                return(NotFound("File not found."));
            }

            filesHandler.DeleteFile(filePath);

            logger.LogInformation($"{HttpContext.Request.Method} {HttpContext.Request.Path} | Sending notification.");
            try {
                await discordAnnouncer.AnnounceFile(filename, modCase, currentUser, RestAction.Deleted);
            }
            catch (Exception e) {
                logger.LogError(e, "Failed to announce file.");
            }

            return(Ok());
        }
Esempio n. 15
0
        public async Task <IActionResult> GetSpecificItem([FromRoute] string guildid, [FromRoute] string modcaseid)
        {
            logger.LogInformation($"{HttpContext.Request.Method} {HttpContext.Request.Path} | Incoming request.");
            Identity currentIdentity = await identityManager.GetIdentity(HttpContext);

            User currentUser = await currentIdentity.GetCurrentDiscordUser();

            if (currentUser == null)
            {
                logger.LogInformation($"{HttpContext.Request.Method} {HttpContext.Request.Path} | 401 Unauthorized.");
                return(Unauthorized());
            }
            ModCase modCase = await database.SelectSpecificModCase(guildid, modcaseid);

            if (!await currentIdentity.HasModRoleOrHigherOnGuild(guildid, this.database) && !config.Value.SiteAdminDiscordUserIds.Contains(currentUser.Id))
            {
                if (modCase == null)
                {
                    logger.LogInformation($"{HttpContext.Request.Method} {HttpContext.Request.Path} | 401 Unauthorized.");
                    return(Unauthorized());
                }
                else
                {
                    if (modCase.UserId != currentUser.Id)
                    {
                        logger.LogInformation($"{HttpContext.Request.Method} {HttpContext.Request.Path} | 401 Unauthorized.");
                        return(Unauthorized());
                    }
                }
            }
            // ========================================================

            if (await database.SelectSpecificGuildConfig(guildid) == null)
            {
                logger.LogInformation($"{HttpContext.Request.Method} {HttpContext.Request.Path} | 400 Guild not registered.");
                return(BadRequest("Guild not registered."));
            }

            if (modCase == null)
            {
                logger.LogInformation($"{HttpContext.Request.Method} {HttpContext.Request.Path} | 404 ModCase not found.");
                return(NotFound());
            }

            logger.LogInformation($"{HttpContext.Request.Method} {HttpContext.Request.Path} | 200 Returning ModCase.");
            return(Ok(modCase));
        }
Esempio n. 16
0
        public async Task <IActionResult> PostItem([FromRoute] string guildid, [FromRoute] string caseid, [FromForm] UploadedFile uploadedFile)
        {
            logger.LogInformation($"{HttpContext.Request.Method} {HttpContext.Request.Path} | Incoming request.");
            Identity currentIdentity = await identityManager.GetIdentity(HttpContext);

            User currentUser = await currentIdentity.GetCurrentDiscordUser();

            if (currentUser == null)
            {
                logger.LogInformation($"{HttpContext.Request.Method} {HttpContext.Request.Path} | 401 Unauthorized.");
                return(Unauthorized());
            }
            if (!await currentIdentity.HasModRoleOrHigherOnGuild(guildid, this.database) && !config.Value.SiteAdminDiscordUserIds.Contains(currentUser.Id))
            {
                logger.LogInformation($"{HttpContext.Request.Method} {HttpContext.Request.Path} | 401 Unauthorized.");
                return(Unauthorized());
            }
            // ========================================================

            if (uploadedFile.File == null)
            {
                logger.LogInformation($"{HttpContext.Request.Method} {HttpContext.Request.Path} | 400 No file provided.");
                return(BadRequest());
            }

            ModCase modCase = await database.SelectSpecificModCase(guildid, caseid);

            if (modCase == null)
            {
                logger.LogInformation($"{HttpContext.Request.Method} {HttpContext.Request.Path} | 400 Modcase not found.");
                return(BadRequest("Modcase not found."));
            }

            string uniqueFileName = await filesHandler.SaveFile(uploadedFile.File, Path.Combine(config.Value.AbsolutePathToFileUpload, guildid, caseid));

            logger.LogInformation($"{HttpContext.Request.Method} {HttpContext.Request.Path} | Sending notification.");
            try {
                await discordAnnouncer.AnnounceFile(uniqueFileName, modCase, currentUser, RestAction.Created);
            }
            catch (Exception e) {
                logger.LogError(e, "Failed to announce file.");
            }

            return(StatusCode(201, new { path = uniqueFileName }));
        }
Esempio n. 17
0
        public async Task <IActionResult> GetAllItems([FromRoute] string guildid, [FromRoute] string caseid)
        {
            logger.LogInformation($"{HttpContext.Request.Method} {HttpContext.Request.Path} | Incoming request.");
            Identity currentIdentity = await identityManager.GetIdentity(HttpContext);

            User currentUser = await currentIdentity.GetCurrentDiscordUser();

            if (currentUser == null)
            {
                logger.LogInformation($"{HttpContext.Request.Method} {HttpContext.Request.Path} | 401 Unauthorized.");
                return(Unauthorized());
            }
            ModCase modCase = await database.SelectSpecificModCase(guildid, caseid);

            if (!await currentIdentity.HasModRoleOrHigherOnGuild(guildid, this.database) && !config.Value.SiteAdminDiscordUserIds.Contains(currentUser.Id))
            {
                if (modCase == null)
                {
                    logger.LogInformation($"{HttpContext.Request.Method} {HttpContext.Request.Path} | 401 Unauthorized.");
                    return(Unauthorized());
                }
                else
                {
                    if (modCase.UserId != currentUser.Id)
                    {
                        logger.LogInformation($"{HttpContext.Request.Method} {HttpContext.Request.Path} | 401 Unauthorized.");
                        return(Unauthorized());
                    }
                }
            }
            // ========================================================

            var uploadDir = Path.Combine(config.Value.AbsolutePathToFileUpload, guildid, caseid);

            FileInfo[] files = filesHandler.GetFilesByDirectory(uploadDir);
            if (files == null)
            {
                logger.LogInformation($"{HttpContext.Request.Method} {HttpContext.Request.Path} | Returning empty list.");
                return(Ok(new { names = new List <string>() }));
            }

            logger.LogInformation($"{HttpContext.Request.Method} {HttpContext.Request.Path} | 200 Returning file list.");
            return(Ok(new { names = files.Select(x => x.Name).ToList() }));
        }
Esempio n. 18
0
        public async Task SendModLog(IGuild guild, ModCase modCase)
        {
            //Retrieve guild settings
            var guildSettings = _botContext.Guilds.AsNoTracking().FirstOrDefault(x => x.GuildId == guild.Id);

            if (guildSettings == null)
            {
                return;
            }

            if (guildSettings.ModerationChannel == 0)
            {
                return;
            }

            var moderationChannel = await guild.GetTextChannelAsync(guildSettings.ModerationChannel);

            await moderationChannel.SendMessageAsync(embed : ModerationFormats.ModLogEmbed(modCase));
        }
Esempio n. 19
0
        /// <summary>Kick specified user from the server with reason.
        /// </summary>
        public async Task <Embed> KickAsync(IUser user, string reason, SocketCommandContext context)
        {
            await SendPunishmentDm(user, ModerationFormats.DmPunishmentEmbed("You have been kicked!",
                                                                             $"You have been kicked from {context.Guild.Name}", context.Guild));

            await((IGuildUser)user).KickAsync(reason);

            var caseId = await GenerateModCaseId(context.Guild.Id);

            //Create mod case
            var modCase = new ModCase(context, user, caseId, PunishmentType.Kick, reason);
            await _botContext.ModCases.AddAsync(modCase);

            await _botContext.SaveChangesAsync();

            await SendModLog(context.Guild, modCase);

            return(ModerationFormats.CreateModerationEmbed(user, $"{user} kicked", $"{user} was kicked from the server for: {reason ?? "_No reason_"}.", Color.DarkGrey));
        }
Esempio n. 20
0
        protected async Task RequirePermission(ulong guildId, int caseId, APIActionPermission permission)
        {
            Identity currentIdentity = await GetIdentity();

            ModCase modCase = await ModCaseRepository.CreateDefault(_serviceProvider, currentIdentity).GetModCase(guildId, caseId);

            if (modCase == null)
            {
                throw new ResourceNotFoundException();
            }
            if (!await currentIdentity.IsAllowedTo(permission, modCase))
            {
                throw new UnauthorizedException();
            }
            if (modCase.MarkedToDeleteAt != null && permission == APIActionPermission.Edit)
            {
                throw new CaseMarkedToBeDeletedException();
            }
        }
Esempio n. 21
0
        /// <summary> Creates an embed with specified mod case information, used for a quick lookup about mod case info. </summary>
        /// <returns> The created embed. </returns>
        public static Embed LookupEmbed(ModCase modCase, string user, string mod)
        {
            var punishment = new EmbedFieldBuilder().WithName("Punishment Type");

            switch (modCase.PunishmentType)
            {
            case PunishmentType.Mute:
                punishment.WithValue("Mute");
                break;

            case PunishmentType.VMute:
                punishment.WithValue("Voice Mute");
                break;

            case PunishmentType.Kick:
                punishment.WithValue("Kick");
                break;

            case PunishmentType.Ban:
                punishment.WithValue("Ban");
                break;
            }

            var userNameField = new EmbedFieldBuilder().WithName("User Name").WithValue(user)
                                .WithIsInline(true);
            var userIdField = new EmbedFieldBuilder().WithName("User ID").WithValue(modCase.UserId)
                              .WithIsInline(true);
            var responsibleModField = new EmbedFieldBuilder().WithName("Responsible Mod").WithValue(mod)
                                      .WithIsInline(true);
            var reasonField = new EmbedFieldBuilder().WithName("Reason").WithValue(modCase.Reason ?? "_No reason_")
                              .WithIsInline(true);

            var embed = new EmbedBuilder()
                        .WithTitle($"Case #{modCase.ModCaseId}")
                        .WithFields(punishment, userNameField, userIdField, responsibleModField, reasonField)
                        .WithColor(Color.LightGrey)
                        .WithTimestamp(modCase.DateTime);

            return(embed.Build());
        }
Esempio n. 22
0
        public async Task Kick(
            [Summary("title", "The title of the modcase")] string title,
            [Summary("user", "User to punish")] IUser user,
            [Summary("description", "The description of the modcase")] string description             = "",
            [Summary("dm-notification", "Whether to send a dm notification")] bool sendDmNotification = true,
            [Summary("public-notification", "Whether to send a public webhook notification")] bool sendPublicNotification    = true,
            [Summary("execute-punishment", "Whether to execute the punishment or just register it.")] bool executePunishment = true)
        {
            await Context.Interaction.DeferAsync(ephemeral : !sendPublicNotification);

            ModCase modCase = new()
            {
                Title   = title,
                GuildId = Context.Guild.Id,
                UserId  = user.Id,
                ModId   = CurrentIdentity.GetCurrentUser().Id
            };

            if (string.IsNullOrEmpty(description))
            {
                modCase.Description = title;
            }
            else
            {
                modCase.Description = description;
            }
            modCase.PunishmentType   = PunishmentType.Kick;
            modCase.PunishmentActive = executePunishment;
            modCase.PunishedUntil    = null;
            modCase.CreationType     = CaseCreationType.ByCommand;

            ModCase created = await ModCaseRepository.CreateDefault(ServiceProvider, CurrentIdentity).CreateModCase(modCase, executePunishment, sendPublicNotification, sendDmNotification);

            string url = $"{Config.GetBaseUrl()}/guilds/{created.GuildId}/cases/{created.CaseId}";
            await Context.Interaction.ModifyOriginalResponseAsync((MessageProperties msg) =>
            {
                msg.Content = Translator.T().CmdPunish(created.CaseId, url);
            });;
        }
    }
Esempio n. 23
0
 protected bool Contains(ModCase obj, string search)
 {
     if (obj == null)
     {
         return(false);
     }
     return(Contains(obj.Title, search) ||
            Contains(obj.Description, search) ||
            Contains(obj.GetPunishment(_translator), search) ||
            Contains(obj.Username, search) ||
            Contains(obj.Discriminator, search) ||
            Contains(obj.Nickname, search) ||
            Contains(obj.UserId, search) ||
            Contains(obj.ModId, search) ||
            Contains(obj.LastEditedByModId, search) ||
            Contains(obj.CreatedAt, search) ||
            Contains(obj.OccuredAt, search) ||
            Contains(obj.LastEditedAt, search) ||
            Contains(obj.Labels, search) ||
            Contains(obj.CaseId.ToString(), search) ||
            Contains($"#{obj.CaseId}", search));
 }
Esempio n. 24
0
        /// <summary> Creates a mod log embed according to specified mod case. </summary>
        /// <returns> The created embed. </returns>
        public static Embed ModLogEmbed(ModCase modCase)
        {
            //Fields
            var userNameField = new EmbedFieldBuilder().WithName("User Name").WithValue(modCase.UserName)
                                .WithIsInline(true);
            var userIdField = new EmbedFieldBuilder().WithName("User ID").WithValue(modCase.UserId)
                              .WithIsInline(true);
            var responsibleModField = new EmbedFieldBuilder().WithName("Responsible Mod").WithValue(modCase.ModName)
                                      .WithIsInline(true);
            var reasonField = new EmbedFieldBuilder().WithName("Reason").WithValue(modCase.Reason ?? "_No reason_")
                              .WithIsInline(true);

            var embed = new EmbedBuilder()
                        .WithTimestamp(modCase.DateTime)
                        .WithColor(Color.DarkPurple)
                        .WithFields(userNameField, userIdField, responsibleModField, reasonField);

            //Change title according to punishment type
            switch (modCase.PunishmentType)
            {
            case PunishmentType.Ban:
                embed.WithTitle($"{modCase.UserName} banned | Case #{modCase.ModCaseId}");
                break;

            case PunishmentType.Kick:
                embed.WithTitle($"{modCase.UserName} kicked | Case #{modCase.ModCaseId}");
                break;

            case PunishmentType.Mute:
                embed.WithTitle($"{modCase.UserName} muted | Case #{modCase.ModCaseId}");
                break;

            case PunishmentType.VMute:
                embed.WithTitle($"{modCase.UserName} voice muted | Case #{modCase.ModCaseId}");
                break;
            }

            return(embed.Build());
        }
Esempio n. 25
0
        /// <summary>
        ///     Ban specified user from the server with reason.
        /// </summary>
        public async Task <Embed> BanAsync(IUser user, int pruneDays, string reason, SocketCommandContext context)
        {
            await context.Message.DeleteAsync();

            if (pruneDays < 0 || pruneDays > 7)
            {
                return(CustomFormats.CreateErrorEmbed("Prune days must be between 0 and 7"));
            }

            //Check if user is already banned
            var isBanned = await context.Guild.GetBanAsync(user);

            if (isBanned != null)
            {
                return(CustomFormats.CreateErrorEmbed($"{user.Username} is already banned!"));
            }

            await SendPunishmentDm(user, ModerationFormats.DmPunishmentEmbed("You have been banned!",
                                                                             $"You have been permanently banned from {context.Guild.Name}", context.Guild));

            _banCache.Set(user.Id, new CacheModel(context.Guild.Id), TimeSpan.FromSeconds(5));

            //Ban user
            await context.Guild.AddBanAsync(user, pruneDays, reason);

            var caseId = await GenerateModCaseId(context.Guild.Id);

            //Create modCase
            var modCase = new ModCase(context.User, context.Guild.Id, user, caseId, PunishmentType.Ban, reason);
            await _botContext.ModCases.AddAsync(modCase);

            await _botContext.SaveChangesAsync();

            await SendModLog(context.Guild, modCase);

            return(ModerationFormats.CreateModerationEmbed(user, $"{user} banned",
                                                           $"{user} was banned from the server for: {reason ?? "_No reason_"}.", Color.DarkGrey));
        }
Esempio n. 26
0
        private async Task AnnounceFile(UploadedFile file, ModCase modCase, IUser actor, RestAction action)
        {
            using var scope = _serviceProvider.CreateScope();

            _logger.LogInformation($"Announcing file {modCase.GuildId}/{modCase.CaseId}/{file.Name}.");

            GuildConfig guildConfig = await GuildConfigRepository.CreateDefault(scope.ServiceProvider).GetGuildConfig(modCase.GuildId);

            if (!string.IsNullOrEmpty(guildConfig.ModInternalNotificationWebhook))
            {
                _logger.LogInformation($"Sending internal webhook for file {modCase.GuildId}/{modCase.CaseId}/{file.Name} to {guildConfig.ModInternalNotificationWebhook}.");
                try
                {
                    EmbedBuilder embed = await file.CreateFileEmbed(modCase, action, actor, scope.ServiceProvider);

                    await _discordAPI.ExecuteWebhook(guildConfig.ModInternalNotificationWebhook, embed.Build());
                }
                catch (Exception e)
                {
                    _logger.LogError(e, $"Error while announcing file {modCase.GuildId}/{modCase.CaseId}/{file.Name} to {guildConfig.ModInternalNotificationWebhook}.");
                }
            }
        }
Esempio n. 27
0
        public async Task UndoPunishment(ModCase modCase, IDatabase database)
        {
            List <ModCase> parallelCases = await database.SelectAllModCasesThatHaveParallelPunishment(modCase);

            if (parallelCases.Count != 0)
            {
                logger.LogInformation("Cannot undo punishment. There exists a parallel punishment for this case");
                return;
            }
            GuildConfig guildConfig = await database.SelectSpecificGuildConfig(modCase.GuildId);

            if (guildConfig == null)
            {
                logger.LogError($"Punisher: Cannot execute punishment in guild {modCase.GuildId} - guildconfig not found.");
                return;
            }
            switch (modCase.PunishmentType)
            {
            case PunishmentType.Mute:
                if (guildConfig.MutedRoleId != null)
                {
                    logger.LogInformation($"Punisher: Unmute User {modCase.UserId} in guild {modCase.GuildId} with role {guildConfig.MutedRoleId}.");
                    await discord.RemoveGuildUserRole(modCase.GuildId, modCase.UserId, guildConfig.MutedRoleId);
                }
                else
                {
                    logger.LogInformation($"Punisher: Cannot Unmute User {modCase.UserId} in guild {modCase.GuildId} - mute role undefined.");
                }
                break;

            case PunishmentType.Ban:
                logger.LogInformation($"Punisher: Unban User {modCase.UserId} in guild {modCase.GuildId}.");
                await discord.UnBanUser(modCase.GuildId, modCase.UserId);

                break;
            }
        }
Esempio n. 28
0
        public async Task ExecutePunishment(ModCase modCase, IDatabase database)
        {
            GuildConfig guildConfig = await database.SelectSpecificGuildConfig(modCase.GuildId);

            if (guildConfig == null)
            {
                logger.LogError($"Punisher: Cannot execute punishment in guild {modCase.GuildId} - guildconfig not found.");
                return;
            }
            switch (modCase.PunishmentType)
            {
            case PunishmentType.Mute:
                if (guildConfig.MutedRoleId != null)
                {
                    logger.LogInformation($"Punisher: Mute User {modCase.UserId} in guild {modCase.GuildId} with role {guildConfig.MutedRoleId}.");
                    await discord.GrantGuildUserRole(modCase.GuildId, modCase.UserId, guildConfig.MutedRoleId);
                }
                else
                {
                    logger.LogInformation($"Punisher: Cannot Mute User {modCase.UserId} in guild {modCase.GuildId} - mute role undefined.");
                }
                break;

            case PunishmentType.Ban:
                logger.LogInformation($"Punisher: Ban User {modCase.UserId} in guild {modCase.GuildId}.");
                await discord.BanUser(modCase.GuildId, modCase.UserId);

                break;

            case PunishmentType.Kick:
                logger.LogInformation($"Punisher: Kick User {modCase.UserId} in guild {modCase.GuildId}.");
                await discord.KickGuildUser(modCase.GuildId, modCase.UserId);

                break;
            }
        }
Esempio n. 29
0
        public static async Task <EmbedBuilder> CreateModcaseEmbed(this ModCase modCase, RestAction action, IUser actor, IServiceProvider provider, IUser suspect = null, bool isInternal = true)
        {
            var translator = provider.GetService <Translator>();

            await translator.SetContext(modCase.GuildId);

            EmbedBuilder embed;

            if (isInternal)
            {
                embed = CreateBasicEmbed(action, provider, actor);
            }
            else
            {
                embed = CreateBasicEmbed(action, provider);
            }

            // Thumbnail
            if (suspect != null)
            {
                embed.WithThumbnailUrl(suspect.GetAvatarOrDefaultUrl());
            }

            // Description
            embed.AddField($"**{translator.T().Description()}**", modCase.Description.Truncate(1000));

            // Title
            embed.Title = $"#{modCase.CaseId} {modCase.Title}";

            // Footer
            embed.WithFooter($"UserId: {modCase.UserId} | CaseId: {modCase.CaseId}");

            // Description
            switch (action)
            {
            case RestAction.Updated:
                if (isInternal)
                {
                    embed.Description = translator.T().NotificationModcaseUpdateInternal(modCase, actor);
                }
                else
                {
                    embed.Description = translator.T().NotificationModcaseUpdatePublic(modCase);
                }
                break;

            case RestAction.Deleted:
                if (isInternal)
                {
                    embed.Description = translator.T().NotificationModcaseDeleteInternal(modCase, actor);
                }
                else
                {
                    embed.Description = translator.T().NotificationModcaseDeletePublic(modCase);
                }
                break;

            case RestAction.Created:
                if (isInternal)
                {
                    embed.Description = translator.T().NotificationModcaseCreateInternal(modCase, actor);
                }
                else
                {
                    embed.Description = translator.T().NotificationModcaseCreatePublic(modCase);
                }
                break;
            }

            // Punishment
            embed.AddField($"{SCALES_EMOTE} - {translator.T().Punishment()}", modCase.GetPunishment(translator), true);
            if (modCase.PunishedUntil != null)
            {
                embed.AddField($"{ALARM_CLOCK} - {translator.T().PunishmentUntil()}", modCase.PunishedUntil.Value.ToDiscordTS(), true);
            }

            // Labels
            if (modCase.Labels.Length != 0)
            {
                StringBuilder sb = new();
                foreach (string label in modCase.Labels)
                {
                    sb.Append($"`{label}` ");
                    if (sb.ToString().Length > 1000)
                    {
                        break;
                    }
                }
                embed.AddField($"{SCROLL_EMOTE} - {translator.T().Labels()}", sb.ToString(), modCase.PunishedUntil == null);
            }

            return(embed);
        }
Esempio n. 30
0
        public static async Task <EmbedBuilder> CreateFileEmbed(this UploadedFile file, ModCase modCase, RestAction action, IUser actor, IServiceProvider provider)
        {
            var translator = provider.GetService <Translator>();

            await translator.SetContext(modCase.GuildId);

            EmbedBuilder embed = CreateBasicEmbed(action, provider, actor);

            // Thumbnail
            embed.WithThumbnailUrl(actor.GetAvatarOrDefaultUrl());

            // Footer
            embed.WithFooter($"UserId: {actor.Id} | CaseId: {modCase.CaseId}");

            // Filename
            embed.AddField($"**{translator.T().Filename()}**", file.Name.Truncate(1000));

            switch (action)
            {
            case RestAction.Updated:
                embed.Description = translator.T().NotificationModcaseFileUpdate(actor);
                embed.Title       = $"**{translator.T().NotificationFilesUpdate().ToUpper()}** - #{modCase.CaseId} {modCase.Title}";
                break;

            case RestAction.Deleted:
                embed.Description = translator.T().NotificationModcaseFileDelete(actor);
                embed.Title       = $"**{translator.T().NotificationFilesDelete().ToUpper()}** - #{modCase.CaseId} {modCase.Title}";
                break;

            case RestAction.Created:
                embed.Description = translator.T().NotificationModcaseFileCreate(actor);
                embed.Title       = $"**{translator.T().NotificationFilesCreate().ToUpper()}** - #{modCase.CaseId} {modCase.Title}";
                break;
            }

            return(embed);
        }