public DetermineConditionResult IsEntityNameValid ( IEnumerable <string> commandNames, string?entityName ) { if (entityName.IsNullOrWhitespace()) { return(DetermineConditionResult.FromError("Names cannot be empty.")); } if (entityName.Any(c => _reservedNameCharacters.Contains(c))) { return(DetermineConditionResult.FromError ( $"Names may not contain any of the following characters: {_reservedNameCharacters.Humanize()}" )); } if (_reservedNames.Any(n => string.Equals(n, entityName, StringComparison.OrdinalIgnoreCase))) { return(DetermineConditionResult.FromError ( "That is a reserved name." )); } if (commandNames.Any(entityName.Contains)) { return(DetermineConditionResult.FromError("Names may not be the same as a command.")); } return(DetermineConditionResult.FromSuccess()); }
/// <summary> /// Sends a consent request to the given DM channel. /// </summary> /// <param name="channel">The channel.</param> /// <returns>An execution result.</returns> public async Task <DetermineConditionResult> RequestConsentAsync(IDMChannel channel) { try { var consentBuilder = _feedback.CreateEmbedBase(Color.Orange); consentBuilder.WithDescription ( "Hello there! This appears to be the first time you're using the bot (or you've not granted your " + "consent for it to store potentially sensitive or identifiable data about you).\n" + "\n" + "In order to use Amby and her commands, you need to give her your consent to store various data " + "about you. We need this consent in order to be compliant with data regulations in the European " + "Union (and it'd be rude not to ask!).\n" + "\n" + "In short, if you use the bot, we're going to be storing " + "stuff like your Discord ID, some messages, server IDs, etc. You can - and should! - read the " + "full privacy policy before you agree to anything. It's not very long (3 pages) and shouldn't take " + "more than five minutes to read through.\n" + "\n" + "Once you've read it, you can grant consent by running the `!privacy grant-consent` command over DM. If you " + "don't want to consent to anything, just don't use the bot :smiley:" ); await channel.SendMessageAsync(string.Empty, embed : consentBuilder.Build()); await SendPrivacyPolicyAsync(channel); } catch (HttpException hex) when(hex.HttpCode == HttpStatusCode.Forbidden) { return(DetermineConditionResult.FromError("Could not send the privacy message over DM.")); } return(DetermineConditionResult.FromSuccess()); }
/// <summary> /// Verifies all yaml files in the given directory. /// </summary> /// <param name="directory">The directory to load files from.</param> /// <returns>A condition result, which may or may not have succeeded.</returns> public DetermineConditionResult VerifyFilesInDirectory(string directory) { var files = Directory.EnumerateFiles(directory, "*.yml", SearchOption.AllDirectories).Where(p => !p.EndsWith("Species.yml")).ToList(); if (files.Count <= 0) { return(DetermineConditionResult.FromError("No files to verify in input directory.")); } foreach (var file in files) { var verificationResult = VerifyFile <Transformation>(file); if (!verificationResult.IsSuccess) { return(verificationResult); } } var speciesPath = Path.Combine(directory, "Species.yml"); if (!File.Exists(speciesPath)) { return(DetermineConditionResult.FromSuccess()); } var speciesVerificationResult = VerifyFile <Species>(speciesPath); if (!speciesVerificationResult.IsSuccess) { return(speciesVerificationResult); } return(DetermineConditionResult.FromSuccess()); }
/// <summary> /// Verifies the content of the given file, treating it as a transformation file. /// </summary> /// <param name="file">The path to the file.</param> /// <typeparam name="T">The class to verify the file as.</typeparam> /// <returns>A condition result, which may or may not have succeeded.</returns> public DetermineConditionResult VerifyFile <T>(string file) { using var sr = new StreamReader(File.OpenRead(file)); var deserB = new DeserializerBuilder() .WithTypeConverter(new ColourYamlConverter()) .WithNodeDeserializer(i => new ValidatingNodeDeserializer(i), s => s.InsteadOf <ObjectNodeDeserializer>()) .WithNamingConvention(UnderscoredNamingConvention.Instance); if (typeof(T) != typeof(Species)) { deserB = deserB.WithTypeConverter(new RawSpeciesYamlConverter()); } var deser = deserB.Build(); var content = sr.ReadToEnd(); try { deser.Deserialize <T>(content); } catch (YamlException yex) { return(DetermineConditionResult.FromError(yex, Path.GetFileName(file))); } return(DetermineConditionResult.FromSuccess()); }
/// <summary> /// Loads the sass from disk. /// </summary> private async Task <DetermineConditionResult> LoadSassAsync() { var sassPath = UPath.Combine(UPath.Root, "Sass", "sass.txt"); var sassNSFWPath = UPath.Combine(UPath.Root, "Sass", "sass-nsfw.txt"); var getSassStream = _content.OpenLocalStream(sassPath); if (getSassStream.IsSuccess) { await using var sassStream = getSassStream.Entity; _sass = (await AsyncIO.ReadAllLinesAsync(sassStream)).ToList(); } else { return(DetermineConditionResult.FromError(getSassStream)); } var getNSFWSassStream = _content.OpenLocalStream(sassNSFWPath); if (getNSFWSassStream.IsSuccess) { await using var nsfwSassStream = getNSFWSassStream.Entity; _sassNSFW = (await AsyncIO.ReadAllLinesAsync(nsfwSassStream)).ToList(); } else { return(DetermineConditionResult.FromError(getNSFWSassStream)); } _isSassLoaded = true; return(DetermineConditionResult.FromSuccess()); }
public async Task <DetermineConditionResult> CanUserTransformUserAsync ( IGuild discordServer, IUser invokingUser, IUser targetUser ) { var getLocalProtectionResult = await GetOrCreateServerUserProtectionAsync(targetUser, discordServer); if (!getLocalProtectionResult.IsSuccess) { return(DetermineConditionResult.FromError(getLocalProtectionResult)); } var localProtection = getLocalProtectionResult.Entity; if (!localProtection.HasOptedIn) { return(DetermineConditionResult.FromError("The target hasn't opted into transformations.")); } var getGlobalProtectionResult = await GetOrCreateGlobalUserProtectionAsync(targetUser); if (!getGlobalProtectionResult.IsSuccess) { return(DetermineConditionResult.FromError(getGlobalProtectionResult)); } var globalProtection = getGlobalProtectionResult.Entity; switch (localProtection.Type) { case ProtectionType.Blacklist: { return(globalProtection.Blacklist.All(u => u.DiscordID != (long)invokingUser.Id) ? DetermineConditionResult.FromSuccess() : DetermineConditionResult.FromError("You're on that user's blacklist.")); } case ProtectionType.Whitelist: { return(globalProtection.Whitelist.Any(u => u.DiscordID == (long)invokingUser.Id) ? DetermineConditionResult.FromSuccess() : DetermineConditionResult.FromError("You're not on that user's whitelist.")); } default: { throw new ArgumentOutOfRangeException(); } } }
/// <inheritdoc /> public async ValueTask <DetermineConditionResult> CheckAsync(RequireContextAttribute attribute, CancellationToken ct) { var getChannel = await _channelAPI.GetChannelAsync(_context.ChannelID, ct); if (!getChannel.IsSuccess) { return(DetermineConditionResult.FromError(getChannel)); } var channel = getChannel.Entity; switch (attribute.Context) { case ChannelContext.DM: { return(channel.Type is DM ? DetermineConditionResult.FromSuccess() : DetermineConditionResult.FromError("This command can only be used in a DM.")); } case ChannelContext.GroupDM: { return(channel.Type is GroupDM ? DetermineConditionResult.FromSuccess() : DetermineConditionResult.FromError("This command can only be used in a group DM.")); } case ChannelContext.Guild: { return(channel.Type is GuildText or GuildVoice or GuildCategory or GuildNews or GuildStore ? DetermineConditionResult.FromSuccess() : DetermineConditionResult.FromError("This command can only be used in a guild.")); } default: { throw new ArgumentOutOfRangeException(); } } }
public async Task <DetermineConditionResult> HasPermissionAsync ( [NotNull] IGuild discordServer, [NotNull] IGuildUser discordUser, IPermission requiredPermission, PermissionTarget target ) { // The server owner always has all permissions by default if (discordServer.OwnerId == discordUser.Id) { return(DetermineConditionResult.FromSuccess()); } // Special handling for the All target if (target == PermissionTarget.All) { var hasSelf = await HasPermissionAsync ( discordServer, discordUser, requiredPermission, PermissionTarget.Self ); var hasOther = await HasPermissionAsync ( discordServer, discordUser, requiredPermission, PermissionTarget.Other ); if (hasSelf.IsSuccess && hasOther.IsSuccess) { return(DetermineConditionResult.FromSuccess()); } return(DetermineConditionResult.FromError("Permission denied.")); } var hasPermission = false; // Check if the user is part of any roles which this permission applies to var rolePermission = await GetApplicableRolePermissions(discordUser) .FirstOrDefaultAsync ( p => p.Permission == requiredPermission.UniqueIdentifier && p.Target == target ); if (!(rolePermission is null)) { hasPermission = rolePermission.IsGranted; } // Check if the user has the permission applied to themselves var userPermission = await GetApplicableUserPermissions(discordServer, discordUser) .FirstOrDefaultAsync ( p => p.Permission == requiredPermission.UniqueIdentifier && p.Target == target ); if (!(userPermission is null)) { hasPermission = userPermission.IsGranted; } if (rolePermission is null && userPermission is null) { // Use the permission's default value hasPermission = requiredPermission.IsGrantedByDefaultTo(target); } if (hasPermission) { return(DetermineConditionResult.FromSuccess()); } return(DetermineConditionResult.FromError("Permission denied.")); }