Example #1
0
        public async Task <Dictionary <KeyValuePair <string, ulong>, DiscordSnapshotInfo> > GetLatestSnapshots(ulong ownerId, DateTime?filter = null)
        {
            Dictionary <KeyValuePair <string, ulong>, DiscordSnapshotInfo> snapshots = new Dictionary <KeyValuePair <string, ulong>, DiscordSnapshotInfo>();
            string ownerPath = Path.Combine(Core.Configuration.SnapshotsFolder, $"{ownerId}");

            if (!Directory.Exists(ownerPath))
            {
                return(snapshots);
            }

            foreach (var guildsDirectory in Directory.GetDirectories(ownerPath))
            {
                string snapshotHistoryPath = Path.Combine(guildsDirectory, "history.json");

                if (!File.Exists(snapshotHistoryPath))
                {
                    return(snapshots);
                }

                DiscordSnapshotHistory history =
                    JsonConvert.DeserializeObject <DiscordSnapshotHistory>(
                        await File.ReadAllTextAsync(snapshotHistoryPath));

                if (filter != null)
                {
                    history.History.RemoveAll(k => k.Value > filter);
                }

                if (history.History.Count == 0)
                {
                    continue;
                }

                history.History.Sort((c, k) =>
                {
                    if (c.Value < k.Value)
                    {
                        return(1);
                    }
                    if (c.Value > k.Value)
                    {
                        return(-1);
                    }
                    return(0);
                });

                string latestSnapshotPath = Path.Combine(guildsDirectory, $"{history.History.First().Key}.json");

                if (!File.Exists(latestSnapshotPath))
                {
                    continue;
                }

                DiscordSnapshotInfo info = JsonConvert.DeserializeObject <DiscordSnapshotInfo>(await File.ReadAllTextAsync(latestSnapshotPath));

                snapshots.Add(new KeyValuePair <string, ulong>(info.GuildName, info.GuildId), info);
            }

            return(snapshots);
        }
Example #2
0
        public async Task TakeSnapshot(CommandContext ctx)
        {
            if (ctx.Guild == null)
            {
                await ctx.RespondAsync($"**This command has to be ran inside a Discord server!**");

                return;
            }


            if (ctx.Guild.Owner.Id != ctx.User.Id)
            {
                await ctx.RespondAsync($"**You must be the owner of this server to run this command!**");

                return;
            }

            if (!Core.Configuration.AllowedUsers.Contains(ctx.User.Id))
            {
                await ctx.RespondAsync($"**You're not allowed to use this bot!**");

                return;
            }

            DiscordSnapshotInfo snapshot = await Core.DiscordBot.PerformSnapshot(ctx.Guild);


            string successText = $"Done! Snapshot Id: **{snapshot.SnapshotId}**\n";

            successText += $"If this backup is important to you, you should write it down somewhere so that you do not forget it.\n";
            successText += "At all times, you can always go back to this snapshot using the command you know and the ID of the important backup you just did.\n";
            successText += "Automatic backups will keep taking place, but if you think that this is a stable backup, please write it down somewhere.";
            await ctx.RespondAsync(successText);
        }
Example #3
0
        public async Task <DiscordSnapshotInfo> PushSnapshot(DiscordSnapshotInfo snapshotInfo)
        {
            snapshotInfo.SnapshotId = Guid.NewGuid();
            string snapshotDir = Path.Combine(Core.Configuration.SnapshotsFolder, $"{snapshotInfo.OwnerId}",
                                              $"{snapshotInfo.GuildId}");
            string snapshotPath        = Path.Combine(snapshotDir, $"{snapshotInfo.SnapshotId.ToString()}.json");
            string snapshotHistoryPath = Path.Combine(snapshotDir, "history.json");

            string snapshotData = JsonConvert.SerializeObject(snapshotInfo, Formatting.Indented);

            Directory.CreateDirectory(Path.GetDirectoryName(snapshotPath));

            await File.WriteAllTextAsync(snapshotPath, snapshotData);

            DiscordSnapshotHistory history;

            if (!File.Exists(snapshotHistoryPath))
            {
                history = new DiscordSnapshotHistory()
                {
                    History = new List <KeyValuePair <Guid, DateTime> >()
                };
            }
            else
            {
                string historyText = await File.ReadAllTextAsync(snapshotHistoryPath);

                history = JsonConvert.DeserializeObject <DiscordSnapshotHistory>(historyText);
            }

            history.History.Add(new KeyValuePair <Guid, DateTime>(snapshotInfo.SnapshotId, snapshotInfo.TakenAt));

            await File.WriteAllTextAsync(snapshotHistoryPath, JsonConvert.SerializeObject(history, Formatting.Indented));

            return(snapshotInfo);
        }
Example #4
0
        public async Task <DiscordSnapshotInfo> PerformSnapshot(DiscordGuild guild)
        {
            if (guildDisabledSnapshots.Contains(guild.Id))
            {
                return(null);
            }

            Console.WriteLine($"[Snapshot] Performing guild {guild.Name} snapshot", Color.DarkCyan);


            DiscordSnapshotInfo snapshotInfo = new DiscordSnapshotInfo();

            snapshotInfo.RolesSnapshot    = new List <DiscordRoleSnapshotInfo>();
            snapshotInfo.ChannelsSnapshot = new List <DiscordChannelSnapshotInfo>();
            snapshotInfo.GuildName        = guild.Name;
            snapshotInfo.GuildId          = guild.Id;


            var roles = guild.Roles;
            Dictionary <ulong, Guid> rolesMapping = new Dictionary <ulong, Guid>();

            foreach (var role in roles)
            {
                Console.WriteLine($"[Snapshot] [{guild.Name}] Performing role {role.Name} snapshot", Color.DarkCyan);

                DiscordRoleSnapshotInfo roleSnapshot = new DiscordRoleSnapshotInfo();

                roleSnapshot.InternalRoleId = Guid.NewGuid();
                roleSnapshot.RoleName       = role.Name;
                roleSnapshot.RoleColor      = role.Color.Value;
                roleSnapshot.IsSeparated    = role.IsHoisted;
                roleSnapshot.IsMentionable  = role.IsMentionable;
                roleSnapshot.Hierarchy      = role.Position;
                roleSnapshot.Permissions    = (ulong)role.Permissions;
                roleSnapshot.IsEveryone     = role.Name == "@everyone";

                rolesMapping.Add(role.Id, roleSnapshot.InternalRoleId);
                snapshotInfo.RolesSnapshot.Add(roleSnapshot);
            }

            var channels = await guild.GetChannelsAsync();

            Dictionary <ulong, Guid> channelMapping = new Dictionary <ulong, Guid>();

            foreach (var channel in channels)
            {
                channelMapping.Add(channel.Id, Guid.NewGuid());
            }

            foreach (var channel in channels)
            {
                Console.WriteLine($"[Snapshot] [{guild.Name}] Performing channel {channel.Name} snapshot",
                                  Color.DarkCyan);

                DiscordChannelSnapshotInfo channelSnapshot = new DiscordChannelSnapshotInfo();
                channelSnapshot.InternalChannelId = channelMapping[channel.Id];
                channelSnapshot.Topic             = channel.Topic;
                channelSnapshot.ChannelName       = channel.Name;
                channelSnapshot.ChannelPosition   = channel.Position;
                channelSnapshot.IsCategory        = channel.Type == ChannelType.Category;
                channelSnapshot.IsText            = channel.Type == ChannelType.Text;
                channelSnapshot.IsVoice           = channel.Type == ChannelType.Voice;

                if (channel.ParentId.HasValue)
                {
                    channelSnapshot.ParentInternalChannelId = channelMapping[channel.ParentId.Value];
                }
                else
                {
                    channelSnapshot.ParentInternalChannelId = null;
                }

                channelSnapshot.ChannelRolesSnapshot = new List <DiscordChannelRoleSnapshotInfo>();

                foreach (var overwrite in channel.PermissionOverwrites)
                {
                    if (overwrite.Type != "role")
                    {
                        continue;
                    }
                    DiscordChannelRoleSnapshotInfo channelRoleSnapshot = new DiscordChannelRoleSnapshotInfo();

                    channelRoleSnapshot.InternalRoleId = rolesMapping[overwrite.Id];
                    channelRoleSnapshot.Allow          = (ulong)overwrite.Allow;
                    channelRoleSnapshot.Deny           = (ulong)overwrite.Deny;

                    channelSnapshot.ChannelRolesSnapshot.Add(channelRoleSnapshot);
                }

                snapshotInfo.ChannelsSnapshot.Add(channelSnapshot);
            }

            snapshotInfo.OwnerId = guild.Owner.Id;
            snapshotInfo.GuildId = guild.Id;
            snapshotInfo.TakenAt = DateTime.Now;

            Console.WriteLine($"[Snapshot] [{guild.Name}] Saving snapshot...", Color.Orange);
            snapshotInfo = await Core.SnapManager.PushSnapshot(snapshotInfo);

            Console.WriteLine($"[Snapshot] [{guild.Name}] Snapshot taken!", Color.Green);

            return(snapshotInfo);
        }
Example #5
0
        public async Task RestoreSnapshot(CommandContext ctx, [Description("The snapshot id to restore")] string snapshotId)
        {
            if (ctx.Guild == null)
            {
                await ctx.RespondAsync($"**This command has to be ran inside a Discord server!**");

                return;
            }


            if (ctx.Guild.Owner.Id != ctx.User.Id)
            {
                await ctx.RespondAsync($"**You must be the owner of this server to run this command!**");

                return;
            }

            if (!Core.Configuration.AllowedUsers.Contains(ctx.User.Id))
            {
                await ctx.RespondAsync($"**You're not allowed to use this bot!**");

                return;
            }

            if (!Guid.TryParse(snapshotId, out Guid snapshotIdGuid))
            {
                await ctx.RespondAsync($"**Invalid snapshot id format!**");

                return;
            }

            DiscordSnapshotInfo snapshotInfo = await Core.SnapManager.LoadSnapshotInfo(ctx.User.Id, snapshotIdGuid);

            if (snapshotInfo == null)
            {
                await ctx.RespondAsync($"**The specified snapshot was not found!**");

                return;
            }

            var guild = await ctx.Client.GetGuildAsync(ctx.Guild.Id);

            Core.DiscordBot.ToggleAutoSnapshot(guild.Id, false);

            foreach (var channel in await guild.GetChannelsAsync())
            {
                await channel.DeleteAsync();
            }


            var roles = guild.Roles.ToList();

            foreach (var role in roles)
            {
                try
                {
                    await guild.DeleteRoleAsync(role);
                }
                catch (Exception)
                {
                }
            }
            int rolesOffset = guild.Roles.Count;

            Dictionary <Guid, DiscordRole> rolesMapping = new Dictionary <Guid, DiscordRole>();

            foreach (var role in snapshotInfo.RolesSnapshot)
            {
                if (role.IsEveryone)
                {
                    rolesMapping.Add(role.InternalRoleId, guild.EveryoneRole);
                    continue;
                }

                var createdRole = await guild.CreateRoleAsync(role.RoleName, (Permissions)role.Permissions, new DiscordColor(role.RoleColor), role.IsSeparated, role.IsMentionable);


                rolesMapping.Add(role.InternalRoleId, createdRole);
            }

            foreach (var role in snapshotInfo.RolesSnapshot)
            {
                var guildRole = rolesMapping[role.InternalRoleId];

                if (role.IsEveryone)
                {
                    await guild.UpdateRoleAsync(guildRole, permissions : (Permissions)role.Permissions, color : new DiscordColor(role.RoleColor), hoist : role.IsSeparated, mentionable : role.IsMentionable);
                }

                try
                {
                    await guild.UpdateRolePositionAsync(guildRole, role.Hierarchy);
                }
                catch (Exception)
                {
                }
            }

            Dictionary <Guid, DiscordChannel> channelsMapping = new Dictionary <Guid, DiscordChannel>();

            foreach (var channel in snapshotInfo.ChannelsSnapshot)
            {
                ChannelType type = ChannelType.Text;

                if (channel.IsCategory)
                {
                    type = ChannelType.Category;
                }
                if (channel.IsText)
                {
                    type = ChannelType.Text;
                }
                if (channel.IsVoice)
                {
                    type = ChannelType.Voice;
                }

                var createdChannel = await guild.CreateChannelAsync(channel.ChannelName, type);

                channelsMapping.Add(channel.InternalChannelId, createdChannel);
            }

            foreach (var channel in snapshotInfo.ChannelsSnapshot)
            {
                if (!channel.ParentInternalChannelId.HasValue)
                {
                    continue;
                }

                var guildChannel       = channelsMapping[channel.InternalChannelId];
                var guildParentChannel = channelsMapping[channel.ParentInternalChannelId.Value];
                await guildChannel.ModifyAsync(parent : guildParentChannel);
            }

            var sortedChannels = snapshotInfo.ChannelsSnapshot;

            sortedChannels.Sort((c, k) =>
            {
                if (c.ChannelPosition < k.ChannelPosition)
                {
                    return(1);
                }
                if (c.ChannelPosition > k.ChannelPosition)
                {
                    return(-1);
                }

                return(0);
            });


            foreach (var channel in sortedChannels)
            {
                var guildChannel = channelsMapping[channel.InternalChannelId];
                foreach (var channelRole in channel.ChannelRolesSnapshot)
                {
                    var guildRole = rolesMapping[channelRole.InternalRoleId];
                    await guildChannel.AddOverwriteAsync(guildRole, (Permissions)channelRole.Allow, (Permissions)channelRole.Deny);
                }

                await guildChannel.ModifyPositionAsync(channel.ChannelPosition);
            }


            Core.DiscordBot.ToggleAutoSnapshot(guild.Id, true);
        }