Exemplo n.º 1
0
        protected virtual void Dispose(bool disposing)
        {
            if (!_disposedValue)
            {
                if (disposing)
                {
                    Fights.Dispose();
                    Bid.Dispose();
                    Roleplay.Dispose();
                    Flood.Dispose();
                    CharacterCreation.Dispose();
                }

                Fights            = null;
                Bid               = null;
                Roleplay          = null;
                Flood             = null;
                CharacterCreation = null;

                _disposedValue = true;
            }
        }
Exemplo n.º 2
0
        public async Task TransferRoleplayOwnershipAsync
        (
            IGuildUser newOwner,
            [RequireEntityOwnerOrPermission(typeof(TransferRoleplay), PermissionTarget.Other)]
            Roleplay roleplay
        )
        {
            var transferResult = await _discordRoleplays.TransferRoleplayOwnershipAsync
                                 (
                newOwner,
                roleplay
                                 );

            if (!transferResult.IsSuccess)
            {
                await _feedback.SendErrorAsync(this.Context, transferResult.ErrorReason);

                return;
            }

            await _feedback.SendConfirmationAsync(this.Context, "Roleplay ownership transferred.");
        }
Exemplo n.º 3
0
        public async Task InvitePlayerAsync
        (
            [NotNull]
            IUser playerToInvite,
            [NotNull]
            [RequireEntityOwnerOrPermission(typeof(EditRoleplay), PermissionTarget.Other)]
            Roleplay roleplay
        )
        {
            var invitePlayerResult = await _roleplays.InviteUserAsync(roleplay, playerToInvite);

            if (!invitePlayerResult.IsSuccess)
            {
                await _feedback.SendErrorAsync(this.Context, invitePlayerResult.ErrorReason);

                return;
            }

            await _feedback.SendConfirmationAsync(this.Context, $"Invited {playerToInvite.Mention} to {roleplay.Name}.");

            var userDMChannel = await playerToInvite.GetOrCreateDMChannelAsync();

            try
            {
                var roleplayName = roleplay.Name.Contains(" ") ? roleplay.Name.Quote() : roleplay.Name;

                await userDMChannel.SendMessageAsync
                (
                    $"You've been invited to join {roleplay.Name}. Use `!rp join {roleplayName}` to join."
                );
            }
            catch (HttpException hex) when(hex.WasCausedByDMsNotAccepted())
            {
            }
            finally
            {
                await userDMChannel.CloseAsync();
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// Removes the given user from the given roleplay.
        /// </summary>
        /// <param name="roleplay">The roleplay to remove the user from.</param>
        /// <param name="removedUser">The user to remove from the roleplay.</param>
        /// <returns>An execution result which may or may not have succeeded.</returns>
        public async Task <DeleteEntityResult> RemoveUserFromRoleplayAsync(Roleplay roleplay, User removedUser)
        {
            removedUser = _database.NormalizeReference(removedUser);

            if (!roleplay.HasJoined(removedUser))
            {
                return(DeleteEntityResult.FromError("No matching user found in the roleplay."));
            }

            if (roleplay.IsOwner(removedUser))
            {
                return(DeleteEntityResult.FromError("The owner of a roleplay can't be removed from it."));
            }

            var participantEntry = roleplay.JoinedUsers.FirstOrDefault(p => p.User == removedUser);

            roleplay.ParticipatingUsers.Remove(participantEntry);

            await _database.SaveChangesAsync();

            return(DeleteEntityResult.FromSuccess());
        }
        public async Task <RuntimeResult> InvitePlayerAsync
        (
            IGuildUser playerToInvite,
            [RequireEntityOwnerOrPermission(typeof(EditRoleplay), PermissionTarget.Other)]
            Roleplay roleplay
        )
        {
            var invitePlayerResult = await _discordRoleplays.InviteUserToRoleplayAsync(roleplay, playerToInvite);

            if (!invitePlayerResult.IsSuccess)
            {
                return(invitePlayerResult.ToRuntimeResult());
            }

            var userDMChannel = await playerToInvite.GetOrCreateDMChannelAsync();

            try
            {
                var roleplayName = roleplay.Name.Contains(" ") ? roleplay.Name.Quote() : roleplay.Name;

                await userDMChannel.SendMessageAsync
                (
                    $"You've been invited to join {roleplay.Name}. Use `!rp join {roleplayName}` to join."
                );
            }
            catch (HttpException hex) when(hex.WasCausedByDMsNotAccepted())
            {
            }
            finally
            {
                await userDMChannel.CloseAsync();
            }

            return(RuntimeCommandResult.FromSuccess
                   (
                       $"Invited {playerToInvite.Mention} to {roleplay.Name}."
                   ));
        }
            public async Task SetRoleplayIsPublic
            (
                bool isPublic,
                [NotNull]
                [RequireEntityOwnerOrPermission(typeof(EditRoleplay), PermissionTarget.Other)]
                Roleplay roleplay
            )
            {
                var result = await _roleplays.SetRoleplayIsPublicAsync(roleplay, isPublic);

                if (!result.IsSuccess)
                {
                    await _feedback.SendErrorAsync(this.Context, result.ErrorReason);

                    return;
                }

                var getDedicatedChannelResult = await _roleplays.GetDedicatedRoleplayChannelAsync
                                                (
                    this.Context.Guild,
                    roleplay
                                                );

                if (getDedicatedChannelResult.IsSuccess)
                {
                    var dedicatedChannel = getDedicatedChannelResult.Entity;
                    var everyoneRole     = this.Context.Guild.EveryoneRole;

                    await _roleplays.SetDedicatedChannelVisibilityForRoleAsync
                    (
                        dedicatedChannel,
                        everyoneRole,
                        isPublic
                    );
                }

                await _feedback.SendConfirmationAsync(this.Context, $"Roleplay set to {(isPublic ? "public" : "private")}");
            }
        public async Task <RuntimeResult> ExportRoleplayAsync
        (
            [RequireEntityOwnerOrPermission(typeof(ExportRoleplay), PermissionTarget.Other)]
            Roleplay roleplay,
            [OverrideTypeReader(typeof(HumanizerEnumTypeReader <ExportFormat>))]
            ExportFormat format = ExportFormat.PDF
        )
        {
            IRoleplayExporter exporter;

            switch (format)
            {
            case ExportFormat.PDF:
            {
                exporter = new PDFRoleplayExporter(this.Context.Guild);
                break;
            }

            case ExportFormat.Plaintext:
            {
                exporter = new PlaintextRoleplayExporter(this.Context.Guild);
                break;
            }

            default:
            {
                return(RuntimeCommandResult.FromError("That export format hasn't been implemented yet."));
            }
            }

            await _feedback.SendConfirmationAsync(this.Context, "Compiling the roleplay...");

            using var output = await exporter.ExportAsync(roleplay);

            await this.Context.Channel.SendFileAsync(output.Data, $"{output.Title}.{output.Format.GetFileExtension()}");

            return(RuntimeCommandResult.FromSuccess());
        }
Exemplo n.º 8
0
    public async Task <Result <FeedbackMessage> > StartRoleplayAsync
    (
        [RequireEntityOwner]
        [AutocompleteProvider("roleplay::owned")]
        Roleplay roleplay
    )
    {
        var startRoleplayResult = await _discordRoleplays.StartRoleplayAsync
                                  (
            _context.ChannelID,
            roleplay
                                  );

        if (!startRoleplayResult.IsSuccess)
        {
            return(Result <FeedbackMessage> .FromError(startRoleplayResult));
        }

        var activationMessage = $"The roleplay \"{roleplay.Name}\" is now active in " +
                                $"<#{roleplay.ActiveChannelID!.Value}>.";

        return(new FeedbackMessage(activationMessage, _feedback.Theme.Secondary));
    }
        public async Task MakeRoleplayCurrentAsync
        (
            [NotNull]
            [RequireEntityOwnerOrPermission(Permission.StartStopRoleplay, PermissionTarget.Other)]
            Roleplay roleplay
        )
        {
            this.Database.Attach(roleplay);

            var isNsfwChannel = this.Context.Channel is ITextChannel textChannel && textChannel.IsNsfw;

            if (roleplay.IsNSFW && !isNsfwChannel)
            {
                await this.Feedback.SendErrorAsync(this.Context, "This channel is not marked as NSFW, while your roleplay is... naughty!");

                return;
            }

            roleplay.ActiveChannelID = (long)this.Context.Channel.Id;
            await this.Database.SaveChangesAsync();

            await this.Feedback.SendConfirmationAsync(this.Context, $"The roleplay \"{roleplay.Name}\" is now current in #{this.Context.Channel.Name}.");
        }
        /// <summary>
        /// Sets the summary of the given roleplay.
        /// </summary>
        /// <param name="roleplay">The roleplay to set the summary of.</param>
        /// <param name="summary">The new summary.</param>
        /// <returns>A modification result which may or may not have succeeded.</returns>
        public async Task <ModifyEntityResult> SetRoleplaySummaryAsync(Roleplay roleplay, string summary)
        {
            var setSummary = await _roleplays.SetRoleplaySummaryAsync(roleplay, summary);

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

            if (!roleplay.DedicatedChannelID.HasValue)
            {
                return(ModifyEntityResult.FromSuccess());
            }

            var setChannelSummary = await _dedicatedChannels.UpdateChannelSummaryAsync(roleplay);

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

            return(ModifyEntityResult.FromSuccess());
        }
        /// <summary>
        /// Sets the NSFW status of the roleplay.
        /// </summary>
        /// <param name="roleplay">The roleplay.</param>
        /// <param name="isNSFW">Whether the roleplay is NSFW.</param>
        /// <returns>A modification result which may or may not have succeeded.</returns>
        public async Task <ModifyEntityResult> SetRoleplayIsNSFWAsync(Roleplay roleplay, bool isNSFW)
        {
            var setNSFW = await _roleplays.SetRoleplayIsNSFWAsync(roleplay, isNSFW);

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

            if (!roleplay.DedicatedChannelID.HasValue)
            {
                return(setNSFW);
            }

            var setChannelNSFW = await _dedicatedChannels.UpdateChannelNSFWStatus(roleplay);

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

            return(ModifyEntityResult.FromSuccess());
        }
Exemplo n.º 12
0
        /// <summary>
        /// Sets whether or not a roleplay is NSFW.
        /// </summary>
        /// <param name="roleplay">The roleplay to set the value in.</param>
        /// <param name="isNSFW">The new value.</param>
        /// <param name="ct">The cancellation token in use.</param>
        /// <returns>A modification result which may or may not have succeeded.</returns>
        public async Task <ModifyEntityResult> SetRoleplayIsNSFWAsync
        (
            Roleplay roleplay,
            bool isNSFW,
            CancellationToken ct = default
        )
        {
            if (roleplay.IsNSFW == isNSFW)
            {
                return(ModifyEntityResult.FromError($"The roleplay is already {(isNSFW ? "NSFW" : "SFW")}."));
            }

            if (roleplay.Messages.Count > 0 && roleplay.IsNSFW && !isNSFW)
            {
                return(ModifyEntityResult.FromError("You can't mark a NSFW roleplay with messages in it as non-NSFW."));
            }

            roleplay.IsNSFW = isNSFW;

            await _database.SaveChangesAsync(ct);

            return(ModifyEntityResult.FromSuccess());
        }
Exemplo n.º 13
0
        public async Task RefreshRoleplayAsync(Roleplay roleplay)
        {
            var isOwner       = roleplay.IsOwner(this.Context.User);
            var isParticipant = roleplay.HasJoined(this.Context.User);

            if (!(isOwner || isParticipant))
            {
                await _feedback.SendErrorAsync(this.Context, "You don't own that roleplay, nor are you a participant.");

                return;
            }

            var refreshResult = await _roleplays.RefreshRoleplayAsync(roleplay);

            if (!refreshResult.IsSuccess)
            {
                await _feedback.SendErrorAsync(this.Context, refreshResult.ErrorReason);

                return;
            }

            await _feedback.SendConfirmationAsync(this.Context, "Timeout refreshed.");
        }
Exemplo n.º 14
0
        /// <summary>
        /// Invites the user to the given roleplay.
        /// </summary>
        /// <param name="roleplay">The roleplay to invite the user to.</param>
        /// <param name="invitedUser">The user to invite.</param>
        /// <param name="ct">The cancellation token in use.</param>
        /// <returns>An execution result which may or may not have succeeded.</returns>
        public async Task <ModifyEntityResult> InviteUserToRoleplayAsync
        (
            Roleplay roleplay,
            User invitedUser,
            CancellationToken ct = default
        )
        {
            invitedUser = _database.NormalizeReference(invitedUser);

            if (roleplay.InvitedUsers.Any(p => p.User.DiscordID == invitedUser.DiscordID))
            {
                return(ModifyEntityResult.FromError("The user has already been invited to that roleplay."));
            }

            // Remove the invited user from the kick list, if they're on it
            var participantEntry = roleplay.ParticipatingUsers.FirstOrDefault
                                   (
                p => p.User.DiscordID == invitedUser.DiscordID
                                   );

            if (participantEntry is null)
            {
                participantEntry = _database.CreateProxy <RoleplayParticipant>(roleplay, invitedUser);
                _database.Update(participantEntry);

                participantEntry.Status = ParticipantStatus.Invited;
                roleplay.ParticipatingUsers.Add(participantEntry);
            }
            else
            {
                participantEntry.Status = ParticipantStatus.Invited;
            }

            await _database.SaveChangesAsync(ct);

            return(ModifyEntityResult.FromSuccess());
        }
Exemplo n.º 15
0
        public async Task <RuntimeResult> KickRoleplayParticipantAsync
        (
            IGuildUser discordUser,
            [RequireEntityOwnerOrPermission(typeof(KickRoleplayMember), PermissionTarget.Other)]
            Roleplay roleplay
        )
        {
            var kickUserResult = await _discordRoleplays.KickUserFromRoleplayAsync(roleplay, discordUser);

            if (!kickUserResult.IsSuccess)
            {
                return(kickUserResult.ToRuntimeResult());
            }

            var userDMChannel = await discordUser.GetOrCreateDMChannelAsync();

            try
            {
                await userDMChannel.SendMessageAsync
                (
                    $"You've been removed from the roleplay \"{roleplay.Name}\" by " +
                    $"{this.Context.Message.Author.Username}."
                );
            }
            catch (HttpException hex) when(hex.WasCausedByDMsNotAccepted())
            {
            }
            finally
            {
                await userDMChannel.CloseAsync();
            }

            return(RuntimeCommandResult.FromSuccess
                   (
                       $"{discordUser.Mention} has been kicked from {roleplay.Name}."
                   ));
        }
        public async Task InvitePlayerAsync
        (
            [NotNull]
            IUser playerToInvite,
            [NotNull]
            [RequireEntityOwnerOrPermission(Permission.EditRoleplay, PermissionTarget.Other)]
            Roleplay roleplay
        )
        {
            this.Database.Attach(roleplay);

            var invitePlayerResult = await this.Roleplays.InviteUserAsync(this.Database, roleplay, playerToInvite);

            if (!invitePlayerResult.IsSuccess)
            {
                await this.Feedback.SendErrorAsync(this.Context, invitePlayerResult.ErrorReason);

                return;
            }

            await this.Feedback.SendConfirmationAsync(this.Context, $"Invited {playerToInvite.Mention} to {roleplay.Name}.");

            var userDMChannel = await playerToInvite.GetOrCreateDMChannelAsync();

            try
            {
                await userDMChannel.SendMessageAsync(
                    $"You've been invited to join {roleplay.Name}. Use \"!rp join {roleplay.Name}\" to join.");
            }
            catch (HttpException hex) when(hex.WasCausedByDMsNotAccepted())
            {
            }
            finally
            {
                await userDMChannel.CloseAsync();
            }
        }
        /// <summary>
        /// Notifies the owner of the roleplay that it was stopped because it timed out.
        /// </summary>
        /// <param name="roleplay">The roleplay.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        private async Task <OperationResult> NotifyOwnerAsync(Roleplay roleplay)
        {
            var owner = this.Client.GetUser((ulong)roleplay.Owner.DiscordID);

            if (owner is null)
            {
                return(OperationResult.FromError("Could not retrieve the owner of the roleplay."));
            }

            var notification = _feedback.CreateEmbedBase();

            notification.WithDescription
            (
                $"Your roleplay \"{roleplay.Name}\" has been inactive for more than 28 days, and has been " +
                $"archived.\n" +
                $"\n" +
                $"This means that the dedicated channel that the roleplay had has been deleted. All messages in the " +
                $"roleplay have been saved, and can be exported or replayed as normal."
            );

            notification.WithFooter
            (
                $"You can export it by running !rp export \"{roleplay.Name}\"."
            );

            try
            {
                await owner.SendMessageAsync(string.Empty, embed : notification.Build());
            }
            catch (HttpException hex) when(hex.WasCausedByDMsNotAccepted())
            {
                // Nom nom nom
            }

            return(OperationResult.FromSuccess());
        }
Exemplo n.º 18
0
        /// <summary>
        /// Invites the user to the given roleplay.
        /// </summary>
        /// <param name="db">The database where the roleplays are stored.</param>
        /// <param name="roleplay">The roleplay to invite the user to.</param>
        /// <param name="invitedUser">The user to invite.</param>
        /// <returns>An execution result which may or may not have succeeded.</returns>
        public async Task <ExecuteResult> InviteUserAsync
        (
            [NotNull] GlobalInfoContext db,
            [NotNull] Roleplay roleplay,
            [NotNull] IUser invitedUser
        )
        {
            if (roleplay.IsPublic)
            {
                return(ExecuteResult.FromError(CommandError.UnmetPrecondition, "The roleplay is not set to private."));
            }

            if (roleplay.InvitedUsers.Any(p => p.User.DiscordID == (long)invitedUser.Id))
            {
                return(ExecuteResult.FromError(CommandError.Unsuccessful, "The user has already been invited to that roleplay."));
            }

            // Remove the invited user from the kick list, if they're on it
            var participantEntry = roleplay.ParticipatingUsers.FirstOrDefault(p => p.User.DiscordID == (long)invitedUser.Id);

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

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

            await db.SaveChangesAsync();

            return(ExecuteResult.FromSuccess());
        }
Exemplo n.º 19
0
        public async Task <RuntimeResult> ViewRoleplayAsync(Roleplay roleplay)
        {
            var getDedicatedChannelResult = await _dedicatedChannels.GetDedicatedChannelAsync
                                            (
                this.Context.Guild,
                roleplay
                                            );

            if (!getDedicatedChannelResult.IsSuccess)
            {
                return(RuntimeCommandResult.FromError
                       (
                           "The given roleplay doesn't have a dedicated channel. Try using \"!rp export\" instead."
                       ));
            }

            var user = this.Context.User;

            if (!roleplay.IsPublic && roleplay.ParticipatingUsers.All(p => p.User.DiscordID != (long)user.Id))
            {
                return(RuntimeCommandResult.FromError
                       (
                           "You don't have permission to view that roleplay."
                       ));
            }

            var dedicatedChannel = getDedicatedChannelResult.Entity;
            await _dedicatedChannels.SetChannelVisibilityForUserAsync(dedicatedChannel, user, true);

            var channelMention = MentionUtils.MentionChannel(dedicatedChannel.Id);

            return(RuntimeCommandResult.FromSuccess
                   (
                       $"The roleplay \"{roleplay.Name}\" is now visible in {channelMention}."
                   ));
        }
    private static async Task <Result> ArchiveRoleplayAsync
    (
        IServiceProvider services,
        FeedbackService feedback,
        RoleplayDiscordService roleplayService,
        DedicatedChannelService dedicatedChannels,
        RoleplayServerSettingsService serverSettings,
        Roleplay roleplay
    )
    {
        if (roleplay.DedicatedChannelID is null)
        {
            return(new UserError("The roleplay doesn't have a dedicated channel."));
        }

        var ensureLogged = await roleplayService.EnsureAllMessagesAreLoggedAsync(roleplay);

        if (!ensureLogged.IsSuccess)
        {
            return(Result.FromError(ensureLogged));
        }

        if (!roleplay.IsPublic)
        {
            return(await dedicatedChannels.DeleteChannelAsync(roleplay));
        }

        var postResult = await PostArchivedRoleplayAsync(services, feedback, serverSettings, roleplay);

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

        return(await dedicatedChannels.DeleteChannelAsync(roleplay));
    }
        /// <summary>
        /// Updates the summary of the roleplay channel.
        /// </summary>
        /// <param name="roleplay">The roleplay.</param>
        /// <returns>A modification result which may or may not have succeeded.</returns>
        public async Task <ModifyEntityResult> UpdateChannelSummaryAsync(Roleplay roleplay)
        {
            var guild = await _client.GetGuildAsync((ulong)roleplay.Server.DiscordID);

            if (guild is null)
            {
                return(ModifyEntityResult.FromError("Could not retrieve a valid guild."));
            }

            var getChannel = await GetDedicatedChannelAsync(guild, roleplay);

            if (!getChannel.IsSuccess)
            {
                return(ModifyEntityResult.FromError(getChannel));
            }

            var channel = getChannel.Entity;
            await channel.ModifyAsync
            (
                m => m.Topic = $"Dedicated roleplay channel for {roleplay.Name}. {roleplay.Summary}"
            );

            return(ModifyEntityResult.FromSuccess());
        }
Exemplo n.º 22
0
        /// <summary>
        /// Removes 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="removedUser">The user to remove from the roleplay.</param>
        /// <returns>An execution result which may or may not have succeeded.</returns>
        public async Task <ExecuteResult> RemoveUserFromRoleplayAsync
        (
            [NotNull] GlobalInfoContext db,
            [NotNull] SocketCommandContext context,
            [NotNull] Roleplay roleplay,
            [NotNull] IUser removedUser
        )
        {
            var isCurrentUser = context.Message.Author.Id == removedUser.Id;

            if (!roleplay.HasJoined(removedUser))
            {
                var errorMessage = isCurrentUser
                                        ? "You're not in that roleplay."
                                        : "No matching user found in the roleplay.";

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

            if (roleplay.IsOwner(removedUser))
            {
                var errorMessage = isCurrentUser
                                        ? "You can't leave a roleplay you own."
                                        : "The owner of a roleplay can't be removed from it.";

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

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

            participantEntry.Status = ParticipantStatus.None;

            await db.SaveChangesAsync();

            return(ExecuteResult.FromSuccess());
        }
 /// <summary>
 /// Refreshes the timestamp on the given roleplay.
 /// </summary>
 /// <param name="roleplay">The roleplay.</param>
 /// <returns>A <see cref="Task{TResult}"/> representing the result of the asynchronous operation.</returns>
 public Task <ModifyEntityResult> RefreshRoleplayAsync(Roleplay roleplay)
 {
     return(_roleplays.RefreshRoleplayAsync(roleplay));
 }
Exemplo n.º 24
0
        /// <summary>
        /// Creates a roleplay with the given parameters.
        /// </summary>
        /// <param name="db">The database where the roleplays are stored.</param>
        /// <param name="context">The context of the command.</param>
        /// <param name="roleplayName">The name of the roleplay.</param>
        /// <param name="roleplaySummary">The summary of the roleplay.</param>
        /// <param name="isNSFW">Whether or not the roleplay is NSFW.</param>
        /// <param name="isPublic">Whether or not the roleplay is public.</param>
        /// <returns>A creation result which may or may not have been successful.</returns>
        public async Task <CreateEntityResult <Roleplay> > CreateRoleplayAsync
        (
            [NotNull] GlobalInfoContext db,
            [NotNull] SocketCommandContext context,
            [NotNull] string roleplayName,
            [NotNull] string roleplaySummary,
            bool isNSFW,
            bool isPublic)
        {
            var owner = await db.GetOrRegisterUserAsync(context.Message.Author);

            var roleplay = new Roleplay
            {
                Owner              = owner,
                ServerID           = (long)context.Guild.Id,
                IsActive           = false,
                ActiveChannelID    = (long)context.Channel.Id,
                ParticipatingUsers = new List <RoleplayParticipant>(),
                Messages           = new List <UserMessage>()
            };

            roleplay.ParticipatingUsers.Add(new RoleplayParticipant(roleplay, owner, ParticipantStatus.Joined));

            var setNameResult = await SetRoleplayNameAsync(db, context, roleplay, roleplayName);

            if (!setNameResult.IsSuccess)
            {
                return(CreateEntityResult <Roleplay> .FromError(setNameResult));
            }

            var setSummaryResult = await SetRoleplaySummaryAsync(db, roleplay, roleplaySummary);

            if (!setSummaryResult.IsSuccess)
            {
                return(CreateEntityResult <Roleplay> .FromError(setSummaryResult));
            }

            var setIsNSFWResult = await SetRoleplayIsNSFWAsync(db, roleplay, isNSFW);

            if (!setIsNSFWResult.IsSuccess)
            {
                return(CreateEntityResult <Roleplay> .FromError(setIsNSFWResult));
            }

            var setIsPublicResult = await SetRoleplayIsPublicAsync(db, roleplay, isPublic);

            if (!setIsPublicResult.IsSuccess)
            {
                return(CreateEntityResult <Roleplay> .FromError(setIsPublicResult));
            }

            await db.Roleplays.AddAsync(roleplay);

            await db.SaveChangesAsync();

            var roleplayResult = await GetUserRoleplayByNameAsync(db, context, context.Message.Author, roleplayName);

            if (!roleplayResult.IsSuccess)
            {
                return(CreateEntityResult <Roleplay> .FromError(roleplayResult));
            }

            return(CreateEntityResult <Roleplay> .FromSuccess(roleplayResult.Entity));
        }
        /// <inheritdoc />
        public override async Task <ExportedRoleplay> ExportAsync(Roleplay roleplay)
        {
            // Create our document
            var pdfDoc = new Document();

            var filePath = Path.GetTempFileName();

            using (var of = File.Create(filePath))
            {
                var writer = PdfWriter.GetInstance(pdfDoc, of);
                writer.Open();
                pdfDoc.Open();

                var owner = await this.Guild.GetUserAsync((ulong)roleplay.Owner.DiscordID);

                pdfDoc.AddAuthor(owner.Nickname);
                pdfDoc.AddCreationDate();
                pdfDoc.AddCreator("DIGOS Ambassador");
                pdfDoc.AddTitle(roleplay.Name);

                var joinedUsers = await Task.WhenAll
                                  (
                    roleplay.JoinedUsers.Select
                    (
                        async p =>
                {
                    var guildUser = await this.Guild.GetUserAsync((ulong)p.User.DiscordID);
                    if (guildUser is null)
                    {
                        var messageByUser = roleplay.Messages.FirstOrDefault
                                            (
                            m => m.AuthorDiscordID == p.User.DiscordID
                                            );

                        if (messageByUser is null)
                        {
                            return($"Unknown user ({p.User.DiscordID})");
                        }

                        return(messageByUser.AuthorNickname);
                    }

                    return(guildUser.Username);
                }
                    )
                                  );

                pdfDoc.Add(CreateTitle(roleplay.Name));
                pdfDoc.Add(CreateParticipantList(joinedUsers));

                pdfDoc.NewPage();

                var messages = roleplay.Messages.OrderBy(m => m.Timestamp).DistinctBy(m => m.Contents);
                foreach (var message in messages)
                {
                    pdfDoc.Add(CreateMessage(message.AuthorNickname, message.Contents));
                }

                pdfDoc.Close();
                writer.Flush();
                writer.Close();
            }

            var resultFile = File.OpenRead(filePath);
            var exported   = new ExportedRoleplay(roleplay.Name, ExportFormat.PDF, resultFile);

            return(exported);
        }
        /// <summary>
        /// Starts the given roleplay in the current channel, or the dedicated channel if one exists.
        /// </summary>
        /// <param name="currentChannel">The current channel.</param>
        /// <param name="roleplay">The roleplay.</param>
        /// <returns>A modification result which may or may not have succeeded.</returns>
        public async Task <ModifyEntityResult> StartRoleplayAsync(ITextChannel currentChannel, Roleplay roleplay)
        {
            var guild = currentChannel.Guild;

            var getDedicatedChannelResult = await _dedicatedChannels.GetDedicatedChannelAsync
                                            (
                guild,
                roleplay
                                            );

            // Identify the channel to start the RP in. Preference is given to the roleplay's dedicated channel.
            var channel = getDedicatedChannelResult.IsSuccess ? getDedicatedChannelResult.Entity : currentChannel;

            if (roleplay.IsNSFW && !channel.IsNsfw)
            {
                return(ModifyEntityResult.FromError
                       (
                           "This channel is not marked as NSFW, while your roleplay is... naughty!"
                       ));
            }

            if (await HasActiveRoleplayAsync(channel))
            {
                var currentRoleplayResult = await GetActiveRoleplayAsync(channel);

                if (!currentRoleplayResult.IsSuccess)
                {
                    return(ModifyEntityResult.FromError(currentRoleplayResult));
                }

                var currentRoleplay   = currentRoleplayResult.Entity;
                var timeOfLastMessage = currentRoleplay.Messages.Last().Timestamp;
                var currentTime       = DateTimeOffset.Now;

                if (timeOfLastMessage < currentTime.AddHours(-4))
                {
                    currentRoleplay.IsActive = false;
                }
                else
                {
                    return(ModifyEntityResult.FromError("There's already a roleplay active in this channel."));
                }
            }

            var start = await _roleplays.StartRoleplayAsync(roleplay, (long)channel.Id);

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

            // If the channel in question is the roleplay's dedicated channel, enable it
            if (!roleplay.DedicatedChannelID.HasValue)
            {
                return(ModifyEntityResult.FromSuccess());
            }

            var enableChannel = await _dedicatedChannels.UpdateParticipantPermissionsAsync(guild, roleplay);

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

            return(ModifyEntityResult.FromSuccess());
        }
        public async Task ReplayRoleplayAsync
        (
            [NotNull] Roleplay roleplay,
            DateTimeOffset from = default,
            DateTimeOffset to   = default
        )
        {
            if (from == default)
            {
                from = DateTimeOffset.MinValue;
            }

            if (to == default)
            {
                to = DateTimeOffset.Now;
            }

            var userDMChannel = await this.Context.Message.Author.GetOrCreateDMChannelAsync();

            var eb = CreateRoleplayInfoEmbed(roleplay);

            try
            {
                await userDMChannel.SendMessageAsync(string.Empty, false, eb);

                var messages = roleplay.Messages.Where
                               (
                    m =>
                    m.Timestamp > from && m.Timestamp < to
                               )
                               .OrderBy(msg => msg.Timestamp).ToList();

                var timestampEmbed = this.Feedback.CreateFeedbackEmbed
                                     (
                    this.Context.User,
                    Color.DarkPurple,
                    $"Roleplay began at {messages.First().Timestamp.ToUniversalTime()}"
                                     );

                await userDMChannel.SendMessageAsync(string.Empty, false, timestampEmbed);

                if (messages.Count <= 0)
                {
                    await userDMChannel.SendMessageAsync("No messages found in the specified timeframe.");

                    return;
                }

                await this.Feedback.SendConfirmationAsync
                (
                    this.Context,
                    $"Replaying \"{roleplay.Name}\". Please check your private messages."
                );

                const int messageCharacterLimit = 2000;
                var       sb = new StringBuilder(messageCharacterLimit);

                foreach (var message in messages)
                {
                    var newContent = $"**{message.AuthorNickname}** {message.Contents}\n";

                    if (sb.Length + newContent.Length >= messageCharacterLimit)
                    {
                        await userDMChannel.SendMessageAsync(sb.ToString());

                        await Task.Delay(TimeSpan.FromSeconds(2));

                        sb.Clear();
                        sb.AppendLine();
                    }

                    sb.Append(newContent);

                    if (message.ID == messages.Last().ID)
                    {
                        await userDMChannel.SendMessageAsync(sb.ToString());
                    }
                }
            }
            catch (HttpException hex) when(hex.WasCausedByDMsNotAccepted())
            {
                await this.Feedback.SendWarningAsync
                (
                    this.Context,
                    "I can't do that, since you don't accept DMs from non-friends on this server."
                );
            }
            finally
            {
                await userDMChannel.CloseAsync();
            }
        }
        public async Task StartRoleplayAsync
        (
            [NotNull]
            [RequireEntityOwnerOrPermission(Permission.StartStopRoleplay, PermissionTarget.Other)]
            Roleplay roleplay
        )
        {
            this.Database.Attach(roleplay);

            var isNsfwChannel = this.Context.Channel is ITextChannel textChannel && textChannel.IsNsfw;

            if (roleplay.IsNSFW && !isNsfwChannel)
            {
                await this.Feedback.SendErrorAsync(this.Context, "This channel is not marked as NSFW, while your roleplay is... naughty!");

                return;
            }

            if (await this.Roleplays.HasActiveRoleplayAsync(this.Database, this.Context.Channel))
            {
                await this.Feedback.SendWarningAsync(this.Context, "There's already a roleplay active in this channel.");

                var currentRoleplayResult = await this.Roleplays.GetActiveRoleplayAsync(this.Database, this.Context);

                if (!currentRoleplayResult.IsSuccess)
                {
                    await this.Feedback.SendErrorAsync(this.Context, currentRoleplayResult.ErrorReason);

                    return;
                }

                var currentRoleplay   = currentRoleplayResult.Entity;
                var timeOfLastMessage = currentRoleplay.Messages.Last().Timestamp;
                var currentTime       = DateTimeOffset.Now;
                if (timeOfLastMessage < currentTime.AddHours(-4))
                {
                    await this.Feedback.SendConfirmationAsync(this.Context, "However, that roleplay has been inactive for over four hours.");

                    currentRoleplay.IsActive = false;
                }
                else
                {
                    return;
                }
            }

            if (roleplay.ActiveChannelID != (long)this.Context.Channel.Id)
            {
                roleplay.ActiveChannelID = (long)this.Context.Channel.Id;
            }

            roleplay.IsActive = true;
            await this.Database.SaveChangesAsync();

            var joinedUsers    = roleplay.JoinedUsers.Select(p => this.Context.Client.GetUser((ulong)p.User.DiscordID));
            var joinedMentions = joinedUsers.Select(u => u.Mention);

            var participantList = joinedMentions.Humanize();

            await this.Feedback.SendConfirmationAsync(this.Context, $"The roleplay \"{roleplay.Name}\" is now active in {MentionUtils.MentionChannel(this.Context.Channel.Id)}.");

            await this.Context.Channel.SendMessageAsync($"Calling {participantList}!");
        }
Exemplo n.º 29
0
    public async Task <Result <FeedbackMessage> > ShowOrCreateDedicatedRoleplayChannel
    (
        [RequireEntityOwner]
        [AutocompleteProvider("roleplay::owned")]
        Roleplay roleplay
    )
    {
        var getDedicatedChannelResult = DedicatedChannelService.GetDedicatedChannel(roleplay);

        if (getDedicatedChannelResult.IsSuccess)
        {
            var existingDedicatedChannel = getDedicatedChannelResult.Entity;
            var message = $"\"{roleplay.Name}\" has a dedicated channel at " +
                          $"<#{existingDedicatedChannel}>";

            return(new FeedbackMessage(message, _feedback.Theme.Secondary));
        }

        var workingMessage = new Embed
        {
            Colour      = _feedback.Theme.Secondary,
            Description = "Setting up dedicated channel..."
        };

        var send = await _feedback.SendContextualEmbedAsync(workingMessage);

        if (!send.IsSuccess)
        {
            return(Result <FeedbackMessage> .FromError(send));
        }

        // The roleplay either doesn't have a channel, or the one it has has been deleted or is otherwise invalid.
        var result = await _dedicatedChannels.CreateDedicatedChannelAsync(roleplay);

        if (!result.IsSuccess)
        {
            return(Result <FeedbackMessage> .FromError(result));
        }

        var dedicatedChannel = result.Entity;

        if (!roleplay.IsActive || roleplay.ActiveChannelID == dedicatedChannel.ID)
        {
            return(new FeedbackMessage
                   (
                       $"All done! Your roleplay now has a dedicated channel at <#{dedicatedChannel}>.",
                       _feedback.Theme.Secondary
                   ));
        }

        var stopResult = await StopRoleplayAsync(roleplay);

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

        var startResult = await StartRoleplayAsync(roleplay);

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

        return(new FeedbackMessage
               (
                   $"All done! Your roleplay now has a dedicated channel at <#{dedicatedChannel}>.",
                   _feedback.Theme.Secondary
               ));
    }
        public async Task ShowRoleplayAsync([NotNull] Roleplay roleplay)
        {
            var eb = CreateRoleplayInfoEmbed(roleplay);

            await this.Feedback.SendEmbedAsync(this.Context, eb);
        }