public async Task <IResult> ShowServerStatsAsync() { var getGuild = await _guildAPI.GetGuildAsync(_context.GuildID.Value, ct : this.CancellationToken); if (!getGuild.IsSuccess) { return(getGuild); } var guild = getGuild.Entity; var eb = CreateGuildInfoEmbed(guild); return(await _feedback.SendContextualEmbedAsync(eb, ct : this.CancellationToken)); }
public async Task <IResult> ShowServerSettingsAsync() { var getGuild = await _guildAPI.GetGuildAsync(_context.GuildID.Value); if (!getGuild.IsSuccess) { return(getGuild); } var guild = getGuild.Entity; var getSettings = await _moderation.GetOrCreateServerSettingsAsync(guild.ID); if (!getSettings.IsSuccess) { return(getSettings); } var settings = getSettings.Entity; var getGuildIcon = CDN.GetGuildIconUrl(guild); var embedFields = new List <EmbedField>(); var eb = new Embed { Colour = _feedback.Theme.Secondary, Title = guild.Name, Thumbnail = getGuildIcon.IsSuccess ? new EmbedThumbnail(getGuildIcon.Entity.ToString()) : default(Optional <IEmbedThumbnail>), Fields = embedFields }; var moderationLogChannelName = settings.ModerationLogChannel.HasValue ? $"<#{settings.ModerationLogChannel}>" : "None"; embedFields.Add(new EmbedField("Moderation Log Channel", moderationLogChannelName)); var monitoringChannelName = settings.MonitoringChannel.HasValue ? $"<#{settings.MonitoringChannel}>" : "None"; embedFields.Add(new EmbedField("Event Monitor Channel", monitoringChannelName)); embedFields.Add(new EmbedField("Warning Threshold", settings.WarningThreshold.ToString())); return(await _feedback.SendContextualEmbedAsync(eb)); }
public async Task <IResult> ListAsync() { var canViewPatterns = _messageContentPatternService.CanViewPatterns(); if (_context is not MessageContext) { return(Result.FromError(new InvalidOperationError("Not a message context"))); } if (!canViewPatterns) { await _channelApi.CreateMessageAsync(_context.ChannelID, $"<@!{_context.User.ID}> does not have permission to view patterns blocked or allowed in guild {_context.GuildID.Value.Value}!", allowedMentions : new NoAllowedMentions()); return(Result.FromError(new InvalidOperationError("You do not have permission to view patterns blocked or allowed in this guild!"))); } var patterns = await _messageContentPatternService.GetPatterns(_context.GuildID.Value.Value); if (!patterns.Any()) { await _channelApi.CreateMessageAsync(_context.ChannelID, $"Guild {_context.GuildID.Value.Value} does not have any patterns set up, get started with `!pattern block` or `!pattern allow`"); return(Result.FromError(new InvalidOperationError("This guild does not have any patterns set up, get started with `!pattern block` or `!pattern allow`"))); } var blocked = patterns.Any(x => x.Type == MessageContentPatternType.Blocked) ? string.Join(Environment.NewLine, patterns.Where(x => x.Type == MessageContentPatternType.Blocked).Select(x => $"- `{x.Pattern}`")) : "There are no blocked patterns"; var allowed = patterns.Any(x => x.Type == MessageContentPatternType.Allowed) ? string.Join(Environment.NewLine, patterns.Where(x => x.Type == MessageContentPatternType.Allowed).Select(x => $"- `{x.Pattern}`")) : "There are no allowed patterns"; var guild = await _guildApi.GetGuildAsync(_context.GuildID.Value); var embed = new Embed( Title: $"Message Patterns for {guild.Entity!.Name}", Description: new Optional <string>("Allowed patterns supersede those that are blocked."), Fields: Enumerable.Empty <IEmbedField>().Concat(blocked.EnumerateLongTextAsFieldBuilders("Blocked")) .Concat(allowed.EnumerateLongTextAsFieldBuilders("Allowed")).ToList() ); await _channelApi.CreateMessageAsync(_context.ChannelID, embeds : new[] { embed }); return(Result.FromSuccess()); }
public async Task <IResult> ShowServerAsync() { var getServerResult = await _servers.GetOrRegisterServerAsync(_context.GuildID.Value); if (!getServerResult.IsSuccess) { return(getServerResult); } var getGuild = await _guildAPI.GetGuildAsync(_context.GuildID.Value, ct : this.CancellationToken); if (!getGuild.IsSuccess) { return(getGuild); } var guild = getGuild.Entity; var server = getServerResult.Entity; var fields = new[]
/// <inheritdoc /> public async Task <Result <QueryResult> > Handle(Query request, CancellationToken cancellationToken) { var getGuildInfoResult = await _guildApi.GetGuildAsync(request.GuildId, ct : cancellationToken); if (!getGuildInfoResult.IsSuccess) { return(Result <QueryResult> .FromError(getGuildInfoResult)); } var guildInfo = getGuildInfoResult.Entity; if (guildInfo is null) { return(new NotFoundError("Guild not found.")); } Uri?iconUrl; if (guildInfo.Icon is not null) { var getIconUrlResult = CDN.GetGuildIconUrl(request.GuildId, guildInfo.Icon, CDNImageFormat.PNG); iconUrl = !getIconUrlResult.IsSuccess ? null : getIconUrlResult.Entity; } else { iconUrl = null; } return(new QueryResult( guildInfo.Name, guildInfo.OwnerID, guildInfo.MaxMembers.HasValue ? guildInfo.MaxMembers.Value : null, guildInfo.Roles.Skip(1).ToList(), iconUrl )); }
/// <inheritdoc /> public async Task <Result <ModerationAction> > Handle(Command request, CancellationToken cancellationToken) { var banModerationAction = new ModerationAction ( moderationActionType: ModerationActionType.Ban, guildId: request.GuildId.Value, isActive: true, reason: request.Reason, date: DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), userDiscordId: request.UserDiscordId?.Value, userIgn: request.UserIgn, expiryDate: request.ExpiryDate ); if (request.UserIgn is not null) { var proto = new GenericCommand { DefaultCommand = "ban", DiscordCommandName = "ban", DiscordChannelId = request.ChannelId.Value.ToString(), Args = { request.UserIgn } }; await _ps.BroadcastMessage(proto); } if (request.UserDiscordId is not null) { var guildResult = await _guildApi.GetGuildAsync(request.GuildId, ct : cancellationToken); if (!guildResult.IsSuccess) { return(Result <ModerationAction> .FromError(guildResult.Error)); } var banResult = await _guildApi.CreateGuildBanAsync( request.GuildId, request.UserDiscordId.Value, reason : request.Reason, ct : cancellationToken ); if (!banResult.IsSuccess) { return(Result <ModerationAction> .FromError(banResult.Error)); } var guildName = guildResult.Entity.Name; var embed = new Embed { Title = $"You have been banned from {guildName}.", Colour = _colourPalette.Red, Thumbnail = EmbedProperties.MmccLogoThumbnail, Timestamp = DateTimeOffset.UtcNow, Fields = new List <EmbedField> { new("Reason", request.Reason, false), new( "Expires at", request.ExpiryDate is null ? "Permanent" : $"{DateTimeOffset.FromUnixTimeMilliseconds(request.ExpiryDate.Value).UtcDateTime} UTC" , false ), new( "Appeals", $"You can appeal this decision **[here]({_discordSettings.AppealsUrl})**." ) } }; var createDmResult = await _userApi.CreateDMAsync(request.UserDiscordId.Value, cancellationToken); const string errMsg = "Failed to send a DM notification to the user. It may be because they have blocked the bot. This error can in most cases be ignored."; if (!createDmResult.IsSuccess || createDmResult.Entity is null) { _logger.LogWarning(errMsg); } else { var sendDmResult = await _channelApi.CreateMessageAsync(createDmResult.Entity.ID, embeds : new[] { embed }, ct : cancellationToken); if (!sendDmResult.IsSuccess) { _logger.LogWarning(errMsg); } } } try { await _context.AddAsync(banModerationAction, cancellationToken); await _context.SaveChangesAsync(cancellationToken); } catch (Exception e) { return(e); } return(banModerationAction); }
/// <inheritdoc /> public async Task <Result <ModerationAction> > Handle(Command request, CancellationToken cancellationToken) { var warnModerationAction = new ModerationAction ( moderationActionType: ModerationActionType.Warn, guildId: request.GuildId.Value, isActive: true, reason: request.Reason, date: DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(), userDiscordId: request.UserDiscordId?.Value, userIgn: request.UserIgn, expiryDate: null ); if (request.UserIgn is not null) { var protobufMessage = new ChatMessage { ServerId = "MMCC", Message = $"You have been warned, @{request.UserIgn}. Reason: {request.Reason}", MessageOffset = 5 }; await _ps.BroadcastMessage(protobufMessage); } if (request.UserDiscordId is not null) { var guildResult = await _guildApi.GetGuildAsync(request.GuildId, ct : cancellationToken); if (!guildResult.IsSuccess) { return(Result <ModerationAction> .FromError(guildResult.Error)); } var guildName = guildResult.Entity.Name; var embed = new Embed { Title = $"You have been warned in {guildName}.", Colour = _colourPalette.Yellow, Thumbnail = EmbedProperties.MmccLogoThumbnail, Timestamp = DateTimeOffset.UtcNow, Fields = new List <EmbedField> { new("Reason", request.Reason, false) } }; var createDmResult = await _userApi.CreateDMAsync(request.UserDiscordId.Value, cancellationToken); const string errMsg = "Failed to send a DM notification to the user. It may be because they have blocked the bot. This error can in most cases be ignored."; if (!createDmResult.IsSuccess || createDmResult.Entity is null) { _logger.LogWarning(errMsg); } else { var sendDmResult = await _channelApi.CreateMessageAsync(createDmResult.Entity.ID, embeds : new[] { embed }, ct : cancellationToken); if (!sendDmResult.IsSuccess) { _logger.LogWarning(errMsg); } } } try { await _context.AddAsync(warnModerationAction, cancellationToken); await _context.SaveChangesAsync(cancellationToken); } catch (Exception e) { return(e); } return(warnModerationAction); }
/// <inheritdoc /> public async ValueTask <Result> CheckHasRequiredPermission( DiscordPermission permission, Snowflake channelId, IUser userToCheck, CancellationToken ct = default ) { var getChannel = await _channelApi.GetChannelAsync(channelId, ct); if (!getChannel.IsSuccess) { return(Result.FromError(getChannel)); } var channel = getChannel.Entity; if (!channel.GuildID.HasValue) { return(new ConditionNotSatisfiedError( "Command requires a guild permission but was executed outside of a guild.")); } var guildId = channel.GuildID.Value; var getGuildMember = await _guildApi.GetGuildMemberAsync(guildId, userToCheck.ID, ct); if (!getGuildMember.IsSuccess) { return(Result.FromError(getGuildMember)); } var getGuildRoles = await _guildApi.GetGuildRolesAsync(guildId, ct); if (!getGuildRoles.IsSuccess) { return(Result.FromError(getGuildRoles)); } var guildRoles = getGuildRoles.Entity; var everyoneRole = guildRoles.FirstOrDefault(r => r.Name.Equals("@everyone")); if (everyoneRole is null) { return(new NotFoundError("No @everyone role found.")); } var user = getGuildMember.Entity; if (user is null) { return(new NotFoundError("Executing user not found")); } var getGuild = await _guildApi.GetGuildAsync(guildId, ct : ct); if (!getGuild.IsSuccess) { return(Result.FromError(getGuild)); } var guildOwnerId = getGuild.Entity.OwnerID; // succeed if the user is the Owner of the guild if (guildOwnerId.Equals(userToCheck.ID)) { return(Result.FromSuccess()); } var memberRoles = guildRoles.Where(r => user.Roles.Contains(r.ID)).ToList(); var computedPermissions = channel.PermissionOverwrites switch { { HasValue : true, Value : { } overwrites } => DiscordPermissionSet.ComputePermissions(
/// <inheritdoc /> public async Task <Result> RespondAsync(IGuildMemberAdd gatewayEvent, CancellationToken ct = default) { if (!gatewayEvent.User.IsDefined(out var user)) { // We can't do anything about this return(Result.FromSuccess()); } var getServerResult = await _servers.GetOrRegisterServerAsync(gatewayEvent.GuildID, ct); if (!getServerResult.IsSuccess) { return(Result.FromError(getServerResult)); } var server = getServerResult.Entity; if (!server.SendJoinMessage) { return(Result.FromSuccess()); } var getJoinMessageResult = ServerService.GetJoinMessage(server); if (!getJoinMessageResult.IsSuccess) { return(Result.FromError(getJoinMessageResult)); } var openDM = await _userAPI.CreateDMAsync(user.ID, ct); if (!openDM.IsSuccess) { return(Result.FromError(openDM)); } var userChannel = openDM.Entity; var embed = new Embed { Colour = _feedback.Theme.Secondary, Description = $"Welcome, <@{user.ID}>!\n" + "\n" + $"{getJoinMessageResult.Entity}" }; var sendEmbed = await _channelAPI.CreateMessageAsync(userChannel.ID, embeds : new[] { embed }, ct : ct); if (sendEmbed.IsSuccess) { return(Result.FromSuccess()); } if (sendEmbed.Error is not RestResultError <RestError> re) { return(Result.FromError(sendEmbed)); } if (re.Error.Code is not DiscordError.CannotSendMessageToUser) { return(Result.FromError(sendEmbed)); } var getGuild = await _guildAPI.GetGuildAsync(gatewayEvent.GuildID, ct : ct); if (!getGuild.IsSuccess) { return(Result.FromError(getGuild)); } var guild = getGuild.Entity; if (!guild.SystemChannelID.HasValue) { // man, we tried return(Result.FromSuccess()); } var content = $"Welcome, <@{user.ID}>! You have DMs disabled, so I couldn't send you " + "the first-join message. To see it, type \"!server join-message\"."; var sendNotification = await _feedback.SendWarningAsync ( guild.SystemChannelID.Value, content, user.ID, ct : ct ); return(sendNotification.IsSuccess ? Result.FromSuccess() : Result.FromError(sendNotification)); }
/// <inheritdoc /> public async ValueTask <Result> CheckHasRequiredPermission( DiscordPermission permission, Snowflake channelId, IUser userToCheck, CancellationToken ct = default ) { var getChannel = await _channelApi.GetChannelAsync(channelId, ct); if (!getChannel.IsSuccess) { return(Result.FromError(getChannel)); } var channel = getChannel.Entity; if (!channel.GuildID.HasValue) { return(new ConditionNotSatisfiedError( "Command requires a guild permission but was executed outside of a guild.")); } var guildId = channel.GuildID.Value; var getGuildMember = await _guildApi.GetGuildMemberAsync(guildId, userToCheck.ID, ct); if (!getGuildMember.IsSuccess) { return(Result.FromError(getGuildMember)); } var getGuildRoles = await _guildApi.GetGuildRolesAsync(guildId, ct); if (!getGuildRoles.IsSuccess) { return(Result.FromError(getGuildRoles)); } var guildRoles = getGuildRoles.Entity; var everyoneRole = guildRoles.FirstOrDefault(r => r.Name.Equals("@everyone")); if (everyoneRole is null) { return(new NotFoundError("No @everyone role found.")); } var user = getGuildMember.Entity; if (user is null) { return(new NotFoundError("Executing user not found")); } var getGuild = await _guildApi.GetGuildAsync(guildId, ct : ct); if (!getGuild.IsSuccess) { return(Result.FromError(getGuild)); } var guildOwnerId = getGuild.Entity.OwnerID; // succeed if the user is the Owner of the guild if (guildOwnerId.Equals(userToCheck.ID)) { return(Result.FromSuccess()); } var memberRoles = guildRoles.Where(r => user.Roles.Contains(r.ID)).ToList(); IDiscordPermissionSet computedPermissions; if (channel.PermissionOverwrites.HasValue) { computedPermissions = DiscordPermissionSet.ComputePermissions( userToCheck.ID, everyoneRole, memberRoles, channel.PermissionOverwrites.Value ); } else { computedPermissions = DiscordPermissionSet.ComputePermissions( userToCheck.ID, everyoneRole, memberRoles ); } // succeed if the user is an Administrator of the guild if (computedPermissions.HasPermission(DiscordPermission.Administrator)) { return(Result.FromSuccess()); } var hasPermission = computedPermissions.HasPermission(permission); return(!hasPermission ? new ConditionNotSatisfiedError( $"Guild User requesting the command does not have the required {permission.ToString()} permission") : Result.FromSuccess()); }
public async Task <Result> HasPermissionAsync ( Snowflake discordServer, Snowflake discordUser, IPermission requiredPermission, PermissionTarget target, CancellationToken ct = default ) { var getDiscordServer = await _guildAPI.GetGuildAsync(discordServer, ct : ct); if (!getDiscordServer.IsSuccess) { return(Result.FromError(getDiscordServer)); } var guild = getDiscordServer.Entity; // The server owner always has all permissions by default if (guild.OwnerID == discordUser) { return(Result.FromSuccess()); } // Special handling for the All target if (target == PermissionTarget.All) { var hasSelf = await HasPermissionAsync ( discordServer, discordUser, requiredPermission, PermissionTarget.Self, ct ); var hasOther = await HasPermissionAsync ( discordServer, discordUser, requiredPermission, PermissionTarget.Other, ct ); if (hasSelf.IsSuccess && hasOther.IsSuccess) { return(Result.FromSuccess()); } return(new UserError("Permission denied.")); } var hasPermission = false; var getGuildMember = await _guildAPI.GetGuildMemberAsync(discordServer, discordUser, ct); if (!getGuildMember.IsSuccess) { return(Result.FromError(getGuildMember)); } var member = getGuildMember.Entity; // Check if the user is part of any roles which this permission applies to var rolePermissions = await GetApplicableRolePermissionsAsync(member.Roles, ct); var rolePermission = rolePermissions.FirstOrDefault ( p => p.Permission == requiredPermission.UniqueIdentifier && p.Target == target ); if (rolePermission is not null) { hasPermission = rolePermission.IsGranted; } // Check if the user has the permission applied to themselves var userPermission = await _database.UserPermissions.ServersideQueryAsync ( q => q .Where(p => p.ServerID == discordServer) .Where(p => p.UserID == discordUser) .Where(p => p.Permission == requiredPermission.UniqueIdentifier) .Where(p => p.Target == target) .SingleOrDefaultAsync(ct) ); if (userPermission is not null) { hasPermission = userPermission.IsGranted; } if (rolePermission is null && userPermission is null) { // Use the permission's default value hasPermission = requiredPermission.IsGrantedByDefaultTo(target); } return(hasPermission ? Result.FromSuccess() : new UserError("Permission denied.")); }