/// <summary>
        /// Creates a new dossier with the given title, summary, and data.
        /// </summary>
        /// <param name="db">The database where the dossier should be stored.</param>
        /// <param name="title">The title of the dossier.</param>
        /// <param name="summary">The summary of the dossier.</param>
        /// <returns>A creation task which may or may not have succeeded.</returns>
        public async Task <CreateEntityResult <Dossier> > CreateDossierAsync
        (
            [NotNull] GlobalInfoContext db,
            [NotNull] string title,
            [NotNull] string summary
        )
        {
            var dossier        = new Dossier();
            var setTitleResult = await SetDossierTitleAsync(db, dossier, title);

            if (!setTitleResult.IsSuccess)
            {
                return(CreateEntityResult <Dossier> .FromError(setTitleResult));
            }

            var setSummary = await SetDossierSummaryAsync(db, dossier, summary);

            if (!setSummary.IsSuccess)
            {
                return(CreateEntityResult <Dossier> .FromError(setSummary));
            }

            await db.Dossiers.AddAsync(dossier);

            await db.SaveChangesAsync();

            return(CreateEntityResult <Dossier> .FromSuccess((await GetDossierByTitleAsync(db, title)).Entity));
        }
        /// <summary>
        /// Updates the location of the dossier data, matching it to the dossier's name.
        /// </summary>
        /// <param name="db">The database containing the dossier metadata.</param>
        /// <param name="dossier">The dossier to update.</param>
        /// <returns>An entity modification result which may or may not have succeeded.</returns>
        public async Task <ModifyEntityResult> UpdateDossierDataLocationAsync
        (
            [NotNull] GlobalInfoContext db,
            [NotNull] Dossier dossier
        )
        {
            var originalDossierPath = dossier.Path;
            var newDossierPath      = Path.GetFullPath(Path.Combine(this.Content.BaseDossierPath, $"{dossier.Title}.pdf"));

            if (Directory.GetParent(newDossierPath).FullName != this.Content.BaseDossierPath)
            {
                return(ModifyEntityResult.FromError(CommandError.Exception, "Invalid data path."));
            }

            if (originalDossierPath.IsNullOrWhitespace() || !File.Exists(originalDossierPath) || originalDossierPath == newDossierPath)
            {
                return(ModifyEntityResult.FromSuccess(ModifyEntityAction.Edited));
            }

            try
            {
                File.Move(originalDossierPath, newDossierPath);
            }
            catch (Exception e)
            {
                return(ModifyEntityResult.FromError(CommandError.Exception, e.Message));
            }

            dossier.Path = newDossierPath;
            await db.SaveChangesAsync();

            return(ModifyEntityResult.FromSuccess(ModifyEntityAction.Edited));
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Grants consent to store user data for a given user.
        /// </summary>
        /// <param name="db">The database.</param>
        /// <param name="discordUser">The user that has granted consent.</param>
        /// <returns>A task that must be awaited.</returns>
        public async Task GrantUserConsentAsync
        (
            [NotNull] GlobalInfoContext db,
            [NotNull] IUser discordUser
        )
        {
            var userConsent = await db.UserConsents.FirstOrDefaultAsync(uc => uc.DiscordID == (long)discordUser.Id);

            if (userConsent is null)
            {
                userConsent = new UserConsent
                {
                    DiscordID    = (long)discordUser.Id,
                    HasConsented = true
                };

                db.UserConsents.Add(userConsent);
            }
            else
            {
                userConsent.HasConsented = true;
            }

            await db.SaveChangesAsync();
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Removes the given character's bodypart.
        /// </summary>
        /// <param name="db">The database where characters and transformations are stored.</param>
        /// <param name="context">The context of the command.</param>
        /// <param name="character">The character to shift.</param>
        /// <param name="bodyPart">The bodypart to remove.</param>
        /// <param name="chirality">The chirality of the bodypart.</param>
        /// <returns>A shifting result which may or may not have succeeded.</returns>
        public async Task <ShiftBodypartResult> RemoveBodypartAsync
        (
            [NotNull] GlobalInfoContext db,
            [NotNull] ICommandContext context,
            [NotNull] Character character,
            Bodypart bodyPart,
            Chirality chirality = Chirality.Center
        )
        {
            var discordUser = await context.Guild.GetUserAsync((ulong)character.Owner.DiscordID);

            var canTransformResult = await CanUserTransformUserAsync(db, context.Guild, context.User, discordUser);

            if (!canTransformResult.IsSuccess)
            {
                return(ShiftBodypartResult.FromError(canTransformResult));
            }

            if (!character.TryGetAppearanceComponent(bodyPart, chirality, out var component))
            {
                return(ShiftBodypartResult.FromError(CommandError.ObjectNotFound, "The character doesn't have that bodypart."));
            }

            character.CurrentAppearance.Components.Remove(component);
            await db.SaveChangesAsync();

            string removeMessage = this.DescriptionBuilder.BuildRemoveMessage(character, component);

            return(ShiftBodypartResult.FromSuccess(removeMessage));
        }
        /// <summary>
        /// Creates a new template character with a given appearance.
        /// </summary>
        /// <param name="db">The database.</param>
        /// <param name="context">The context of the command.</param>
        /// <param name="characterName">The name of the new character.</param>
        /// <param name="appearance">The appearance that the new character should have.</param>
        /// <returns>A creation result which may or may not have succeeded.</returns>
        public async Task <CreateEntityResult <Character> > CreateCharacterFromAppearanceAsync
        (
            [NotNull] GlobalInfoContext db,
            [NotNull] ICommandContext context,
            [NotNull] string characterName,
            [NotNull] Appearance appearance
        )
        {
            var createCharacterResult = await CreateCharacterAsync(db, context, characterName);

            if (!createCharacterResult.IsSuccess)
            {
                return(createCharacterResult);
            }

            var newCharacter = createCharacterResult.Entity;

            newCharacter.DefaultAppearance = appearance;

            await db.SaveChangesAsync();

            var getCharacterResult = await GetUserCharacterByNameAsync(db, context, context.Message.Author, characterName);

            if (!getCharacterResult.IsSuccess)
            {
                return(CreateEntityResult <Character> .FromError(getCharacterResult));
            }

            return(CreateEntityResult <Character> .FromSuccess(getCharacterResult.Entity));
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Sets the user's preference for the given kink.
        /// </summary>
        /// <param name="db">The database.</param>
        /// <param name="userKink">The user's kink.</param>
        /// <param name="preference">The new preference.</param>
        /// <returns>A modification result which may or may not have succeeded.</returns>
        public async Task <ModifyEntityResult> SetKinkPreferenceAsync([NotNull] GlobalInfoContext db, [NotNull] UserKink userKink, KinkPreference preference)
        {
            userKink.Preference = preference;
            await db.SaveChangesAsync();

            return(ModifyEntityResult.FromSuccess(ModifyEntityAction.Edited));
        }
        /// <summary>
        /// Sets the default character of a user.
        /// </summary>
        /// <param name="db">The database containing the characters.</param>
        /// <param name="context">The context of the operation.</param>
        /// <param name="newDefaultCharacter">The new default character.</param>
        /// <param name="targetUser">The user to set the default character of.</param>
        /// <returns>A modification result which may or may not have succeeded.</returns>
        public async Task <ModifyEntityResult> SetDefaultCharacterForUserAsync
        (
            [NotNull] GlobalInfoContext db,
            [NotNull] ICommandContext context,
            [NotNull] Character newDefaultCharacter,
            [NotNull] User targetUser
        )
        {
            var isCurrentUser   = context.Message.Author.Id == (ulong)newDefaultCharacter.Owner.DiscordID;
            var isSameCharacter = targetUser.DefaultCharacter?.Name == newDefaultCharacter.Name;

            if (isSameCharacter)
            {
                var errorMessage = isCurrentUser
                                        ? "That's already your default character."
                                        : "That's already the user's default character.";

                return(ModifyEntityResult.FromError(CommandError.UnmetPrecondition, errorMessage));
            }

            targetUser.DefaultCharacter = newDefaultCharacter;
            await db.SaveChangesAsync();

            return(ModifyEntityResult.FromSuccess(ModifyEntityAction.Edited));
        }
        /// <summary>
        /// Adds the given image with the given metadata to the given character.
        /// </summary>
        /// <param name="db">The database where the characters and images are stored.</param>
        /// <param name="character">The character to add the image to.</param>
        /// <param name="imageName">The name of the image.</param>
        /// <param name="imageUrl">The url of the image.</param>
        /// <param name="imageCaption">The caption of the image.</param>
        /// <param name="isNSFW">Whether or not the image is NSFW</param>
        /// <returns>An execution result which may or may not have succeeded.</returns>
        public async Task <ModifyEntityResult> AddImageToCharacterAsync
        (
            [NotNull] GlobalInfoContext db,
            [NotNull] Character character,
            [NotNull] string imageName,
            [NotNull] string imageUrl,
            [CanBeNull] string imageCaption = null,
            bool isNSFW = false
        )
        {
            bool isImageNameUnique = !character.Images.Any(i => string.Equals(i.Name, imageName, StringComparison.OrdinalIgnoreCase));

            if (!isImageNameUnique)
            {
                return(ModifyEntityResult.FromError(CommandError.MultipleMatches, "The character already has an image with that name."));
            }

            var image = new Image
            {
                Name    = imageName,
                Caption = imageCaption,
                Url     = imageUrl,
                IsNSFW  = isNSFW
            };

            character.Images.Add(image);
            await db.SaveChangesAsync();

            return(ModifyEntityResult.FromSuccess(ModifyEntityAction.Added));
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Grants the specified user the given permission. If the user already has the permission, it is augmented with
        /// the new scope and target (if they are more permissive than the existing ones).
        /// </summary>
        /// <param name="db">The database.</param>
        /// <param name="discordServer">The Discord server the permission was granted on.</param>
        /// <param name="discordUser">The Discord user.</param>
        /// <param name="grantedPermission">The granted permission.</param>
        /// <returns>A task wrapping the granting of the permission.</returns>
        public async Task GrantLocalPermissionAsync
        (
            [NotNull] GlobalInfoContext db,
            [NotNull] IGuild discordServer,
            [NotNull] IUser discordUser,
            [NotNull] LocalPermission grantedPermission
        )
        {
            var existingPermission = await GetLocalUserPermissions(db, discordUser, discordServer).FirstOrDefaultAsync
                                     (
                p =>
                p.Permission == grantedPermission.Permission &&
                p.ServerDiscordID == (long)discordServer.Id
                                     );

            if (existingPermission is null)
            {
                await db.LocalPermissions.AddAsync(grantedPermission);
            }
            else
            {
                // Include the new target permissions
                existingPermission.Target |= grantedPermission.Target;
            }

            await db.SaveChangesAsync();
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Kicks the given user from the given roleplay.
        /// </summary>
        /// <param name="db">The database where the roleplays are stored.</param>
        /// <param name="context">The context of the user.</param>
        /// <param name="roleplay">The roleplay to remove the user from.</param>
        /// <param name="kickedUser">The user to remove from the roleplay.</param>
        /// <returns>An execution result which may or may not have succeeded.</returns>
        public async Task <ExecuteResult> KickUserFromRoleplayAsync
        (
            [NotNull] GlobalInfoContext db,
            [NotNull] SocketCommandContext context,
            [NotNull] Roleplay roleplay,
            [NotNull] IUser kickedUser
        )
        {
            if (!roleplay.HasJoined(kickedUser) && !roleplay.IsInvited(kickedUser))
            {
                return(ExecuteResult.FromError(CommandError.ObjectNotFound, "That user is neither invited to or a participant of the roleplay."));
            }

            if (!roleplay.HasJoined(kickedUser))
            {
                var removeUserResult = await RemoveUserFromRoleplayAsync(db, context, roleplay, kickedUser);

                if (!removeUserResult.IsSuccess)
                {
                    return(removeUserResult);
                }
            }

            var participantEntry = roleplay.JoinedUsers.First(p => p.User.DiscordID == (long)kickedUser.Id);

            participantEntry.Status = ParticipantStatus.Kicked;

            await db.SaveChangesAsync();

            return(ExecuteResult.FromSuccess());
        }
        /// <summary>
        /// Sets the preferred pronoun for the given character.
        /// </summary>
        /// <param name="db">The database.</param>
        /// <param name="character">The character.</param>
        /// <param name="pronounFamily">The pronoun family.</param>
        /// <returns>A modification result which may or may not have succeeded.</returns>
        public async Task <ModifyEntityResult> SetCharacterPronounAsync
        (
            [NotNull] GlobalInfoContext db,
            [NotNull] Character character,
            [NotNull] string pronounFamily
        )
        {
            if (pronounFamily.IsNullOrWhitespace())
            {
                return(ModifyEntityResult.FromError(CommandError.BadArgCount, "You need to provide a pronoun family."));
            }

            if (!this.PronounProviders.ContainsKey(pronounFamily))
            {
                return(ModifyEntityResult.FromError(CommandError.ObjectNotFound, "Could not find a pronoun provider for that family."));
            }

            if (character.PronounProviderFamily == pronounFamily)
            {
                return(ModifyEntityResult.FromError(CommandError.Unsuccessful, "The character is already using that pronoun set."));
            }

            var pronounProvider = this.PronounProviders[pronounFamily];

            character.PronounProviderFamily = pronounProvider.Family;

            await db.SaveChangesAsync();

            return(ModifyEntityResult.FromSuccess(ModifyEntityAction.Edited));
        }
        /// <summary>
        /// Sets the summary of the given character.
        /// </summary>
        /// <param name="db">The database containing the characters.</param>
        /// <param name="character">The character to set the summary of.</param>
        /// <param name="newCharacterSummary">The new summary.</param>
        /// <returns>A modification result which may or may not have succeeded.</returns>
        public async Task <ModifyEntityResult> SetCharacterSummaryAsync
        (
            [NotNull] GlobalInfoContext db,
            [NotNull] Character character,
            [NotNull] string newCharacterSummary
        )
        {
            if (string.IsNullOrWhiteSpace(newCharacterSummary))
            {
                return(ModifyEntityResult.FromError(CommandError.BadArgCount, "You need to provide a new summary."));
            }

            if (character.Summary == newCharacterSummary)
            {
                return(ModifyEntityResult.FromError(CommandError.Unsuccessful, "That's already the character's summary."));
            }

            if (newCharacterSummary.Length > 240)
            {
                return(ModifyEntityResult.FromError(CommandError.Unsuccessful, "The summary is too long. It can be at most 240 characters."));
            }

            character.Summary = newCharacterSummary;
            await db.SaveChangesAsync();

            return(ModifyEntityResult.FromSuccess(ModifyEntityAction.Edited));
        }
        /// <summary>
        /// Sets the nickname of the given character.
        /// </summary>
        /// <param name="db">The database containing the characters.</param>
        /// <param name="character">The character to set the nickname of.</param>
        /// <param name="newCharacterNickname">The new nickname.</param>
        /// <returns>A modification result which may or may not have succeeded.</returns>
        public async Task <ModifyEntityResult> SetCharacterNicknameAsync
        (
            [NotNull] GlobalInfoContext db,
            [NotNull] Character character,
            [NotNull] string newCharacterNickname
        )
        {
            if (string.IsNullOrWhiteSpace(newCharacterNickname))
            {
                return(ModifyEntityResult.FromError(CommandError.BadArgCount, "You need to provide a new nickname."));
            }

            if (character.Nickname == newCharacterNickname)
            {
                return(ModifyEntityResult.FromError(CommandError.Unsuccessful, "The character already has that nickname."));
            }

            if (newCharacterNickname.Length > 32)
            {
                return(ModifyEntityResult.FromError(CommandError.Unsuccessful, "The summary is too long. Nicknames can be at most 32 characters."));
            }

            character.Nickname = newCharacterNickname;
            await db.SaveChangesAsync();

            return(ModifyEntityResult.FromSuccess(ModifyEntityAction.Edited));
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Shifts the given character's bodypart to the given species.
        /// </summary>
        /// <param name="db">The database where characters and transformations are stored.</param>
        /// <param name="context">The context of the command.</param>
        /// <param name="character">The character to shift.</param>
        /// <param name="bodyPart">The bodypart to shift.</param>
        /// <param name="species">The species to shift the bodypart into.</param>
        /// <param name="chirality">The chirality of the bodypart.</param>
        /// <returns>A shifting result which may or may not have succeeded.</returns>
        public async Task <ShiftBodypartResult> ShiftBodypartAsync
        (
            [NotNull] GlobalInfoContext db,
            [NotNull] ICommandContext context,
            [NotNull] Character character,
            Bodypart bodyPart,
            [NotNull] string species,
            Chirality chirality = Chirality.Center
        )
        {
            var discordUser = await context.Guild.GetUserAsync((ulong)character.Owner.DiscordID);

            var canTransformResult = await CanUserTransformUserAsync(db, context.Guild, context.User, discordUser);

            if (!canTransformResult.IsSuccess)
            {
                return(ShiftBodypartResult.FromError(canTransformResult));
            }

            var getSpeciesResult = await GetSpeciesByNameAsync(db, species);

            if (!getSpeciesResult.IsSuccess)
            {
                return(ShiftBodypartResult.FromError(getSpeciesResult));
            }

            var getTFResult = await GetTransformationByPartAndSpeciesAsync(db, bodyPart, getSpeciesResult.Entity);

            if (!getTFResult.IsSuccess)
            {
                return(ShiftBodypartResult.FromError(getTFResult));
            }

            string shiftMessage;
            var    transformation = getTFResult.Entity;

            if (!character.TryGetAppearanceComponent(bodyPart, chirality, out var currentComponent))
            {
                currentComponent = AppearanceComponent.CreateFrom(transformation, chirality);
                character.CurrentAppearance.Components.Add(currentComponent);

                shiftMessage = this.DescriptionBuilder.BuildGrowMessage(character, currentComponent);
            }
            else
            {
                if (currentComponent.Transformation.Species.Name.Equals(transformation.Species.Name))
                {
                    return(ShiftBodypartResult.FromError(CommandError.Unsuccessful, "The user's bodypart is already that form."));
                }

                currentComponent.Transformation = transformation;

                shiftMessage = this.DescriptionBuilder.BuildShiftMessage(character, currentComponent);
            }

            await db.SaveChangesAsync();

            return(ShiftBodypartResult.FromSuccess(shiftMessage));
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Resets the user's kink preferences.
        /// </summary>
        /// <param name="db">The database.</param>
        /// <param name="discordUser">The user.</param>
        /// <returns>A task that must be awaited.</returns>
        public async Task ResetUserKinksAsync([NotNull] GlobalInfoContext db, [NotNull] IUser discordUser)
        {
            var user = await db.GetOrRegisterUserAsync(discordUser);

            user.Kinks.Clear();

            await db.SaveChangesAsync();
        }
Ejemplo n.º 16
0
        /// <summary>
        /// Adds a new message to the given roleplay, or edits it if there is an existing one.
        /// </summary>
        /// <param name="db">The database where the roleplays are stored.</param>
        /// <param name="roleplay">The roleplay to modify.</param>
        /// <param name="message">The message to add or update.</param>
        /// <returns>A task wrapping the update action.</returns>
        public async Task <ModifyEntityResult> AddToOrUpdateMessageInRoleplayAsync
        (
            [NotNull] GlobalInfoContext db,
            [NotNull] Roleplay roleplay,
            [NotNull] IMessage message
        )
        {
            if (!roleplay.HasJoined(message.Author))
            {
                return(ModifyEntityResult.FromError(CommandError.Unsuccessful, "The given message was not authored by a participant of the roleplay."));
            }

            string userNick = message.Author.Username;

            if (message.Author is SocketGuildUser guildUser && !string.IsNullOrEmpty(guildUser.Nickname))
            {
                userNick = guildUser.Nickname;
            }

            if (roleplay.Messages.Any(m => m.DiscordMessageID == (long)message.Id))
            {
                // Edit the existing message
                var existingMessage = roleplay.Messages.Find(m => m.DiscordMessageID == (long)message.Id);

                if (existingMessage.Contents.Equals(message.Content))
                {
                    return(ModifyEntityResult.FromError(CommandError.Unsuccessful, "Nothing to do; message content match."));
                }

                existingMessage.Contents = message.Content;

                await db.SaveChangesAsync();

                return(ModifyEntityResult.FromSuccess(ModifyEntityAction.Edited));
            }

            var roleplayMessage = UserMessage.FromDiscordMessage(message, userNick);

            roleplay.Messages.Add(roleplayMessage);

            await db.SaveChangesAsync();

            return(ModifyEntityResult.FromSuccess(ModifyEntityAction.Added));
        }
Ejemplo n.º 17
0
        /// <summary>
        /// Adds the given user to the given roleplay.
        /// </summary>
        /// <param name="db">The database where the roleplays are stored.</param>
        /// <param name="context">The context of the user.</param>
        /// <param name="roleplay">The roleplay to add the user to.</param>
        /// <param name="newUser">The user to add to the roleplay.</param>
        /// <returns>An execution result which may or may not have succeeded.</returns>
        public async Task <ExecuteResult> AddUserToRoleplayAsync
        (
            [NotNull] GlobalInfoContext db,
            [NotNull] SocketCommandContext context,
            [NotNull] Roleplay roleplay,
            [NotNull] IUser newUser
        )
        {
            var isCurrentUser = context.Message.Author.Id == newUser.Id;

            if (roleplay.HasJoined(newUser))
            {
                var errorMessage = isCurrentUser
                                        ? "You're already in that roleplay."
                                        : "The user is aleady in that roleplay.";

                return(ExecuteResult.FromError(CommandError.Unsuccessful, errorMessage));
            }

            if (roleplay.IsKicked(newUser))
            {
                var errorMessage = isCurrentUser
                                        ? "You've been kicked from that roleplay, and can't rejoin unless invited."
                                        : "The user has been kicked from that roleplay, and can't rejoin unless invited.";

                return(ExecuteResult.FromError(CommandError.UnmetPrecondition, errorMessage));
            }

            // Check the invite list for nonpublic roleplays.
            if (!roleplay.IsPublic && !roleplay.IsInvited(newUser))
            {
                var errorMessage = isCurrentUser
                                        ? "You haven't been invited to that roleplay."
                                        : "The user hasn't been invited to that roleplay.";

                return(ExecuteResult.FromError(CommandError.UnmetPrecondition, errorMessage));
            }

            var participantEntry = roleplay.ParticipatingUsers.FirstOrDefault(p => p.User.DiscordID == (long)newUser.Id);

            if (participantEntry is null)
            {
                var user = await db.GetOrRegisterUserAsync(newUser);

                participantEntry = new RoleplayParticipant(roleplay, user, ParticipantStatus.Joined);
                roleplay.ParticipatingUsers.Add(participantEntry);
            }
            else
            {
                participantEntry.Status = ParticipantStatus.Joined;
            }

            await db.SaveChangesAsync();

            return(ExecuteResult.FromSuccess());
        }
Ejemplo n.º 18
0
        /// <summary>
        /// Sets whether or not a roleplay is public.
        /// </summary>
        /// <param name="db">The database containing the roleplays.</param>
        /// <param name="roleplay">The roleplay to set the value in.</param>
        /// <param name="isPublic">The new value.</param>
        /// <returns>A modification result which may or may not have succeeded.</returns>
        public async Task <ModifyEntityResult> SetRoleplayIsPublicAsync
        (
            [NotNull] GlobalInfoContext db,
            [NotNull] Roleplay roleplay,
            bool isPublic
        )
        {
            roleplay.IsPublic = isPublic;
            await db.SaveChangesAsync();

            return(ModifyEntityResult.FromSuccess(ModifyEntityAction.Edited));
        }
        /// <summary>
        /// Sets the name of the given character.
        /// </summary>
        /// <param name="db">The database containing the characters.</param>
        /// <param name="context">The context of the operation.</param>
        /// <param name="character">The character to set the name of.</param>
        /// <param name="newCharacterName">The new name.</param>
        /// <returns>A modification result which may or may not have succeeded.</returns>
        public async Task <ModifyEntityResult> SetCharacterNameAsync
        (
            [NotNull] GlobalInfoContext db,
            [NotNull] ICommandContext context,
            [NotNull] Character character,
            [NotNull] string newCharacterName
        )
        {
            var isCurrentUser = context.Message.Author.Id == (ulong)character.Owner.DiscordID;

            if (string.IsNullOrWhiteSpace(newCharacterName))
            {
                return(ModifyEntityResult.FromError(CommandError.BadArgCount, "You need to provide a name."));
            }

            if (string.Equals(character.Name, newCharacterName, StringComparison.OrdinalIgnoreCase))
            {
                return(ModifyEntityResult.FromError(CommandError.Unsuccessful, "The character already has that name."));
            }

            if (newCharacterName.Contains("\""))
            {
                return(ModifyEntityResult.FromError(CommandError.Unsuccessful, "The name may not contain double quotes."));
            }

            if (!await IsCharacterNameUniqueForUserAsync(db, context.Message.Author, newCharacterName, context.Guild))
            {
                var errorMessage = isCurrentUser
                                        ? "You already have a character with that name."
                                        : "The user already has a character with that name.";

                return(ModifyEntityResult.FromError(CommandError.MultipleMatches, errorMessage));
            }

            var commandModule = this.Commands.Modules.FirstOrDefault(m => m.Name == "character");

            if (!(commandModule is null))
            {
                var validNameResult = this.OwnedEntities.IsEntityNameValid(commandModule, newCharacterName);
                if (!validNameResult.IsSuccess)
                {
                    return(ModifyEntityResult.FromError(validNameResult));
                }
            }

            character.Name = newCharacterName;
            await db.SaveChangesAsync();

            return(ModifyEntityResult.FromSuccess(ModifyEntityAction.Edited));
        }
Ejemplo n.º 20
0
        /// <summary>
        /// Adds the given bodypart to the given character.
        /// </summary>
        /// <param name="db">The database where characters and transformations are stored.</param>
        /// <param name="context">The context of the command.</param>
        /// <param name="character">The character to shift.</param>
        /// <param name="bodyPart">The bodypart to add.</param>
        /// <param name="species">The species of the part to add..</param>
        /// <param name="chirality">The chirality of the bodypart.</param>
        /// <returns>A shifting result which may or may not have succeeded.</returns>
        public async Task <ShiftBodypartResult> AddBodypartAsync
        (
            [NotNull] GlobalInfoContext db,
            [NotNull] ICommandContext context,
            [NotNull] Character character,
            Bodypart bodyPart,
            [NotNull] string species,
            Chirality chirality = Chirality.Center
        )
        {
            var discordUser = await context.Guild.GetUserAsync((ulong)character.Owner.DiscordID);

            var canTransformResult = await CanUserTransformUserAsync(db, context.Guild, context.User, discordUser);

            if (!canTransformResult.IsSuccess)
            {
                return(ShiftBodypartResult.FromError(canTransformResult));
            }

            if (character.HasComponent(bodyPart, chirality))
            {
                return(ShiftBodypartResult.FromError(CommandError.ObjectNotFound, "The character already has that bodypart."));
            }

            var getSpeciesResult = await GetSpeciesByNameAsync(db, species);

            if (!getSpeciesResult.IsSuccess)
            {
                return(ShiftBodypartResult.FromError(getSpeciesResult));
            }

            var getTFResult = await GetTransformationByPartAndSpeciesAsync(db, bodyPart, getSpeciesResult.Entity);

            if (!getTFResult.IsSuccess)
            {
                return(ShiftBodypartResult.FromError(getTFResult));
            }

            var transformation = getTFResult.Entity;

            var component = AppearanceComponent.CreateFrom(transformation, chirality);

            character.CurrentAppearance.Components.Add(component);
            await db.SaveChangesAsync();

            string growMessage = this.DescriptionBuilder.BuildGrowMessage(character, component);

            return(ShiftBodypartResult.FromSuccess(growMessage));
        }
Ejemplo n.º 21
0
        /// <summary>
        /// Revokes consent to store user data for a given user.
        /// </summary>
        /// <param name="db">The database.</param>
        /// <param name="discordUser">The user that has revoked consent.</param>
        /// <returns>A task that must be awaited.</returns>
        public async Task RevokeUserConsentAsync
        (
            [NotNull] GlobalInfoContext db,
            [NotNull] IUser discordUser
        )
        {
            var userConsent = await db.UserConsents.FirstOrDefaultAsync(uc => uc.DiscordID == (long)discordUser.Id);

            if (!(userConsent is null))
            {
                userConsent.HasConsented = false;
            }

            await db.SaveChangesAsync();
        }
Ejemplo n.º 22
0
        /// <summary>
        /// Sets the title of the dossier.
        /// </summary>
        /// <param name="db">The database containing the dossier metadata.</param>
        /// <param name="dossier">The dossier to modify.</param>
        /// <param name="newTitle">The new title.</param>
        /// <returns>An entity modification result which may or may not have succeeded.</returns>
        public async Task <ModifyEntityResult> SetDossierTitleAsync
        (
            [NotNull] GlobalInfoContext db,
            [NotNull] Dossier dossier,
            [NotNull] string newTitle
        )
        {
            var isNewNameUnique = await IsDossierTitleUniqueAsync(db, newTitle);

            // If the only thing that has changed is casing, let it through
            if (!isNewNameUnique)
            {
                bool isOnlyCaseChange = false;
                if (!(dossier.Title is null))
                {
                    isOnlyCaseChange = string.Equals(dossier.Title, newTitle, StringComparison.OrdinalIgnoreCase);
                }

                if (!isOnlyCaseChange)
                {
                    return(ModifyEntityResult.FromError(CommandError.MultipleMatches, "A dossier with that title already exists."));
                }
            }

            if (newTitle.Contains("\""))
            {
                return(ModifyEntityResult.FromError(CommandError.Unsuccessful, "The title may not contain double quotes."));
            }

            if (newTitle.IndexOfAny(Path.GetInvalidPathChars()) > -1)
            {
                return(ModifyEntityResult.FromError(CommandError.Unsuccessful, $"The title contains one or more of invalid characters ({Path.GetInvalidPathChars().Humanize("or")})"));
            }

            dossier.Title = newTitle;

            var updateDataResult = await UpdateDossierDataLocationAsync(db, dossier);

            if (!updateDataResult.IsSuccess)
            {
                return(updateDataResult);
            }

            await db.SaveChangesAsync();

            return(ModifyEntityResult.FromSuccess(ModifyEntityAction.Edited));
        }
Ejemplo n.º 23
0
        /// <summary>
        /// Grants the specified user their default permissions on the given server.
        /// </summary>
        /// <param name="db">The database.</param>
        /// <param name="server">The server to grant the permissions on.</param>
        /// <param name="user">The user to grant the permissions to.</param>
        /// <returns>A task wrapping the granting of default permissions.</returns>
        public async Task GrantDefaultPermissionsAsync([NotNull] GlobalInfoContext db, [NotNull] IGuild server, [NotNull] IUser user)
        {
            foreach (var permission in DefaultPermissions.DefaultPermissionSet)
            {
                var scopedPermission = new LocalPermission
                {
                    Permission      = permission.Permission,
                    Target          = permission.Target,
                    UserDiscordID   = (long)user.Id,
                    ServerDiscordID = (long)server.Id
                };

                await db.LocalPermissions.AddAsync(scopedPermission);
            }

            await db.SaveChangesAsync();
        }
Ejemplo n.º 24
0
        /// <summary>
        /// Sets the summary of the dossier.
        /// </summary>
        /// <param name="db">The database containing the dossier metadata.</param>
        /// <param name="dossier">The dossier to modify.</param>
        /// /// <param name="newSummary">The new summary.</param>
        /// <returns>An entity modification result which may or may not have succeeded.</returns>
        public async Task <ModifyEntityResult> SetDossierSummaryAsync
        (
            [NotNull] GlobalInfoContext db,
            [NotNull] Dossier dossier,
            [NotNull] string newSummary
        )
        {
            if (newSummary.IsNullOrWhitespace())
            {
                return(ModifyEntityResult.FromError(CommandError.ObjectNotFound, "You need to provide a summary."));
            }

            dossier.Summary = newSummary;
            await db.SaveChangesAsync();

            return(ModifyEntityResult.FromSuccess(ModifyEntityAction.Edited));
        }
Ejemplo n.º 25
0
        /// <summary>
        /// Sets whether or not a roleplay is NSFW.
        /// </summary>
        /// <param name="db">The database containing the roleplays.</param>
        /// <param name="roleplay">The roleplay to set the value in.</param>
        /// <param name="isNSFW">The new value.</param>
        /// <returns>A modification result which may or may not have succeeded.</returns>
        public async Task <ModifyEntityResult> SetRoleplayIsNSFWAsync
        (
            [NotNull] GlobalInfoContext db,
            [NotNull] Roleplay roleplay,
            bool isNSFW
        )
        {
            if (roleplay.Messages.Count > 0 && roleplay.IsNSFW && !isNSFW)
            {
                return(ModifyEntityResult.FromError(CommandError.UnmetPrecondition, "You can't mark a NSFW roleplay with messages in it as non-NSFW."));
            }

            roleplay.IsNSFW = isNSFW;
            await db.SaveChangesAsync();

            return(ModifyEntityResult.FromSuccess(ModifyEntityAction.Edited));
        }
Ejemplo n.º 26
0
        /// <summary>
        /// Sets the summary of the given roleplay.
        /// </summary>
        /// <param name="db">The database containing the roleplays.</param>
        /// <param name="roleplay">The roleplay to set the summary of.</param>
        /// <param name="newRoleplaySummary">The new summary.</param>
        /// <returns>A modification result which may or may not have succeeded.</returns>
        public async Task <ModifyEntityResult> SetRoleplaySummaryAsync
        (
            [NotNull] GlobalInfoContext db,
            [NotNull] Roleplay roleplay,
            [NotNull] string newRoleplaySummary
        )
        {
            if (string.IsNullOrWhiteSpace(newRoleplaySummary))
            {
                return(ModifyEntityResult.FromError(CommandError.BadArgCount, "You need to provide a new summary."));
            }

            roleplay.Summary = newRoleplaySummary;
            await db.SaveChangesAsync();

            return(ModifyEntityResult.FromSuccess(ModifyEntityAction.Edited));
        }
Ejemplo n.º 27
0
        /// <summary>
        /// Adds a kink to a user's preference list.
        /// </summary>
        /// <param name="db">The database.</param>
        /// <param name="discordUser">The user.</param>
        /// <param name="kink">The kink.</param>
        /// <returns>A creation result which may or may not have succeeded.</returns>
        public async Task <CreateEntityResult <UserKink> > AddUserKinkAsync([NotNull] GlobalInfoContext db, [NotNull] IUser discordUser, Kink kink)
        {
            var user = await db.GetOrRegisterUserAsync(discordUser);

            if (user.Kinks.Any(k => k.Kink.FListID == kink.FListID))
            {
                return(CreateEntityResult <UserKink> .FromError(CommandError.MultipleMatches, "The user already has a preference for that kink."));
            }

            var userKink = UserKink.CreateFrom(kink);

            user.Kinks.Add(userKink);

            await db.SaveChangesAsync();

            return(CreateEntityResult <UserKink> .FromSuccess(userKink));
        }
Ejemplo n.º 28
0
        /// <summary>
        /// Shifts the colour of the given bodypart's pattern on the given character to the given colour.
        /// </summary>
        /// <param name="db">The database.</param>
        /// <param name="context">The command context.</param>
        /// <param name="character">The character to shift.</param>
        /// <param name="bodyPart">The bodypart to shift.</param>
        /// <param name="patternColour">The colour to shift it into.</param>
        /// <param name="chirality">The chirality of the bodypart.</param>
        /// <returns>A shifting result which may or may not have succeeded.</returns>
        public async Task <ShiftBodypartResult> ShiftPatternColourAsync
        (
            [NotNull] GlobalInfoContext db,
            [NotNull] ICommandContext context,
            [NotNull] Character character,
            Bodypart bodyPart,
            [NotNull] Colour patternColour,
            Chirality chirality = Chirality.Center
        )
        {
            var discordUser = await context.Guild.GetUserAsync((ulong)character.Owner.DiscordID);

            var canTransformResult = await CanUserTransformUserAsync(db, context.Guild, context.User, discordUser);

            if (!canTransformResult.IsSuccess)
            {
                return(ShiftBodypartResult.FromError(canTransformResult));
            }

            if (!character.TryGetAppearanceComponent(bodyPart, chirality, out var currentComponent))
            {
                return(ShiftBodypartResult.FromError(CommandError.ObjectNotFound, "The character doesn't have that bodypart."));
            }

            if (!currentComponent.Pattern.HasValue)
            {
                return(ShiftBodypartResult.FromError(CommandError.ObjectNotFound, "The bodypart doesn't have a pattern."));
            }

            if (currentComponent.PatternColour == patternColour)
            {
                return(ShiftBodypartResult.FromError(CommandError.Unsuccessful, "The pattern is already that colour."));
            }

            var originalColour = currentComponent.PatternColour;

            currentComponent.PatternColour = patternColour;

            await db.SaveChangesAsync();

            // ReSharper disable once AssignNullToNotNullAttribute - Having a pattern implies having a pattern colour
            string shiftMessage = this.DescriptionBuilder.BuildPatternColourShiftMessage(character, originalColour, currentComponent);

            return(ShiftBodypartResult.FromSuccess(shiftMessage));
        }
Ejemplo n.º 29
0
        /// <summary>
        /// Deletes a dossier from the database.
        /// </summary>
        /// <param name="db">The database where dossier metadata is stored.</param>
        /// <param name="dossier">The dossier to delete.</param>
        /// <returns>A deletion result which may or may not have succeeded.</returns>
        public async Task <DeleteEntityResult> DeleteDossierAsync
        (
            [NotNull] GlobalInfoContext db,
            [NotNull] Dossier dossier
        )
        {
            var deleteContentResult = await this.Content.DeleteDossierDataAsync(dossier);

            if (!deleteContentResult.IsSuccess)
            {
                return(deleteContentResult);
            }

            db.Dossiers.Remove(dossier);
            await db.SaveChangesAsync();

            return(DeleteEntityResult.FromSuccess());
        }
        /// <summary>
        /// Removes the named image from the given character.
        /// </summary>
        /// <param name="db">The database where the characters and images are stored.</param>
        /// <param name="character">The character to remove the image from.</param>
        /// <param name="imageName">The name of the image.</param>
        /// <returns>An execution result which may or may not have succeeded.</returns>
        public async Task <ModifyEntityResult> RemoveImageFromCharacterAsync
        (
            [NotNull] GlobalInfoContext db,
            [NotNull] Character character,
            [NotNull] string imageName
        )
        {
            bool hasNamedImage = character.Images.Any(i => string.Equals(i.Name, imageName, StringComparison.OrdinalIgnoreCase));

            if (!hasNamedImage)
            {
                return(ModifyEntityResult.FromError(CommandError.MultipleMatches, "The character has no image with that name."));
            }

            character.Images.RemoveAll(i => string.Equals(i.Name, imageName, StringComparison.OrdinalIgnoreCase));
            await db.SaveChangesAsync();

            return(ModifyEntityResult.FromSuccess(ModifyEntityAction.Added));
        }