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; } }
/// <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)); }
/// <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)); }
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)); }
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))); }
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)); }
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)); }
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)); }
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); });; } }
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."); } }
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()); }
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)); }
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 })); }
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() })); }
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)); }
/// <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)); }
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(); } }
/// <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()); }
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); });; } }
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)); }
/// <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()); }
/// <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)); }
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}."); } } }
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; } }
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; } }
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); }
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); }