worked on automod
diff --git a/TODO.json b/TODO.json
index 4637953..90fe168 100644
--- a/TODO.json
+++ b/TODO.json
@@ -1,10 +1,5 @@
 {
     "filters": {
-        "images": {
-            "NSFW": false,
-            "size": false
-        },
-        "malware": false,
         "wordFilter": {
             "enabled": true,
             "words": {
diff --git a/src/commands/settings/filters.ts b/src/commands/settings/filters.ts
deleted file mode 100644
index 7636f91..0000000
--- a/src/commands/settings/filters.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-import type Discord from "discord.js";
-import type { CommandInteraction } from "discord.js";
-import type { SlashCommandSubcommandBuilder } from "discord.js";
-
-const command = (builder: SlashCommandSubcommandBuilder) =>
-    builder.setName("filter").setDescription("Setting for message filters");
-
-const callback = async (_interaction: CommandInteraction): Promise<void> => {
-    console.log("Filters");
-};
-
-const check = (interaction: CommandInteraction, _partial: boolean = false) => {
-    const member = interaction.member as Discord.GuildMember;
-    if (!member.permissions.has("ManageMessages"))
-        return "You must have the *Manage Messages* permission to use this command";
-    return true;
-};
-
-export { command };
-export { callback };
-export { check };
diff --git a/src/commands/settings/filters/_meta.ts b/src/commands/settings/filters/_meta.ts
deleted file mode 100644
index d2aff53..0000000
--- a/src/commands/settings/filters/_meta.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import { group } from "../../../utils/commandRegistration/slashCommandBuilder.js";
-
-const name = "filters";
-const description = "Settings for filters";
-
-const subcommand = await group(name, description, `settings/filters`)
-
-export { name, description, subcommand as command};
diff --git a/src/commands/settings/rolemenu.ts b/src/commands/settings/rolemenu.ts
index 9528183..90b224d 100644
--- a/src/commands/settings/rolemenu.ts
+++ b/src/commands/settings/rolemenu.ts
@@ -364,7 +364,7 @@
                 new ButtonBuilder()
                     .setCustomId("reorder")
                     .setLabel("Reorder Pages")
-                    .setEmoji(getEmojiByName("ICONS.SHUFFLE", "id") as APIMessageComponentEmoji)
+                    .setEmoji(getEmojiByName("ICONS.REORDER", "id") as APIMessageComponentEmoji)
                     .setStyle(ButtonStyle.Secondary)
                     .setDisabled(Object.keys(currentObject).length <= 1),
                 new ButtonBuilder()
diff --git a/src/commands/settings/tracks.ts b/src/commands/settings/tracks.ts
index 782f52f..354a948 100644
--- a/src/commands/settings/tracks.ts
+++ b/src/commands/settings/tracks.ts
@@ -1,4 +1,4 @@
-import { ActionRowBuilder, APIMessageComponentEmoji, ButtonBuilder, ButtonInteraction, ButtonStyle, Collection, CommandInteraction, GuildMember, Message, ModalBuilder, ModalSubmitInteraction, Role, RoleSelectMenuBuilder, RoleSelectMenuInteraction, SlashCommandSubcommandBuilder, StringSelectMenuBuilder, StringSelectMenuInteraction, StringSelectMenuOptionBuilder, TextInputBuilder, TextInputStyle } from "discord.js";
+import { ActionRowBuilder, APIMessageComponentEmoji, ButtonBuilder, ButtonInteraction, ButtonStyle, Collection, CommandInteraction, GuildMember, Message, ModalBuilder, ModalSubmitInteraction, PermissionsBitField, Role, RoleSelectMenuBuilder, RoleSelectMenuInteraction, SlashCommandSubcommandBuilder, StringSelectMenuBuilder, StringSelectMenuInteraction, StringSelectMenuOptionBuilder, TextInputBuilder, TextInputStyle } from "discord.js";
 import client from "../../utils/client.js";
 import createPageIndicator, { createVerticalTrack } from "../../utils/createPageIndicator.js";
 import { LoadingEmbed } from "../../utils/defaults.js";
@@ -7,6 +7,8 @@
 import ellipsis from "../../utils/ellipsis.js";
 import { modalInteractionCollector } from "../../utils/dualCollector.js";
 
+const { renderRole } = client.logger
+
 const command = (builder: SlashCommandSubcommandBuilder) =>
     builder
         .setName("tracks")
@@ -20,6 +22,7 @@
     manageableBy: string[];
 }
 
+
 const editName = async (i: ButtonInteraction, interaction: StringSelectMenuInteraction | ButtonInteraction, m: Message, current?: string) => {
 
     let name = current ?? "";
@@ -134,6 +137,7 @@
 }
 
 const editTrack = async (interaction: ButtonInteraction | StringSelectMenuInteraction, message: Message, roles: Collection<string, Role>, current?: ObjectSchema) => {
+    const isAdmin = (interaction.member!.permissions as PermissionsBitField).has("Administrator");
     if(!current) {
         current = {
             name: "",
@@ -143,40 +147,25 @@
             manageableBy: []
         }
     }
-    const buttons = new ActionRowBuilder<ButtonBuilder>()
-        .addComponents(
-            new ButtonBuilder()
-                .setCustomId("back")
-                .setLabel("Back")
-                .setStyle(ButtonStyle.Secondary)
-                .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji),
-            new ButtonBuilder()
-                .setCustomId("edit")
-                .setLabel("Edit Name")
-                .setStyle(ButtonStyle.Primary)
-                .setEmoji(getEmojiByName("ICONS.EDIT", "id") as APIMessageComponentEmoji),
-            new ButtonBuilder()
-                .setCustomId("reorder")
-                .setLabel("Reorder")
-                .setStyle(ButtonStyle.Primary)
-                .setEmoji(getEmojiByName("ICONS.REORDER", "id") as APIMessageComponentEmoji),
-        );
+
     const roleSelect = new ActionRowBuilder<RoleSelectMenuBuilder>()
         .addComponents(
             new RoleSelectMenuBuilder()
                 .setCustomId("addRole")
                 .setPlaceholder("Select a role to add")
+                .setDisabled(!isAdmin)
         );
     let closed = false;
     do {
         const editableRoles: string[] = current.track.map((r) => {
-            if(!(roles.get(r)!.position >= (interaction.member as GuildMember).roles.highest.position)) return r;
+            if(!(roles.get(r)!.position >= (interaction.member as GuildMember).roles.highest.position)) return roles.get(r)!.name;
         }).filter(v => v !== undefined) as string[];
         const selectMenu = new ActionRowBuilder<StringSelectMenuBuilder>()
             .addComponents(
                 new StringSelectMenuBuilder()
                     .setCustomId("removeRole")
                     .setPlaceholder("Select a role to remove")
+                    .setDisabled(!isAdmin)
                     .addOptions(
                         editableRoles.map((r, i) => {
                             return new StringSelectMenuOptionBuilder()
@@ -185,23 +174,56 @@
                         )
                     )
             );
+        const buttons = new ActionRowBuilder<ButtonBuilder>()
+            .addComponents(
+                new ButtonBuilder()
+                    .setCustomId("back")
+                    .setLabel("Back")
+                    .setStyle(ButtonStyle.Secondary)
+                    .setEmoji(getEmojiByName("CONTROL.LEFT", "id") as APIMessageComponentEmoji),
+                new ButtonBuilder()
+                    .setCustomId("edit")
+                    .setLabel("Edit Name")
+                    .setStyle(ButtonStyle.Primary)
+                    .setEmoji(getEmojiByName("ICONS.EDIT", "id") as APIMessageComponentEmoji),
+                new ButtonBuilder()
+                    .setCustomId("reorder")
+                    .setLabel("Reorder")
+                    .setDisabled(!isAdmin)
+                    .setStyle(ButtonStyle.Primary)
+                    .setEmoji(getEmojiByName("ICONS.REORDER", "id") as APIMessageComponentEmoji),
+                new ButtonBuilder()
+                    .setCustomId("retainPrevious")
+                    .setLabel("Retain Previous")
+                    .setStyle(current.retainPrevious ? ButtonStyle.Success : ButtonStyle.Danger)
+                    .setEmoji(getEmojiByName("CONTROL." + (current.retainPrevious ? "TICK" : "CROSS"), "id") as APIMessageComponentEmoji),
+                new ButtonBuilder()
+                    .setCustomId("nullable")
+                    .setLabel(`Role ${current.nullable ? "Not " : ""}Required`)
+                    .setStyle(current.nullable ? ButtonStyle.Success : ButtonStyle.Danger)
+                    .setEmoji(getEmojiByName("CONTROL." + (current.nullable ? "TICK" : "CROSS"), "id") as APIMessageComponentEmoji)
+        );
+
         let allowed: boolean[] = [];
         for (const role of current.track) {
             const disabled: boolean =
                 roles.get(role)!.position >= (interaction.member as GuildMember).roles.highest.position;
             allowed.push(disabled)
         }
+        const mapped = current.track.map(role => roles.find(aRole => aRole.id === role)!);
 
         const embed = new EmojiEmbed()
             .setTitle("Tracks")
             .setDescription(
                 `**Currently Editing:** ${current.name}\n\n` +
-                `${getEmojiByName} Members ${current.nullable ? "don't " : ""}need a role in this track` +
-                `${getEmojiByName} Members ${current.retainPrevious ? "don't " : ""}keep all roles below their current highest` +
-                createVerticalTrack(current.track, new Array(current.track.length).fill(false), allowed)
+                `${getEmojiByName("CONTROL." + (current.nullable ? "CROSS" : "TICK"))} Members ${current.nullable ? "don't " : ""}need a role in this track\n` +
+                `${getEmojiByName("CONTROL." + (current.retainPrevious ? "TICK" : "CROSS"))} Members ${current.retainPrevious ? "" : "don't "}keep all roles below their current highest\n\n` +
+                createVerticalTrack(
+                    mapped.map(role => renderRole(role)), new Array(current.track.length).fill(false), allowed)
             )
+            .setStatus("Success")
 
-        interaction.editReply({embeds: [embed], components: [buttons, roleSelect, selectMenu]});
+        interaction.editReply({embeds: [embed], components: [roleSelect, selectMenu, buttons]});
 
         let out: ButtonInteraction | RoleSelectMenuInteraction | StringSelectMenuInteraction | null;
 
@@ -227,6 +249,13 @@
                     break;
                 case "reorder":
                     current.track = (await reorderTracks(out, message, roles, current.track))!;
+                    break;
+                case "retainPrevious":
+                    current.retainPrevious = !current.retainPrevious;
+                    break;
+                case "nullable":
+                    current.nullable = !current.nullable;
+                    break;
             }
         } else if (out.isStringSelectMenu()) {
             out.deferUpdate();
@@ -258,8 +287,6 @@
     const config = await client.database.guilds.read(interaction.guild!.id);
     const tracks: ObjectSchema[] = config.tracks;
     const roles = await interaction.guild!.roles.fetch();
-    const memberRoles = interaction.member!.roles;
-    const member = interaction.member as GuildMember;
 
     let page = 0;
     let closed = false;
@@ -329,10 +356,11 @@
         } else {
             page = Math.min(page, Object.keys(tracks).length - 1);
             current = tracks[page]!;
+            const mapped = current.track.map(role => roles.find(aRole => aRole.id === role)!);
             embed.setDescription(`**Currently Editing:** ${current.name}\n\n` +
                 `${getEmojiByName("CONTROL." + (current.nullable ? "CROSS" : "TICK"))} Members ${current.nullable ? "don't " : ""}need a role in this track\n` +
                 `${getEmojiByName("CONTROL." + (current.retainPrevious ? "TICK" : "CROSS"))} Members ${current.retainPrevious ? "" : "don't "}keep all roles below their current highest\n\n` +
-                createVerticalTrack(current.track, new Array(current.track.length).fill(false)) +
+                createVerticalTrack(mapped.map(role => renderRole(role)), new Array(current.track.length).fill(false)) +
                 `\n${createPageIndicator(config.tracks.length, page)}`
             );
 
@@ -372,7 +400,7 @@
                     page = tracks.length - 1;
                     break;
                 case "save":
-                    // client.database.guilds.write(interaction.guild!.id, {"roleMenu.options": tracks});  // TODO
+                    client.database.guilds.write(interaction.guild!.id, {tracks: tracks});
                     modified = false;
                     break;
             }
diff --git a/src/config/default.json b/src/config/default.json
index 8e4197c..9129765 100644
--- a/src/config/default.json
+++ b/src/config/default.json
@@ -15,12 +15,17 @@
             "words": {
                 "strict": [],
                 "loose": []
+            },
+            "allowed": {
+                "user": [],
+                "roles": [],
+                "channels": []
             }
         },
         "invite": {
             "enabled": false,
             "allowed": {
-                "users": [],
+                "user": [],
                 "roles": [],
                 "channels": []
             }
@@ -28,7 +33,13 @@
         "pings": {
             "mass": 5,
             "everyone": true,
-            "roles": true
+            "roles": true,
+            "allowed": {
+                "user": [],
+                "roles": [],
+                "channels": [],
+                "rolesToMention": []
+            }
         }
     },
     "welcome": {
diff --git a/src/config/emojis.json b/src/config/emojis.json
index abeb52a..9ccb9fa 100644
--- a/src/config/emojis.json
+++ b/src/config/emojis.json
@@ -25,7 +25,7 @@
         "ATTACHMENT": "997570687193587812",
         "LOGGING": "999613304446144562",
         "SAVE": "1065722246322200586",
-        "SHUFFLE": "1069323453909454890",
+        "REORDER": "1069323453909454890",
         "NOTIFY": {
             "ON": "1000726394579464232",
             "OFF": "1000726363495477368"
diff --git a/src/events/messageDelete.ts b/src/events/messageDelete.ts
index f8433fc..9563a33 100644
--- a/src/events/messageDelete.ts
+++ b/src/events/messageDelete.ts
@@ -4,61 +4,58 @@
 export const event = "messageDelete";
 
 export async function callback(client: NucleusClient, message: Message) {
-    try {
-        if (message.author.id === client.user!.id) return;
-        if (client.noLog.includes(`${message.id}/${message.channel.id}/${message.id}`)) return;
-        const { getAuditLog, log, NucleusColors, entry, renderUser, renderDelta, renderChannel } = client.logger;
-        const auditLog = (await getAuditLog(message.guild!, AuditLogEvent.MemberBanAdd))
-            .filter((entry: GuildAuditLogsEntry) => (entry.target! as User).id === message.author.id)[0];
-        if (auditLog) {
-            if (auditLog.createdTimestamp - 1000 < new Date().getTime()) return;
-        }
-        const replyTo = message.reference;
-        let content = message.cleanContent;
-        content.replace("`", "\\`");
-        if (content.length > 256) content = content.substring(0, 253) + "...";
-        const attachments =
-            message.attachments.size + (
-                message.content.match(
-                    /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/gi
-                ) ?? []
-            ).length;
-        let attachmentJump = "";
-        const config = (await client.database.guilds.read(message.guild!.id)).logging.attachments.saved[
-            message.channel.id + message.id
-        ];
-        if (config) { attachmentJump = ` [[View attachments]](${config})`; }
-        const data = {
-            meta: {
-                type: "messageDelete",
-                displayName: "Message Deleted",
-                calculateType: "messageDelete",
-                color: NucleusColors.red,
-                emoji: "MESSAGE.DELETE",
-                timestamp: new Date().getTime()
-            },
-            separate: {
-                start: content ? `**Message:**\n\`\`\`${content}\`\`\`` : "**Message:** *Message had no content*"
-            },
-            list: {
-                messageId: entry(message.id, `\`${message.id}\``),
-                sentBy: entry(message.author.id, renderUser(message.author)),
-                sentIn: entry(message.channel.id, renderChannel(message.channel as Discord.GuildChannel | Discord.ThreadChannel)),
-                deleted: entry(new Date().getTime(), renderDelta(new Date().getTime())),
-                mentions: message.mentions.users.size,
-                attachments: entry(attachments, attachments + attachmentJump),
-                repliedTo: entry(
-                    replyTo ? replyTo.messageId! : null,
-                    replyTo ? `[[Jump to message]](https://discord.com/channels/${message.guild!.id}/${message.channel.id}/${replyTo.messageId})`
-                            : "None"
-                )
-            },
-            hidden: {
-                guild: message.guild!.id
-            }
-        };
-        log(data);
-    } catch (e) {
-        console.log(e);
+    if (message.author.id === client.user!.id) return;
+    if (message.author.bot) return;
+    if (client.noLog.includes(`${message.id}/${message.channel.id}/${message.id}`)) return;
+    const { getAuditLog, log, NucleusColors, entry, renderUser, renderDelta, renderChannel } = client.logger;
+    const auditLog = (await getAuditLog(message.guild!, AuditLogEvent.MemberBanAdd))
+        .filter((entry: GuildAuditLogsEntry) => (entry.target! as User).id === message.author.id)[0];
+    if (auditLog) {
+        if (auditLog.createdTimestamp - 1000 < new Date().getTime()) return;
     }
+    const replyTo = message.reference;
+    let content = message.cleanContent;
+    content.replace("`", "\\`");
+    if (content.length > 256) content = content.substring(0, 253) + "...";
+    const attachments =
+        message.attachments.size + (
+            message.content.match(
+                /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/gi
+            ) ?? []
+        ).length;
+    let attachmentJump = "";
+    const config = (await client.database.guilds.read(message.guild!.id)).logging.attachments.saved[
+        message.channel.id + message.id
+    ];
+    if (config) { attachmentJump = ` [[View attachments]](${config})`; }
+    const data = {
+        meta: {
+            type: "messageDelete",
+            displayName: "Message Deleted",
+            calculateType: "messageDelete",
+            color: NucleusColors.red,
+            emoji: "MESSAGE.DELETE",
+            timestamp: new Date().getTime()
+        },
+        separate: {
+            start: content ? `**Message:**\n\`\`\`${content}\`\`\`` : "**Message:** *Message had no content*"
+        },
+        list: {
+            messageId: entry(message.id, `\`${message.id}\``),
+            sentBy: entry(message.author.id, renderUser(message.author)),
+            sentIn: entry(message.channel.id, renderChannel(message.channel as Discord.GuildChannel | Discord.ThreadChannel)),
+            deleted: entry(new Date().getTime(), renderDelta(new Date().getTime())),
+            mentions: message.mentions.users.size,
+            attachments: entry(attachments, attachments + attachmentJump),
+            repliedTo: entry(
+                replyTo ? replyTo.messageId! : null,
+                replyTo ? `[[Jump to message]](https://discord.com/channels/${message.guild!.id}/${message.channel.id}/${replyTo.messageId})`
+                        : "None"
+            )
+        },
+        hidden: {
+            guild: message.guild!.id
+        }
+    };
+    log(data);
 }
diff --git a/src/events/messageEdit.ts b/src/events/messageEdit.ts
index caa00f6..d491641 100644
--- a/src/events/messageEdit.ts
+++ b/src/events/messageEdit.ts
@@ -6,6 +6,7 @@
 
 export async function callback(client: NucleusClient, oldMessage: Message, newMessage: Message) {
     if (newMessage.author.id === client.user!.id) return;
+    if (newMessage.author.bot) return;
     if (!newMessage.guild) return;
     const { log, NucleusColors, entry, renderUser, renderDelta, renderNumberDelta, renderChannel } = client.logger;
     const replyTo: MessageReference | null = newMessage.reference;
diff --git a/src/index.ts b/src/index.ts
index 306811e..a3a8d38 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -19,4 +19,4 @@
 
 await client.login(config.enableDevelopment ? config.developmentToken : config.token)
 
-await recordPerformance();
\ No newline at end of file
+await recordPerformance();
diff --git a/src/premium/attachmentLogs.ts b/src/premium/attachmentLogs.ts
index 628c2ec..078587e 100644
--- a/src/premium/attachmentLogs.ts
+++ b/src/premium/attachmentLogs.ts
@@ -13,7 +13,7 @@
     const attachments = [];
     for (const attachment of message.attachments.values()) {
         attachments.push({
-            local: await saveAttachment(attachment.url),
+            local: (await saveAttachment(attachment.url))[0],
             url: attachment.url,
             height: attachment.height,
             width: attachment.width,
@@ -24,7 +24,7 @@
     for (const link of links) {
         if (link.toLowerCase().match(/\.(jpg|jpeg|png|gif|gifv|webm|webp|mp4|wav|mp3|ogg)$/gi)) {
             attachments.push({
-                local: await saveAttachment(link),
+                local: (await saveAttachment(link))[0],
                 url: link,
                 height: null,
                 width: null
@@ -70,7 +70,6 @@
             ],
             files: attachments.map((file) => file.local)
         });
-        // await client.database.guilds.write(interaction.guild.id, {[`tags.${name}`]: value});
         client.database.guilds.write(message.guild.id, {
             [`logging.attachments.saved.${message.channel.id}${message.id}`]: m.url
         });