/// <inheritdoc/> public override async Task <RetrieveEntityResult <bool> > IsConditionFulfilledForUserAsync ( IServiceProvider services, IGuildUser discordUser, CancellationToken ct = default ) { var statistics = services.GetRequiredService <UserStatisticsService>(); var channel = await discordUser.Guild.GetTextChannelAsync((ulong)this.SourceID); if (channel is null) { return(RetrieveEntityResult <bool> .FromError("Failed to retrieve the channel.")); } var getUserStatistics = await statistics.GetOrCreateUserChannelStatisticsAsync(discordUser, channel, ct); if (!getUserStatistics.IsSuccess) { return(RetrieveEntityResult <bool> .FromError(getUserStatistics)); } var userStatistics = getUserStatistics.Entity; return(userStatistics.MessageCount.HasValue && userStatistics.MessageCount >= this.RequiredCount); }
/// <summary> /// Gets or creates server settings for the given guild. /// </summary> /// <param name="guild">The guild.</param> /// <returns>A retrieval result which may or may not have succeeded.</returns> public async Task <RetrieveEntityResult <AutoroleServerSettings> > GetOrCreateServerSettingsAsync ( IGuild guild ) { var existingSettings = await _database.AutoroleServerSettings.AsQueryable().FirstOrDefaultAsync ( s => s.Server.DiscordID == (long)guild.Id ); if (!(existingSettings is null)) { return(existingSettings); } var getServer = await _servers.GetOrRegisterServerAsync(guild); if (!getServer.IsSuccess) { return(RetrieveEntityResult <AutoroleServerSettings> .FromError(getServer)); } var server = getServer.Entity; var newSettings = _database.CreateProxy <AutoroleServerSettings>(server); _database.AutoroleServerSettings.Update(newSettings); await _database.SaveChangesAsync(); return(newSettings); }
/// <summary> /// Gets the roleplay currently active in the given channel. /// </summary> /// <param name="textChannel">The channel.</param> /// <returns>A retrieval result which may or may not have succeeded.</returns> public async Task <RetrieveEntityResult <Roleplay> > GetActiveRoleplayAsync(ITextChannel textChannel) { var getServer = await _servers.GetOrRegisterServerAsync(textChannel.Guild); if (!getServer.IsSuccess) { return(RetrieveEntityResult <Roleplay> .FromError(getServer)); } var server = getServer.Entity; var roleplay = (await _roleplays.GetRoleplaysAsync(server)).FirstOrDefault ( rp => rp.IsActive && rp.ActiveChannelID == (long)textChannel.Id ); if (roleplay is null) { return(RetrieveEntityResult <Roleplay> .FromError ( "There is no roleplay that is currently active in this channel." )); } return(roleplay); }
public static RetrieveEntityResult <TResult> SelectFromBestLevenshteinMatch <TSource, TResult> ( this IEnumerable <TSource> @this, Func <TSource, TResult> selector, Func <TSource, string> stringSelector, string search, double tolerance = 0.25 ) where TResult : class where TSource : class { var enumerable = @this as IList <TSource> ?? @this.ToList(); var matchResult = enumerable.Select(stringSelector).BestLevenshteinMatch(search, tolerance); if (!matchResult.IsSuccess) { return(RetrieveEntityResult <TResult> .FromError(matchResult)); } var selectedString = matchResult.Entity; var selectedObject = enumerable.FirstOrDefault(i => stringSelector(i) == selectedString); if (selectedObject is null) { return(RetrieveEntityResult <TResult> .FromError("No matching object for the selector found.")); } var result = selector(selectedObject); return(RetrieveEntityResult <TResult> .FromSuccess(result)); }
/// <summary> /// Adds a Discord user to the database. /// </summary> /// <param name="discordUser">The Discord user.</param> /// <param name="ct">The cancellation token in use.</param> /// <returns>The freshly created information about the user.</returns> /// <exception cref="ArgumentException">Thrown if the user already exists in the database.</exception> public async Task <RetrieveEntityResult <User> > AddUserAsync ( IUser discordUser, CancellationToken ct = default ) { if (discordUser.IsBot || discordUser.IsWebhook) { return(RetrieveEntityResult <User> .FromError ( "Users cannot be viewed or created for bots or webhooks." )); } if (await IsUserKnownAsync(discordUser, ct)) { return(RetrieveEntityResult <User> .FromError ( $"A user with the ID {discordUser.Id} has already been added to the database." )); } var newUser = _database.CreateProxy <User>((long)discordUser.Id); _database.Users.Update(newUser); await _database.SaveChangesAsync(ct); return(newUser); }
/// <inheritdoc /> public async Task <RetrieveEntityResult <Character> > GetUserCharacterByNameAsync ( User user, Server server, string name, CancellationToken ct = default ) { user = _database.NormalizeReference(user); server = _database.NormalizeReference(server); var character = await _database.Characters.UserScopedServersideQueryAsync ( user, server, q => q .Where(ch => string.Equals(ch.Name.ToLower(), name.ToLower())) .SingleOrDefaultAsync(ct) ); if (!(character is null)) { return(character); } return(RetrieveEntityResult <Character> .FromError("The user doesn't own a character with that name.")); }
/// <summary> /// Determines whether a given user is qualified for the given autorole. /// </summary> /// <param name="autorole">The autorole.</param> /// <param name="user">The user.</param> /// <param name="ct">The cancellation token in use.</param> /// <returns>true if the user qualifies; otherwise, false.</returns> public async Task <RetrieveEntityResult <bool> > IsUserQualifiedForAutoroleAsync ( AutoroleConfiguration autorole, IGuildUser user, CancellationToken ct = default ) { foreach (var condition in autorole.Conditions) { var isFulfilledResult = await condition.IsConditionFulfilledForUserAsync(_serviceProvider, user, ct); if (!isFulfilledResult.IsSuccess) { return(RetrieveEntityResult <bool> .FromError("One or more conditions were indeterminate.")); } var isFulfilled = isFulfilledResult.Entity; if (!isFulfilled) { return(false); } } return(true); }
private RetrieveEntityResult <IReadOnlyList <string> > GetSampleDataSet <TType>(string subfolder) { var getBasePath = GetBaseSampleDataPath(); if (!getBasePath.IsSuccess) { return(RetrieveEntityResult <IReadOnlyList <string> > .FromError(getBasePath)); } var basePath = Path.Combine(getBasePath.Entity, subfolder); var samplesDirectoryName = typeof(TType).Name.Underscore().Transform(To.UpperCase); if (typeof(TType).IsInterface && samplesDirectoryName.StartsWith('I')) { samplesDirectoryName = samplesDirectoryName.Substring(2); } var samplesPath = Path.Combine(basePath, samplesDirectoryName); if (!Directory.Exists(samplesPath)) { return(RetrieveEntityResult <IReadOnlyList <string> > .FromError("No valid sample data found.")); } return(Directory.EnumerateFiles(samplesPath, "*.json", SearchOption.AllDirectories).ToList()); }
public async Task <RetrieveEntityResult <IReadOnlyList <Transformation> > > GetTransformationsByPartAndSpeciesAsync ( Bodypart bodypart, Species species ) { var bodyparts = new List <Bodypart>(); if (bodypart.IsComposite()) { bodyparts.AddRange(bodypart.GetComposingParts()); } else { bodyparts.Add(bodypart); } var transformations = await _database.Transformations.AsQueryable() .Where(tf => bodyparts.Contains(tf.Part) && tf.Species.Name.ToLower().Equals(species.Name.ToLower())) .ToListAsync(); if (!transformations.Any()) { return(RetrieveEntityResult <IReadOnlyList <Transformation> > .FromError ( "No transformation found for that combination." )); } return(RetrieveEntityResult <IReadOnlyList <Transformation> > .FromSuccess(transformations)); }
public async Task <RetrieveEntityResult <Roleplay> > GetUserRoleplayByNameAsync ( [NotNull] ICommandContext context, [NotNull] IUser roleplayOwner, [NotNull] string roleplayName ) { var roleplay = await GetRoleplays(context.Guild) .FirstOrDefaultAsync ( rp => rp.Name.Equals(roleplayName, StringComparison.OrdinalIgnoreCase) && rp.Owner.DiscordID == (long)roleplayOwner.Id ); if (roleplay is null) { var isCurrentUser = context.Message.Author.Id == roleplayOwner.Id; var errorMessage = isCurrentUser ? "You don't own a roleplay with that name." : "The user doesn't own a roleplay with that name."; return(RetrieveEntityResult <Roleplay> .FromError(errorMessage)); } return(RetrieveEntityResult <Roleplay> .FromSuccess(roleplay)); }
/// <inheritdoc /> public override async Task <RetrieveEntityResult <bool> > IsConditionFulfilledForUserAsync ( IServiceProvider services, IGuildUser discordUser, CancellationToken ct = default ) { var statistics = services.GetRequiredService <UserStatisticsService>(); var getUserStatistics = await statistics.GetOrCreateUserServerStatisticsAsync(discordUser, ct); if (!getUserStatistics.IsSuccess) { return(RetrieveEntityResult <bool> .FromError(getUserStatistics)); } var userStatistics = getUserStatistics.Entity; if (userStatistics.LastActivityTime is null) { // The user has never been active return(false); } var timeSinceLastActivity = DateTime.UtcNow - userStatistics.LastActivityTime; return(timeSinceLastActivity <= this.RequiredTime); }
public async Task <RetrieveEntityResult <IGuildChannel> > GetDedicatedRoleplayChannelAsync ( [NotNull] IGuild guild, [NotNull] Roleplay roleplay ) { if (!(roleplay.DedicatedChannelID is null)) { var guildChannel = await guild.GetChannelAsync((ulong)roleplay.DedicatedChannelID.Value); if (!(guildChannel is null)) { return(RetrieveEntityResult <IGuildChannel> .FromSuccess(guildChannel)); } return(RetrieveEntityResult <IGuildChannel> .FromError ( "Attempted to delete a channel, but it appears to have been deleted." )); } return(RetrieveEntityResult <IGuildChannel> .FromError ( "The roleplay doesn't have a dedicated channel." )); }
private RetrieveEntityResult <TUser> FindBestMatchingUserBy <TUser> ( IEnumerable <TUser> users, Func <TUser, string> selector, string value ) where TUser : class, IUser { var values = users.Select(u => (User: u, Value: selector(u))).ToImmutableList(); var literalMatch = values.FirstOrDefault(uv => uv.Value == value).User; if (!(literalMatch is null)) { return(RetrieveEntityResult <TUser> .FromSuccess(literalMatch)); } var partialMatch = values.FirstOrDefault ( uv => string.Equals(uv.Value, value, StringComparison.OrdinalIgnoreCase) ).User; if (!(partialMatch is null)) { return(RetrieveEntityResult <TUser> .FromSuccess(partialMatch)); } return(RetrieveEntityResult <TUser> .FromError("No matching user found.")); }
/// <inheritdoc /> protected override async Task <RetrieveEntityResult <Roleplay> > RetrieveEntityAsync ( IUser?entityOwner, string?entityName, ICommandContext context, IServiceProvider services ) { var roleplayService = services.GetRequiredService <RoleplayDiscordService>(); if (!(context.Channel is ITextChannel textChannel)) { return(RetrieveEntityResult <Roleplay> .FromError("The channel was not a text channel.")); } if (!entityName.IsNullOrWhitespace() && string.Equals(entityName, "current", StringComparison.OrdinalIgnoreCase)) { return(await roleplayService.GetActiveRoleplayAsync(textChannel)); } return(await roleplayService.GetBestMatchingRoleplayAsync ( (ITextChannel)context.Channel, context.Guild, entityOwner, entityName )); }
/// <inheritdoc /> public async Task <RetrieveEntityResult <Character> > GetCurrentCharacterAsync ( User user, Server server, CancellationToken ct = default ) { user = _database.NormalizeReference(user); server = _database.NormalizeReference(server); if (!await HasCurrentCharacterAsync(user, server, ct)) { return(RetrieveEntityResult <Character> .FromError("The user hasn't assumed a character.")); } var currentCharacter = await _database.Characters.UserScopedServersideQueryAsync ( user, server, q => q .Where(ch => ch.IsCurrent) .SingleOrDefaultAsync(ct) ); if (!(currentCharacter is null)) { return(currentCharacter); } return(RetrieveEntityResult <Character> .FromError("Failed to retrieve a current character.")); }
/// <summary> /// Gets the current appearance for the given character, cloning it from the default appearance if one does not /// exist. /// </summary> /// <param name="character">The character.</param> /// <returns>A retrieval result which may or may not have succeeded.</returns> public async Task <RetrieveEntityResult <Appearance> > GetOrCreateCurrentAppearanceAsync ( Character character ) { var getCurrentAppearanceResult = await GetCurrentAppearanceAsync(character); if (getCurrentAppearanceResult.IsSuccess) { return(getCurrentAppearanceResult); } // There's no current appearance, so we'll grab the default one and copy it var getDefaultAppearance = await GetOrCreateDefaultAppearanceAsync(character); if (!getDefaultAppearance.IsSuccess) { return(RetrieveEntityResult <Appearance> .FromError(getDefaultAppearance)); } var defaultAppearance = getDefaultAppearance.Entity; var currentAppearance = Appearance.CopyFrom(defaultAppearance); currentAppearance.IsCurrent = true; _database.Appearances.Update(currentAppearance); await _database.SaveChangesAsync(); // Requery the database return(await GetOrCreateCurrentAppearanceAsync(character)); }
/// <inheritdoc /> public async Task <RetrieveEntityResult <Character> > GetCharacterByNameAsync ( Server server, string name, CancellationToken ct = default ) { server = _database.NormalizeReference(server); var characters = await _database.Characters.ServerScopedServersideQueryAsync ( server, q => q.Where(ch => string.Equals(ch.Name.ToLower(), name.ToLower())), ct ); if (characters.Count > 1) { return(RetrieveEntityResult <Character> .FromError ( "There's more than one character with that name. Please specify which user it belongs to." )); } var character = characters.SingleOrDefault(); if (!(character is null)) { return(character); } return(RetrieveEntityResult <Character> .FromError("No character with that name found.")); }
/// <summary> /// Gets or creates the global transformation protection data for the given user. /// </summary> /// <param name="discordUser">The user.</param> /// <returns>Global protection data for the given user.</returns> public async Task <RetrieveEntityResult <GlobalUserProtection> > GetOrCreateGlobalUserProtectionAsync ( IUser discordUser ) { var protection = await _database.GlobalUserProtections.AsQueryable() .FirstOrDefaultAsync(p => p.User.DiscordID == (long)discordUser.Id); if (!(protection is null)) { return(RetrieveEntityResult <GlobalUserProtection> .FromSuccess(protection)); } var getUserResult = await _users.GetOrRegisterUserAsync(discordUser); if (!getUserResult.IsSuccess) { return(RetrieveEntityResult <GlobalUserProtection> .FromError(getUserResult)); } var user = getUserResult.Entity; protection = new GlobalUserProtection(user); _database.GlobalUserProtections.Update(protection); await _database.SaveChangesAsync(); return(RetrieveEntityResult <GlobalUserProtection> .FromSuccess(protection)); }
/// <inheritdoc /> public async Task <RetrieveEntityResult <Character> > GetDefaultCharacterAsync ( User user, Server server, CancellationToken ct = default ) { user = _database.NormalizeReference(user); server = _database.NormalizeReference(server); var defaultCharacter = await _database.Characters.UserScopedServersideQueryAsync ( user, server, q => q .Where(ch => ch.IsDefault) .SingleOrDefaultAsync(ct) ); if (!(defaultCharacter is null)) { return(defaultCharacter); } return(RetrieveEntityResult <Character> .FromError("The user doesn't have a default character.")); }
/// <summary> /// Gets the default appearance for the given character, or creates one if one does not exist. /// </summary> /// <param name="character">The character.</param> /// <returns>A retrieval result which may or may not have succeeded.</returns> public async Task <RetrieveEntityResult <Appearance> > GetOrCreateDefaultAppearanceAsync ( Character character ) { var getDefaultAppearance = await GetDefaultAppearanceAsync(character); if (getDefaultAppearance.IsSuccess) { return(getDefaultAppearance); } var createDefaultAppearanceResult = await Appearance.CreateDefaultAsync(character, this); if (!createDefaultAppearanceResult.IsSuccess) { return(RetrieveEntityResult <Appearance> .FromError(createDefaultAppearanceResult)); } var defaultAppearance = createDefaultAppearanceResult.Entity; defaultAppearance.IsDefault = true; _database.Appearances.Update(defaultAppearance); await _database.SaveChangesAsync(); // Requery the database return(await GetOrCreateDefaultAppearanceAsync(character)); }
/// <summary> /// Gets or creates server settings for the given guild. /// </summary> /// <param name="guild">The guild.</param> /// <param name="ct">The cancellation token in use.</param> /// <returns>A retrieval result which may or may not have succeeded.</returns> public async Task <RetrieveEntityResult <AutoroleServerSettings> > GetOrCreateServerSettingsAsync ( IGuild guild, CancellationToken ct = default ) { var settings = await _database.AutoroleServerSettings.ServersideQueryAsync ( q => q .Where(s => s.Server.DiscordID == (long)guild.Id) .SingleOrDefaultAsync(ct) ); if (!(settings is null)) { return(settings); } var getServer = await _servers.GetOrRegisterServerAsync(guild, ct); if (!getServer.IsSuccess) { return(RetrieveEntityResult <AutoroleServerSettings> .FromError(getServer)); } var server = getServer.Entity; var newSettings = _database.CreateProxy <AutoroleServerSettings>(server); _database.AutoroleServerSettings.Update(newSettings); await _database.SaveChangesAsync(ct); return(newSettings); }
/// <summary> /// Gets the current character of the given user. /// </summary> /// <param name="guildUser">The user.</param> /// <param name="ct">The cancellation token in use.</param> /// <returns>A retrieval result which may or may not have succeeded.</returns> public async Task <RetrieveEntityResult <Character> > GetCurrentCharacterAsync ( IGuildUser guildUser, CancellationToken ct = default ) { var getUser = await _users.GetOrRegisterUserAsync(guildUser, ct); if (!getUser.IsSuccess) { return(RetrieveEntityResult <Character> .FromError(getUser)); } var getServer = await _servers.GetOrRegisterServerAsync(guildUser.Guild, ct); if (!getServer.IsSuccess) { return(RetrieveEntityResult <Character> .FromError(getServer)); } var user = getUser.Entity; var server = getServer.Entity; return(await _characters.GetCurrentCharacterAsync(user, server, ct)); }
public static async Task <RetrieveEntityResult <TResult> > SelectFromBestLevenshteinMatchAsync <TSource, TResult> ( this IQueryable <TSource> @this, Func <TSource, TResult> selector, Expression <Func <TSource, string> > stringSelector, string search, double tolerance = 0.25 ) where TResult : class where TSource : class { var matchResult = (await @this.Select(stringSelector).ToListAsync()).BestLevenshteinMatch(search, tolerance); if (!matchResult.IsSuccess) { return(RetrieveEntityResult <TResult> .FromError(matchResult)); } var selectedString = matchResult.Entity; var selectorFunc = stringSelector.Compile(); var selectedObject = await @this.FirstOrDefaultAsync(i => selectorFunc(i) == selectedString); if (selectedObject is null) { return(RetrieveEntityResult <TResult> .FromError("No matching object for the selector found.")); } var result = selector(selectedObject); return(RetrieveEntityResult <TResult> .FromSuccess(result)); }
/// <summary> /// Gets the best matching character for the given owner and name combination. If no owner is provided, then the /// global list is searched for a unique name. If no name is provided, then the user's current character is /// used. If neither are set, no character will ever be returned. /// </summary> /// <param name="guild">The guild the user is on.</param> /// <param name="guildUser">The user.</param> /// <param name="name">The name of the character.</param> /// <param name="ct">The cancellation token in use.</param> /// <returns>A retrieval result which may or may not have succeeded.</returns> public async Task <RetrieveEntityResult <Character> > GetBestMatchingCharacterAsync ( IGuild guild, IGuildUser?guildUser, string?name, CancellationToken ct = default ) { var getServer = await _servers.GetOrRegisterServerAsync(guild, ct); if (!getServer.IsSuccess) { return(RetrieveEntityResult <Character> .FromError(getServer)); } var server = getServer.Entity; if (guildUser is null) { return(await _characters.GetBestMatchingCharacterAsync(server, null, name, ct)); } var getUser = await _users.GetOrRegisterUserAsync(guildUser, ct); if (!getUser.IsSuccess) { return(RetrieveEntityResult <Character> .FromError(getUser)); } var user = getUser.Entity; return(await _characters.GetBestMatchingCharacterAsync(server, user, name, ct)); }
/// <summary> /// Gets a condition of the specified ID and type from the given autorole. /// </summary> /// <param name="autorole">The autorole.</param> /// <param name="conditionID">The ID of the condition.</param> /// <typeparam name="TCondition">The type of the condition.</typeparam> /// <returns>A retrieval result which may or may not have succeeded.</returns> public RetrieveEntityResult <TCondition> GetCondition <TCondition> ( AutoroleConfiguration autorole, long conditionID ) where TCondition : AutoroleCondition { var condition = autorole.Conditions.FirstOrDefault(c => c.ID == conditionID); if (condition is null) { return(RetrieveEntityResult <TCondition> .FromError ( "The autorole doesn't have any condition with that ID." )); } if (!(condition is TCondition)) { return(RetrieveEntityResult <TCondition> .FromError ( "The condition with that ID isn't this kind of condition." )); } return((TCondition)condition); }
/// <summary> /// Determines whether the given name is unique among the given user's characters. /// </summary> /// <param name="guildUser">The user.</param> /// <param name="name">The name.</param> /// <param name="ct">The cancellation token in use.</param> /// <returns>A retrieval result which may or may not have succeeded.</returns> public async Task <RetrieveEntityResult <bool> > IsNameUniqueForUserAsync ( IGuildUser guildUser, string name, CancellationToken ct = default ) { var getUser = await _users.GetOrRegisterUserAsync(guildUser, ct); if (!getUser.IsSuccess) { return(RetrieveEntityResult <bool> .FromError(getUser)); } var getServer = await _servers.GetOrRegisterServerAsync(guildUser.Guild, ct); if (!getServer.IsSuccess) { return(RetrieveEntityResult <bool> .FromError(getServer)); } var user = getUser.Entity; var server = getServer.Entity; return(await _characters.IsNameUniqueForUserAsync(user, server, name, ct)); }
public static RetrieveEntityResult <string> BestLevenshteinMatch ( this IEnumerable <string> @this, string search, double tolerance = 0.25 ) { var candidates = @this.Select ( s => { var distance = LevenshteinDistance.Compute ( s.ToLowerInvariant(), search.ToLowerInvariant() ); var maxDistance = Math.Max(s.Length, search.Length); var percentile = distance / (float)maxDistance; return(value: s, distance, percentile); } ); var passing = candidates.Where(c => c.percentile <= tolerance).ToList(); if (!passing.Any()) { return(RetrieveEntityResult <string> .FromError("No sufficiently close match found.")); } var best = passing.MinBy(c => c.distance).First(); return(RetrieveEntityResult <string> .FromSuccess(best.value)); }
/// <inheritdoc /> public async Task <RetrieveEntityResult <Character> > GetBestMatchingCharacterAsync ( Server server, User?user, string?name, CancellationToken ct = default ) { server = _database.NormalizeReference(server); if (!(user is null)) { user = _database.NormalizeReference(user); } if (user is null && name is null) { return(RetrieveEntityResult <Character> .FromError("No user and no name specified.")); } if (user is null) { return(await GetCharacterByNameAsync(server, name !, ct)); } if (name.IsNullOrWhitespace()) { return(await GetCurrentCharacterAsync(user, server, ct)); } return(await GetUserCharacterByNameAsync(user, server, name, ct)); }
/// <summary> /// Loads and retrieves the bundled transformation messages. /// </summary> /// <param name="this">The content service.</param> /// <returns>A retrieval result which may or may not have succeeded.</returns> public static RetrieveEntityResult <TransformationText> GetTransformationMessages ( [NotNull] this ContentService @this ) { if ([email protected](TransformationMessagesPath)) { return(RetrieveEntityResult <TransformationText> .FromError("Transformation messages not found.")); } using ( var reader = new StreamReader ( @this.FileSystem.OpenFile ( TransformationMessagesPath, FileMode.Open, FileAccess.Read, FileShare.Read ) ) ) { var content = reader.ReadToEnd(); if (!TransformationText.TryDeserialize(content, out var text)) { return(RetrieveEntityResult <TransformationText> .FromError("Failed to parse the messages.")); } return(RetrieveEntityResult <TransformationText> .FromSuccess(text)); } }
public async Task <RetrieveEntityResult <Roleplay> > GetUserRoleplayByNameAsync ( Server server, User roleplayOwner, string roleplayName ) { roleplayOwner = _database.NormalizeReference(roleplayOwner); server = _database.NormalizeReference(server); var roleplay = await GetRoleplays(server) .FirstOrDefaultAsync ( rp => rp.Name.ToLower().Equals(roleplayName.ToLower()) && rp.Owner == roleplayOwner ); if (roleplay is null) { return(RetrieveEntityResult <Roleplay> .FromError("You don't own a roleplay with that name.")); } return(RetrieveEntityResult <Roleplay> .FromSuccess(roleplay)); }