resetting linux lol
diff --git a/COPYING.md b/COPYING.md
index 2a301ce..ceffdf6 100644
--- a/COPYING.md
+++ b/COPYING.md
@@ -1,6 +1,6 @@
 # Nucleus by Clicks
 
-## TLDR:
+## In Short:
 
 You **may**:
 - Modify our code
@@ -13,7 +13,29 @@
 - Mention the code is originally by Clicks, and include a link to our [website](https://clicks.codes) or [GitHub](https://github.com/clicksminuteper)
 - Release your project with the same license [GNU Affero General Public License V3.0](https://choosealicense.com/licenses/agpl-3.0/)
 
-## The legal bit
+
+## How to:
+
+We hide the config file with our important data like the bot token. Below you can find a copy of `src/config/main.json`.
+
+```json
+{
+    "token": "your-token-here",
+    "developmentToken": "dev-token-here",
+    "managementGuildID": "your-management-guild-id-here",
+    "developmentGuildID": "your-development-guild-id-here",
+    "enableDevelopment": true,
+    "owners": [
+      "your-discord-id",
+    ],
+    "verifySecret": "if making a verify command, this is the value that checks if requests are from the website",
+    "mongoUrl": "mongodb://your-mongo-ip-and-port",
+    "baseUrl": "your website url, e.g. https://clicks.codes",
+}
+```
+
+
+## The legal bit:
 
 ```
                     GNU AFFERO GENERAL PUBLIC LICENSE
diff --git a/TODO.json b/TODO.json
new file mode 100644
index 0000000..b4b2524
--- /dev/null
+++ b/TODO.json
@@ -0,0 +1,94 @@
+{
+  "filters": {
+    "images": {
+      "NSFW": false,
+      "size": false
+    },
+    "malware": false,
+    "wordFilter": {
+      "enabled": false,
+      "words": {
+        "strict": [],
+        "loose": []
+      },
+      "allowed": {
+        "users": [],
+        "roles": [],
+        "channels": []
+      }
+    },
+    "invite": {
+      "enabled": false,
+      "allowed": {
+        "users": [],
+        "channels": [],
+        "roles": []
+      }
+    },
+    "pings": {
+      "mass": 5,
+      "everyone": true,
+      "roles": true,
+      "allowed": {
+        "roles": [],
+        "rolesToMention": [],
+        "users": [],
+        "channels": []
+      }
+    }
+  },
+  "welcome": {
+    "enabled": false,
+    "welcomeRole": null,
+    "channel": null,
+    "message": null
+  },
+  "stats": [
+    {
+      "enabled": true,
+      "channel": "9849175359",
+      "text": "{count} members | {count:bots} bots | {count:humans} humans"
+    }
+  ],
+  "moderation": {
+    "mute": {
+      "timeout": true,
+      "role": null,
+      "text": null,
+      "link": null
+    },
+    "kick": {
+      "text": null,
+      "link": null
+    },
+    "ban": {
+      "text": null,
+      "link": null
+    },
+    "softban": {
+      "text": null,
+      "link": null
+    },
+    "warn": {
+      "text": null,
+      "link": null
+    },
+    "role": {
+      "role": null
+    }
+  },
+  "tracks": [
+  ],
+  "logging": {
+    "logs": {
+      "enabled": true,
+      "toLog": "3fffff"
+    }
+  },
+  "roleMenu": {
+    "enabled": true,
+    "allowWebUI": true,
+    "options": [
+    ]
+  }
+}
\ No newline at end of file
diff --git a/src/api/index.ts b/src/api/index.ts
index 00c866d..b2edc66 100644
--- a/src/api/index.ts
+++ b/src/api/index.ts
@@ -18,7 +18,6 @@
     app.post('/verify/:code', jsonParser, async function (req, res) {
         const code = req.params.code;
         const secret = req.body.secret;
-        const { log, NucleusColors, entry, renderUser } = client.logger
         if (secret === client.config.verifySecret) {
             let guild = await client.guilds.fetch(client.verify[code].gID);
             if (!guild) { return res.status(404) }
@@ -36,6 +35,8 @@
                     .setEmoji("MEMBER.JOIN")
                 ], components: []});
             }
+            delete client.verify[code];
+            const { log, NucleusColors, entry, renderUser } = client.logger
             try {
                 let data = {
                     meta:{
@@ -47,7 +48,7 @@
                         timestamp: new Date().getTime()
                     },
                     list: {
-                        id: entry(member.id, `\`${member.id}\``),
+                        memberId: entry(member.id, `\`${member.id}\``),
                         member: entry(member.id, renderUser(member))
                     },
                     hidden: {
@@ -62,25 +63,20 @@
         }
     });
 
-    app.patch('/verify/:code', (req, res) => {
-        const code = req.params.code;
-        try {
-            let interaction = client.verify[code].interaction;
-            if (interaction) {
-                interaction.editReply({embeds: [new EmojiEmbed()
-                    .setTitle("Verify")
-                    .setDescription(`Verify was opened in another tab or window, please complete the CAPTCHA there to continue`)
-                    .setStatus("Success")
-                    .setEmoji("MEMBER.JOIN")
-                ]});
-            }
-        } catch {}
-        res.sendStatus(200);
-    })
-
     app.get('/verify/:code', jsonParser, function (req, res) {
         const code = req.params.code;
         if (client.verify[code]) {
+            try {
+                let interaction = client.verify[code].interaction;
+                if (interaction) {
+                    interaction.editReply({embeds: [new EmojiEmbed()
+                        .setTitle("Verify")
+                        .setDescription(`Verify was opened in another tab or window, please complete the CAPTCHA there to continue`)
+                        .setStatus("Success")
+                        .setEmoji("MEMBER.JOIN")
+                    ]});
+                }
+            } catch {}
             let data = structuredClone(client.verify[code])
             delete data.interaction;
             return res.status(200).send(data);
@@ -88,6 +84,44 @@
         return res.sendStatus(404);
     })
 
+    app.post('/rolemenu/:code', jsonParser, async function (req, res) {
+        const code = req.params.code;
+        const secret = req.body.secret;
+        const data = req.body.data;
+        if (secret === client.config.verifySecret) {
+            console.table(data)
+            let guild = await client.guilds.fetch(client.roleMenu[code].guild); // TODO: do checks here to like max roles because people are fucking annoying and will edit the source :)
+            if (!guild) { return res.status(404) }
+            let member = await guild.members.fetch(client.roleMenu[code].user);
+            if (!member) { return res.status(404) }
+            res.sendStatus(200);
+        } else {
+            res.sendStatus(403);
+        }
+    });
+
+    app.get('/rolemenu/:code', jsonParser, function (req, res) {
+        const code = req.params.code;
+        if (client.roleMenu[code] !== undefined) {
+            try {
+                let interaction = client.roleMenu[code].interaction;
+                if (interaction) {
+                    interaction.editReply({embeds: [new EmojiEmbed()
+                        .setTitle("Roles")
+                        .setDescription(`The role menu was opened in another tab or window, please select your roles there to continue`)
+                        .setStatus("Success")
+                        .setEmoji("GUILD.GREEN")
+                    ], components: []});
+                }
+            } catch {}
+            let data = structuredClone(client.roleMenu[code])
+            delete data.interaction;
+            console.log(data)
+            return res.status(200).send(data);
+        }
+        return res.sendStatus(404);
+    })
+
     app.listen(port);
 }
 
diff --git a/src/automations/createModActionTicket.ts b/src/automations/createModActionTicket.ts
index fad9a62..2ab9a46 100644
--- a/src/automations/createModActionTicket.ts
+++ b/src/automations/createModActionTicket.ts
@@ -54,7 +54,7 @@
                 `Ticket created by a Moderator\n` +
                 `**Support type:** Appeal submission\n` + (reason != null ? `**Reason:**\n> ${reason}\n` : "") +
                 `**Ticket ID:** \`${c.id}\`\n` +
-                `Type \`/ticket close\` to archive this ticket.`,
+                `Type \`/ticket close\` to close this ticket.`,
             )
             .setStatus("Success")
             .setEmoji("GUILD.TICKET.OPEN")
diff --git a/src/automations/guide.ts b/src/automations/guide.ts
index 8e0e6cd..655d781 100644
--- a/src/automations/guide.ts
+++ b/src/automations/guide.ts
@@ -37,8 +37,9 @@
                     "Nucleus can log server events and keep you informed with what content is being posted to your server.\n" +
                     "We have 2 different types of logs, which each can be configured to send to a channel of your choice:\n" +
                     "**General Logs:** These are events like kicks and channel changes etc.\n" +
-                    "**Warning Logs:** Warnings like NSFW avatars and spam etc that may require action by a server staff member.\n\n" +
-                    "A general log channel can be set with `/settings log channel`\n" +
+                    "**Warning Logs:** Warnings like NSFW avatars and spam etc. that may require action by a server staff member. " +
+                    "These go to to a separate staff notifications channel.\n\n" +
+                    "A general log channel can be set with `/settings log`\n" +
                     "A warning log channel can be set with `/settings warnings channel`"
                 )
                 .setEmoji("NUCLEUS.LOGO")
@@ -69,7 +70,7 @@
                     "Nucleus has a verification system that allows users to prove they aren't bots.\n" +
                     "This is done by running `/verify` which sends a message only the user can see, giving them a link to a CAPTCHA to verify.\n" +
                     "After the user complete's the CAPTCHA, they are given a role and can use the permissions accordingly.\n" +
-                    "You can set the role given with `/settings verify role`"
+                    "You can set the role given with `/settings verify`"
                 )
                 .setEmoji("NUCLEUS.LOGO")
                 .setStatus("Danger")
@@ -80,7 +81,7 @@
                 .setDescription(
                     "Nucleus has a content scanning system that automatically scans links and images sent by users.\n" +
                     "Nucleus can detect, delete, and punish users for sending NSFW content, or links to scam or adult sites.\n" +
-                    "You can set the threshold for this in `/settings automation`"
+                    "You can set the threshold for this in `/settings automation`" // TODO
                 )
                 .setEmoji("NUCLEUS.LOGO")
                 .setStatus("Danger")
@@ -91,7 +92,7 @@
                 .setDescription(
                     "Nucleus has a ticket system that allows users to create tickets and have a support team respond to them.\n" +
                     "Tickets can be created with `/ticket create` and a channel is created, pinging the user and support role.\n" +
-                    "When the ticket is resolved, anyone can run `/ticket close` to archive it.\n" +
+                    "When the ticket is resolved, anyone can run `/ticket close` (or click the button) to close it.\n" +
                     "Running `/ticket close` again will delete the ticket."
                 )
                 .setEmoji("NUCLEUS.LOGO")
diff --git a/src/automations/roleMenu.ts b/src/automations/roleMenu.ts
index e82c82c..318a0dd 100644
--- a/src/automations/roleMenu.ts
+++ b/src/automations/roleMenu.ts
@@ -44,8 +44,11 @@
         }
         client.roleMenu[code] = {
             guild: interaction.guild.id,
+            guildName: interaction.guild.name,
             guildIcon: interaction.guild.iconURL({format: "png"}),
             user: interaction.member.user.id,
+            username: interaction.member.user.username,
+            data: config.roleMenu.options,
             interaction: interaction
         };
         m = await interaction.editReply({
@@ -58,7 +61,8 @@
                 new MessageButton()
                     .setLabel("Online")
                     .setStyle("LINK")
-                    .setURL(`https://clicks.codes/nuclues/rolemenu?code=${code}`),
+                    .setDisabled(false) // TODO check if the server is up
+                    .setURL(`${client.config.baseUrl}/nucleus/rolemenu?code=${code}`),
                 new MessageButton()
                     .setLabel("Manual")
                     .setStyle("PRIMARY")
diff --git a/src/automations/tickets/create.ts b/src/automations/tickets/create.ts
index 8eee3b2..8d58493 100644
--- a/src/automations/tickets/create.ts
+++ b/src/automations/tickets/create.ts
@@ -167,7 +167,7 @@
                 `Ticket created by <@${interaction.member.user.id}>\n` +
                 `**Support type:** ${chosenType != null ? (emoji) + " " + capitalize(chosenType) : "General"}\n` +
                 `**Ticket ID:** \`${c.id}\`\n${content}\n` +
-                `Type \`/ticket close\` to archive this ticket.`,
+                `Type \`/ticket close\` to close this ticket.`,
             )
             .setStatus("Success")
             .setEmoji("GUILD.TICKET.OPEN")
diff --git a/src/automations/unscan.ts b/src/automations/unscan.ts
index 940a1fe..d1fa7d4 100644
--- a/src/automations/unscan.ts
+++ b/src/automations/unscan.ts
@@ -12,9 +12,7 @@
         } catch {}
         detections.push({tags: element.tags || [], safe: element.safe})
     });
-    console.log(1)
     await Promise.all(promises);
-    console.log(2)
     let types = [
         "PHISHING",  "DATING",            "TRACKERS",    "ADVERTISEMENTS", "FACEBOOK",
         "AMP",       "FACEBOOK TRACKERS", "IP GRABBERS", "PORN",
@@ -27,7 +25,6 @@
         // if (!element.safe) return "UNSAFE"
         return undefined
     }).filter(element => element !== undefined)
-    console.log(detectionsTypes)
     return detectionsTypes.length > 0
 }
 
@@ -56,22 +53,22 @@
     }
 }
 
-export function TestString(string, soft, strict): string {
+export function TestString(string, soft, strict): object | null {
     for(let word of strict || []) {
         if (string.toLowerCase().includes(word)) {
-            return "strict"
+            return {word: word, type: "strict"}
         }
     }
     for(let word of soft) {
         for(let word2 of string.match(/[a-z]+/gi) || []) {
             if (word2 == word) {
-                return "loose"
+                return {word: word, type: "strict"}
             }
         }
     }
-    return "none"
+    return null
 }
 
-export async function TestImage(element): Promise<string> {
-    return "";
+export async function TestImage(element): Promise<string | null> {
+    return null;
 }
diff --git a/src/automations/verify.ts b/src/automations/verify.ts
index ed24d25..710439a 100644
--- a/src/automations/verify.ts
+++ b/src/automations/verify.ts
@@ -88,7 +88,7 @@
             .setStatus("Warning")
             .setEmoji("NUCLEUS.LOADING")
         ]});
-        if (TestString((interaction.member as Discord.GuildMember).displayName, config.filters.wordFilter.words.loose, config.filters.wordFilter.words.strict) != "none") {
+        if (TestString((interaction.member as Discord.GuildMember).displayName, config.filters.wordFilter.words.loose, config.filters.wordFilter.words.strict) !== null) {
             return await interaction.editReply({embeds: [new EmojiEmbed()
                 .setTitle("Verify")
                 .setDescription(`Your name contained a word we do not allow in this server.\nPlease contact one of our staff members if you believe this is a mistake` + step(2))
@@ -124,7 +124,7 @@
         gID: interaction.guild.id,
         rID: config.verify.role,
         rName: (await interaction.guild.roles.fetch(config.verify.role)).name,
-        mCount: interaction.guild.memberCount,
+        uName: interaction.member.user.username,
         gName: interaction.guild.name,
         gIcon: interaction.guild.iconURL({format: "png"}),
         interaction: interaction
diff --git a/src/commands/mod/ban.ts b/src/commands/mod/ban.ts
index 4581c0f..11c6c79 100644
--- a/src/commands/mod/ban.ts
+++ b/src/commands/mod/ban.ts
@@ -75,7 +75,7 @@
                     timestamp: new Date().getTime()
                 },
                 list: {
-                    id: entry(member.user.id, `\`${member.user.id}\``),
+                    memberId: entry(member.user.id, `\`${member.user.id}\``),
                     name: entry(member.user.id, renderUser(member.user)),
                     banned: entry(new Date().getTime(), renderDelta(new Date().getTime())),
                     bannedBy: entry(interaction.user.id, renderUser(interaction.user)),
diff --git a/src/commands/mod/kick.ts b/src/commands/mod/kick.ts
index 97ead7b..b1464ee 100644
--- a/src/commands/mod/kick.ts
+++ b/src/commands/mod/kick.ts
@@ -71,7 +71,7 @@
                     timestamp: new Date().getTime()
                 },
                 list: {
-                    id: entry(member.id, `\`${member.id}\``),
+                    memberId: entry(member.id, `\`${member.id}\``),
                     name: entry(member.id, renderUser(member.user)),
                     joined: entry(member.joinedAt, renderDelta(member.joinedAt)),
                     kicked: entry(new Date().getTime(), renderDelta(new Date().getTime())),
diff --git a/src/commands/mod/mute.ts b/src/commands/mod/mute.ts
index 5f42b27..4c326e7 100644
--- a/src/commands/mod/mute.ts
+++ b/src/commands/mod/mute.ts
@@ -163,7 +163,7 @@
             }
             if (config.moderation.mute.role) {
                 member.roles.add(config.moderation.mute.role)
-            }
+            } // make sure this gets removed
         } catch {
             await interaction.editReply({embeds: [new EmojiEmbed()
                 .setEmoji("PUNISH.MUTE.RED")
diff --git a/src/commands/mod/nick.ts b/src/commands/mod/nick.ts
index e154277..8dcbf62 100644
--- a/src/commands/mod/nick.ts
+++ b/src/commands/mod/nick.ts
@@ -73,7 +73,7 @@
                     timestamp: new Date().getTime()
                 },
                 list: {
-                    id: entry(member.id, `\`${member.id}\``),
+                    memberId: entry(member.id, `\`${member.id}\``),
                     before: entry(before, before ? before : '*None*'),
                     after: entry(nickname, nickname ? nickname : '*None*'),
                     updated: entry(new Date().getTime(), renderDelta(new Date().getTime())),
diff --git a/src/commands/mod/purge.ts b/src/commands/mod/purge.ts
index 9aab260..fd8e6b8 100644
--- a/src/commands/mod/purge.ts
+++ b/src/commands/mod/purge.ts
@@ -144,7 +144,7 @@
                     timestamp: new Date().getTime()
                 },
                 list: {
-                    id: entry(interaction.user.id, `\`${interaction.user.id}\``),
+                    memberId: entry(interaction.user.id, `\`${interaction.user.id}\``),
                     purgedBy: entry(interaction.user.id, renderUser(interaction.user)),
                     channel: entry(interaction.channel.id, renderChannel(interaction.channel)),
                     messagesCleared: entry(deleted.length, deleted.length),
@@ -246,7 +246,7 @@
                         timestamp: new Date().getTime()
                     },
                     list: {
-                        id: entry(interaction.user.id, `\`${interaction.user.id}\``),
+                        memberId: entry(interaction.user.id, `\`${interaction.user.id}\``),
                         purgedBy: entry(interaction.user.id, renderUser(interaction.user)),
                         channel: entry(interaction.channel.id, renderChannel(interaction.channel)),
                         messagesCleared: entry(messages.size, messages.size),
diff --git a/src/commands/mod/unban.ts b/src/commands/mod/unban.ts
index 7f605d9..e512084 100644
--- a/src/commands/mod/unban.ts
+++ b/src/commands/mod/unban.ts
@@ -53,7 +53,7 @@
                     timestamp: new Date().getTime()
                 },
                 list: {
-                    id: entry(member.id, `\`${member.id}\``),
+                    memberId: entry(member.id, `\`${member.id}\``),
                     name: entry(member.id, renderUser(member)),
                     unbanned: entry(new Date().getTime(), renderDelta(new Date().getTime())),
                     unbannedBy: entry(interaction.user.id, renderUser(interaction.user)),
diff --git a/src/commands/mod/viewas.ts b/src/commands/mod/viewas.ts
index b3875a7..684fc3a 100644
--- a/src/commands/mod/viewas.ts
+++ b/src/commands/mod/viewas.ts
@@ -97,7 +97,6 @@
 
 
 const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
-    return true // FIXME FOR RELEASE
     let member = (interaction.member as GuildMember)
     if (! member.permissions.has("MANAGE_ROLES")) throw "You do not have the Manage roles permission";
     return true
diff --git a/src/commands/rolemenu.ts b/src/commands/rolemenu.ts
new file mode 100644
index 0000000..f53e10a
--- /dev/null
+++ b/src/commands/rolemenu.ts
@@ -0,0 +1,20 @@
+import { CommandInteraction } from "discord.js";
+import { SlashCommandBuilder } from "@discordjs/builders";
+import { WrappedCheck } from "jshaiku";
+import { callback as roleMenu } from "../automations/roleMenu.js"
+
+const command = new SlashCommandBuilder()
+    .setName("rolemenu")
+    .setDescription("Lets you choose from sets of roles to apply to yourself")
+
+const callback = async (interaction: CommandInteraction): Promise<any> => {
+    await roleMenu(interaction);
+}
+
+const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
+    return true;
+}
+
+export { command };
+export { callback };
+export { check };
diff --git a/src/commands/settings/logs/channel.ts b/src/commands/settings/logs/channel.ts
index 19a389b..10a5887 100644
--- a/src/commands/settings/logs/channel.ts
+++ b/src/commands/settings/logs/channel.ts
@@ -53,6 +53,28 @@
         if (confirmation.success) {
             try {
                 await client.database.guilds.write(interaction.guild.id, {"logging.logs.channel": channel.id})
+                const { log, NucleusColors, entry, renderUser, renderChannel } = client.logger
+                try {
+                    let data = {
+                        meta:{
+                            type: 'logChannelUpdate',
+                            displayName: 'Log Channel Changed',
+                            calculateType: 'nucleusSettingsUpdated',
+                            color: NucleusColors.yellow,
+                            emoji: "CHANNEL.TEXT.EDIT",
+                            timestamp: new Date().getTime()
+                        },
+                        list: {
+                            memberId: entry(interaction.user.id, `\`${interaction.user.id}\``),
+                            changedBy: entry(interaction.user.id, renderUser(interaction.user)),
+                            channel: entry(channel.id, renderChannel(channel)),
+                        },
+                        hidden: {
+                            guild: channel.guild.id
+                        }
+                    }
+                    log(data);
+                } catch {}
             } catch (e) {
                 console.log(e)
                 return interaction.editReply({embeds: [new EmojiEmbed()
@@ -120,7 +142,7 @@
 
 const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
     let member = (interaction.member as Discord.GuildMember)
-    if (!member.permissions.has("MANAGE_GUILD")) throw "You must have the `manage_server` permission to use this command"
+    if (!member.permissions.has("MANAGE_GUILD")) throw "You must have the Manage Server permission to use this command"
     return true;
 }
 
diff --git a/src/commands/settings/logs/ignore.ts b/src/commands/settings/logs/ignore.ts
index 12af085..3b81d42 100644
--- a/src/commands/settings/logs/ignore.ts
+++ b/src/commands/settings/logs/ignore.ts
@@ -103,14 +103,38 @@
             if (role) data.logging.logs.ignore.roles.concat([role.id])
             if (interaction.options.getString("action") == "add") {
                 await client.database.guilds.append(interaction.guild.id, data)
+            } else {
+                await client.database.guilds.remove(interaction.guild.id, data)
             }
+            const { log, NucleusColors, entry, renderUser, renderChannel } = client.logger
+            try {
+                let data = {
+                    meta:{
+                        type: 'logIgnoreUpdated',
+                        displayName: 'Ignored Groups Changed',
+                        calculateType: 'nucleusSettingsUpdated',
+                        color: NucleusColors.yellow,
+                        emoji: "CHANNEL.TEXT.EDIT",
+                        timestamp: new Date().getTime()
+                    },
+                    list: {
+                        memberId: entry(interaction.user.id, `\`${interaction.user.id}\``),
+                        changedBy: entry(interaction.user.id, renderUser(interaction.user)),
+                        channel: entry(channel.id, renderChannel(channel)),
+                    },
+                    hidden: {
+                        guild: interaction.guild.id
+                    }
+                }
+                log(data);
+            } catch {}
         }
     }
 }
 
 const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
     let member = (interaction.member as Discord.GuildMember)
-    if (!member.permissions.has("MANAGE_GUILD")) throw "You must have the `manage_server` permission to use this command"
+    if (!member.permissions.has("MANAGE_GUILD")) throw "You must have the Manage Server permission to use this command"
     return true;
 }
 
diff --git a/src/commands/settings/rolemenu.ts b/src/commands/settings/rolemenu.ts
new file mode 100644
index 0000000..ec54820
--- /dev/null
+++ b/src/commands/settings/rolemenu.ts
@@ -0,0 +1,26 @@
+import Discord, { CommandInteraction, MessageActionRow, MessageButton } from "discord.js";
+import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
+import confirmationMessage from "../../utils/confirmationMessage.js";
+import getEmojiByName from "../../utils/getEmojiByName.js";
+import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
+import { WrappedCheck } from "jshaiku";
+import client from "../../utils/client.js";
+
+const command = (builder: SlashCommandSubcommandBuilder) =>
+    builder
+    .setName("role")
+    .setDescription("Sets or shows the role given to users after using /verify")
+    .addRoleOption(option => option.setName("role").setDescription("The role to give after verifying"))
+
+const callback = async (interaction: CommandInteraction): Promise<any> => {
+}
+
+const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
+    let member = (interaction.member as Discord.GuildMember)
+    if (!member.permissions.has("MANAGE_ROLES")) throw "You must have the Manage roles permission to use this command"
+    return true;
+}
+
+export { command };
+export { callback };
+export { check };
\ No newline at end of file
diff --git a/src/commands/settings/staff/channel.ts b/src/commands/settings/staff.ts
similarity index 77%
rename from src/commands/settings/staff/channel.ts
rename to src/commands/settings/staff.ts
index 74605cf..e0d2776 100644
--- a/src/commands/settings/staff/channel.ts
+++ b/src/commands/settings/staff.ts
@@ -1,19 +1,19 @@
 import { ChannelType } from 'discord-api-types';
 import Discord, { CommandInteraction, MessageActionRow, MessageButton } from "discord.js";
-import EmojiEmbed from "../../../utils/generateEmojiEmbed.js";
-import confirmationMessage from "../../../utils/confirmationMessage.js";
-import getEmojiByName from "../../../utils/getEmojiByName.js";
+import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
+import confirmationMessage from "../../utils/confirmationMessage.js";
+import getEmojiByName from "../../utils/getEmojiByName.js";
 import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
 import { WrappedCheck } from "jshaiku";
-import client from "../../../utils/client.js";
+import client from "../../utils/client.js";
 
 const command = (builder: SlashCommandSubcommandBuilder) =>
     builder
-    .setName("channel")
-    .setDescription("Sets or shows the staff notifications channel")
+    .setName("staff")
+    .setDescription("Settings for the staff notifications channel")
     .addChannelOption(option => option.setName("channel").setDescription("The channel to set the staff notifications channel to").addChannelTypes([
         ChannelType.GuildNews, ChannelType.GuildText
-    ]))
+    ]).setRequired(false))
 
 const callback = async (interaction: CommandInteraction): Promise<any> => {
     let m;
@@ -56,6 +56,28 @@
         if (confirmation.success) {
             try {
                 await client.database.guilds.write(interaction.guild.id, {"logging.staff.channel": channel.id})
+                const { log, NucleusColors, entry, renderUser, renderChannel } = client.logger
+                try {
+                    let data = {
+                        meta:{
+                            type: 'logIgnoreUpdated',
+                            displayName: 'Staff Notifications Channel Updated',
+                            calculateType: 'nucleusSettingsUpdated',
+                            color: NucleusColors.yellow,
+                            emoji: "CHANNEL.TEXT.EDIT",
+                            timestamp: new Date().getTime()
+                        },
+                        list: {
+                            memberId: entry(interaction.user.id, `\`${interaction.user.id}\``),
+                            changedBy: entry(interaction.user.id, renderUser(interaction.user)),
+                            channel: entry(channel.id, renderChannel(channel)),
+                        },
+                        hidden: {
+                            guild: interaction.guild.id
+                        }
+                    }
+                    log(data);
+                } catch {}
             } catch (e) {
                 return interaction.editReply({embeds: [new EmojiEmbed()
                     .setTitle("Staff Notifications Channel")
@@ -122,7 +144,7 @@
 
 const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
     let member = (interaction.member as Discord.GuildMember)
-    if (!member.permissions.has("MANAGE_GUILD")) throw "You must have the `manage_server` permission to use this command"
+    if (!member.permissions.has("MANAGE_GUILD")) throw "You must have the Manage Server permission to use this command"
     return true;
 }
 
diff --git a/src/commands/settings/staff/_meta.ts b/src/commands/settings/staff/_meta.ts
deleted file mode 100644
index 9c3cd62..0000000
--- a/src/commands/settings/staff/_meta.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-const name = "warnings";
-const description = "Settings for mod warnings";
-
-export { name, description };
\ No newline at end of file
diff --git a/src/commands/settings/tickets.ts b/src/commands/settings/tickets.ts
index b505c5c..e664bd0 100644
--- a/src/commands/settings/tickets.ts
+++ b/src/commands/settings/tickets.ts
@@ -404,7 +404,7 @@
 
 const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
     let member = (interaction.member as Discord.GuildMember)
-    if (!member.permissions.has("MANAGE_GUILD")) throw "You must have the `manage_server` permission to use this command"
+    if (!member.permissions.has("MANAGE_GUILD")) throw "You must have the Manage Server permission to use this command"
     return true;
 }
 
diff --git a/src/commands/settings/verify/role.ts b/src/commands/settings/verify.ts
similarity index 75%
rename from src/commands/settings/verify/role.ts
rename to src/commands/settings/verify.ts
index 44406e9..7a68c64 100644
--- a/src/commands/settings/verify/role.ts
+++ b/src/commands/settings/verify.ts
@@ -1,16 +1,16 @@
 import Discord, { CommandInteraction, MessageActionRow, MessageButton } from "discord.js";
-import EmojiEmbed from "../../../utils/generateEmojiEmbed.js";
-import confirmationMessage from "../../../utils/confirmationMessage.js";
-import getEmojiByName from "../../../utils/getEmojiByName.js";
+import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
+import confirmationMessage from "../../utils/confirmationMessage.js";
+import getEmojiByName from "../../utils/getEmojiByName.js";
 import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
 import { WrappedCheck } from "jshaiku";
-import client from "../../../utils/client.js";
+import client from "../../utils/client.js";
 
 const command = (builder: SlashCommandSubcommandBuilder) =>
     builder
-    .setName("role")
-    .setDescription("Sets or shows the role given to users after using /verify")
-    .addRoleOption(option => option.setName("role").setDescription("The role to give after verifying"))
+    .setName("verify")
+    .setDescription("Manage the role given after typing /verify")
+    .addRoleOption(option => option.setName("role").setDescription("The role to give after verifying").setRequired(false))
 
 const callback = async (interaction: CommandInteraction): Promise<any> => {
     let m;
@@ -50,6 +50,28 @@
         if (confirmation.success) {
             try {
                 await client.database.guilds.write(interaction.guild.id, {"verify.role": role.id, "verify.enabled": true});
+                const { log, NucleusColors, entry, renderUser, renderRole } = client.logger
+                try {
+                    let data = {
+                        meta:{
+                            type: 'verifyRoleChanged',
+                            displayName: 'Ignored Groups Changed',
+                            calculateType: 'nucleusSettingsUpdated',
+                            color: NucleusColors.green,
+                            emoji: "CONTROL.BLOCKTICK",
+                            timestamp: new Date().getTime()
+                        },
+                        list: {
+                            memberId: entry(interaction.user.id, `\`${interaction.user.id}\``),
+                            changedBy: entry(interaction.user.id, renderUser(interaction.user)),
+                            role: entry(role.id, renderRole(role)),
+                        },
+                        hidden: {
+                            guild: interaction.guild.id
+                        }
+                    }
+                    log(data);
+                } catch {}
             } catch (e) {
                 console.log(e)
                 return interaction.editReply({embeds: [new EmojiEmbed()
@@ -117,7 +139,7 @@
 
 const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
     let member = (interaction.member as Discord.GuildMember)
-    if (!member.permissions.has("MANAGE_GUILD")) throw "You must have the `manage_server` permission to use this command"
+    if (!member.permissions.has("MANAGE_GUILD")) throw "You must have the Manage Server permission to use this command"
     return true;
 }
 
diff --git a/src/commands/settings/verify/_meta.ts b/src/commands/settings/verify/_meta.ts
deleted file mode 100644
index 999c50b..0000000
--- a/src/commands/settings/verify/_meta.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-const name = "verify";
-const description = "Settings for verification";
-
-export { name, description };
\ No newline at end of file
diff --git a/src/commands/tags/create.ts b/src/commands/tags/create.ts
index c1ed839..6dbecf4 100644
--- a/src/commands/tags/create.ts
+++ b/src/commands/tags/create.ts
@@ -78,7 +78,7 @@
 
 const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
     let member = (interaction.member as Discord.GuildMember)
-    if (!member.permissions.has("MANAGE_MESSAGES")) throw "You must have the `manage_messages` permission to use this command"
+    if (!member.permissions.has("MANAGE_MESSAGES")) throw "You must have the Manage Messages permission to use this command"
     return true;
 }
 
diff --git a/src/commands/tags/delete.ts b/src/commands/tags/delete.ts
index f24a5fc..2707465 100644
--- a/src/commands/tags/delete.ts
+++ b/src/commands/tags/delete.ts
@@ -60,7 +60,7 @@
 
 const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
     let member = (interaction.member as Discord.GuildMember)
-    if (!member.permissions.has("MANAGE_MESSAGES")) throw "You must have the `manage_messages` permission to use this command"
+    if (!member.permissions.has("MANAGE_MESSAGES")) throw "You must have the Manage Messages permission to use this command"
     return true;
 }
 
diff --git a/src/commands/tags/edit.ts b/src/commands/tags/edit.ts
index b0a4835..77e21ae 100644
--- a/src/commands/tags/edit.ts
+++ b/src/commands/tags/edit.ts
@@ -93,7 +93,7 @@
 
 const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
     let member = (interaction.member as Discord.GuildMember)
-    if (!member.permissions.has("MANAGE_MESSAGES")) throw "You must have the `manage_messages` permission to use this command"
+    if (!member.permissions.has("MANAGE_MESSAGES")) throw "You must have the Manage Messages permission to use this command"
     return true;
 }
 
diff --git a/src/config/emojis.json b/src/config/emojis.json
index f6eabe0..e9fb578 100644
--- a/src/config/emojis.json
+++ b/src/config/emojis.json
@@ -119,6 +119,7 @@
         "DELETE": "752070251948146768"
     },
     "MESSAGE": {
+        "CREATE": "751762088229339136",
         "EDIT": "729065958584614925",
         "DELETE": "729064530432360461",
         "PIN": "729064530755190894",
diff --git a/src/events/channelCreate.ts b/src/events/channelCreate.ts
index 3bde0f2..2d48255 100644
--- a/src/events/channelCreate.ts
+++ b/src/events/channelCreate.ts
@@ -55,7 +55,7 @@
                 timestamp: channel.createdTimestamp
             },
             list: {
-                id: entry(channel.id, `\`${channel.id}\``),
+                channelId: entry(channel.id, `\`${channel.id}\``),
                 name: entry(channel.name, renderChannel(channel)),
                 type: entry(channel.type, readableType),
                 category: entry(channel.parent ? channel.parent.id : null, channel.parent ? channel.parent.name : "Uncategorised"),
diff --git a/src/events/channelDelete.ts b/src/events/channelDelete.ts
index 2188141..5c7139a 100644
--- a/src/events/channelDelete.ts
+++ b/src/events/channelDelete.ts
@@ -39,7 +39,7 @@
             }
         }
         let list = {
-            id: entry(channel.id, `\`${channel.id}\``),
+            channelIid: entry(channel.id, `\`${channel.id}\``),
             name: entry(channel.id, `${channel.name}`),
             topic: null,
             type: entry(channel.type, readableType),
diff --git a/src/events/channelUpdate.ts b/src/events/channelUpdate.ts
index 560ca11..50a3de1 100644
--- a/src/events/channelUpdate.ts
+++ b/src/events/channelUpdate.ts
@@ -18,7 +18,7 @@
         let readableType:string;
         let displayName:string ;
         let changes = {
-            id: entry(nc.id, `\`${nc.id}\``),
+            channelId: entry(nc.id, `\`${nc.id}\``),
             channel: entry(nc.id, renderChannel(nc)),
             edited: entry(new Date().getTime(), renderDelta(new Date().getTime())),
             editedBy: entry(audit.executor.id, renderUser((await nc.guild.members.fetch(audit.executor.id)).user)),
diff --git a/src/events/emojiCreate.ts b/src/events/emojiCreate.ts
index 1048869..25d1b62 100644
--- a/src/events/emojiCreate.ts
+++ b/src/events/emojiCreate.ts
@@ -16,7 +16,7 @@
                 timestamp: emoji.createdTimestamp
             },
             list: {
-                id: entry(emoji.id, `\`${emoji.id}\``),
+                emojiId: entry(emoji.id, `\`${emoji.id}\``),
                 emoji: entry(emoji.name, renderEmoji(emoji)),
                 createdBy: entry(audit.executor.id, renderUser(audit.executor)),
                 created: entry(emoji.createdTimestamp, renderDelta(emoji.createdTimestamp))
diff --git a/src/events/emojiDelete.ts b/src/events/emojiDelete.ts
index 02bec0d..2dcb685 100644
--- a/src/events/emojiDelete.ts
+++ b/src/events/emojiDelete.ts
@@ -16,7 +16,7 @@
                 timestamp: audit.createdTimestamp,
             },
             list: {
-                id: entry(emoji.id, `\`${emoji.id}\``),
+                emojiId: entry(emoji.id, `\`${emoji.id}\``),
                 emoji: entry(emoji.name, renderEmoji(emoji)),
                 deletedBy: entry(audit.executor.id, renderUser(audit.executor)),
                 created: entry(emoji.createdTimestamp, renderDelta(emoji.createdTimestamp)),
diff --git a/src/events/emojiUpdate.ts b/src/events/emojiUpdate.ts
index eb39cb9..79fb171 100644
--- a/src/events/emojiUpdate.ts
+++ b/src/events/emojiUpdate.ts
@@ -12,7 +12,7 @@
         if (audit.executor.id == client.user.id) return;
 
         let changes = {
-            id: entry(ne.id, `\`${ne.id}\``),
+            emojiId: entry(ne.id, `\`${ne.id}\``),
             emoji: entry(ne.id, renderEmoji(ne)),
             edited: entry(ne.createdTimestamp, renderDelta(ne.createdTimestamp)),
             editedBy: entry(audit.executor.id, renderUser((await ne.guild.members.fetch(audit.executor.id)).user)),
diff --git a/src/events/guildBanAdd.ts b/src/events/guildBanAdd.ts
index a1848fd..05b98ed 100644
--- a/src/events/guildBanAdd.ts
+++ b/src/events/guildBanAdd.ts
@@ -22,7 +22,7 @@
                 timestamp: new Date().getTime()
             },
             list: {
-                id: entry(ban.user.id, `\`${ban.user.id}\``),
+                memberId: entry(ban.user.id, `\`${ban.user.id}\``),
                 name: entry(ban.user.id, renderUser(ban.user)),
                 banned: entry(new Date().getTime(), renderDelta(new Date().getTime())),
                 bannedBy: entry(audit.executor.id, renderUser(audit.executor)),
diff --git a/src/events/guildBanRemove.ts b/src/events/guildBanRemove.ts
index 59fbf7a..85dc2af 100644
--- a/src/events/guildBanRemove.ts
+++ b/src/events/guildBanRemove.ts
@@ -23,7 +23,7 @@
                 timestamp: new Date().getTime()
             },
             list: {
-                id: entry(ban.user.id, `\`${ban.user.id}\``),
+                memberId: entry(ban.user.id, `\`${ban.user.id}\``),
                 name: entry(ban.user.id, renderUser(ban.user)),
                 unbanned: entry(new Date().getTime(), renderDelta(new Date().getTime())),
                 unbannedBy: entry(audit.executor.id, renderUser(audit.executor)),
diff --git a/src/events/guildMemberUpdate.ts b/src/events/guildMemberUpdate.ts
index 2175aaf..dab89fa 100644
--- a/src/events/guildMemberUpdate.ts
+++ b/src/events/guildMemberUpdate.ts
@@ -23,7 +23,7 @@
                     timestamp: new Date().getTime()
                 },
                 list: {
-                    id: entry(after.id, `\`${after.id}\``),
+                    memberId: entry(after.id, `\`${after.id}\``),
                     before: entry(before.nickname, before.nickname ? before.nickname : '*None*'),
                     after: entry(after.nickname, after.nickname ? after.nickname : '*None*'),
                     updated: entry(new Date().getTime(), renderDelta(new Date().getTime())),
diff --git a/src/events/memberJoin.ts b/src/events/memberJoin.ts
index f3c4d18..2031b12 100644
--- a/src/events/memberJoin.ts
+++ b/src/events/memberJoin.ts
@@ -21,7 +21,7 @@
                 timestamp: member.joinedTimestamp
             },
             list: {
-                id: entry(member.id, `\`${member.id}\``),
+                memberId: entry(member.id, `\`${member.id}\``),
                 name: entry(member.id, renderUser(member.user)),
                 joined: entry(member.joinedAt, renderDelta(member.joinedAt)),
                 accountCreated: entry(member.user.createdAt, renderDelta(member.user.createdAt)),
diff --git a/src/events/memberLeave.ts b/src/events/memberLeave.ts
index 43e78bd..b9d6e84 100644
--- a/src/events/memberLeave.ts
+++ b/src/events/memberLeave.ts
@@ -31,7 +31,7 @@
                     timestamp: new Date().getTime()
                 },
                 list: {
-                    id: entry(member.id, `\`${member.id}\``),
+                    memberId: entry(member.id, `\`${member.id}\``),
                     name: entry(member.id, renderUser(member.user)),
                     joined: entry(member.joinedAt, renderDelta(member.joinedAt)),
                     kicked: entry(new Date().getTime(), renderDelta(new Date().getTime())),
@@ -57,7 +57,7 @@
                     timestamp: new Date().getTime()
                 },
                 list: {
-                    id: entry(member.id, `\`${member.id}\``),
+                    memberId: entry(member.id, `\`${member.id}\``),
                     name: entry(member.id, renderUser(member.user)),
                     joined: entry(member.joinedTimestamp, renderDelta(member.joinedAt)),
                     left: entry(new Date().getTime(), renderDelta(new Date().getTime())),
diff --git a/src/events/messageChecks.ts b/src/events/messageChecks.ts
index 4e99c61..2755ff1 100644
--- a/src/events/messageChecks.ts
+++ b/src/events/messageChecks.ts
@@ -1,9 +1,11 @@
 import { LinkCheck, MalwareCheck, NSFWCheck, SizeCheck, TestString, TestImage } from '../automations/unscan.js'
 import { Message } from 'discord.js'
+import client from '../utils/client.js'
 
 export const event = 'messageCreate'
 
 export async function callback(client, message) {
+    const { log, NucleusColors, entry, renderUser } = client.logger
     if (message.author.bot) return
     if (message.channel.type === 'dm') return
 
@@ -16,8 +18,7 @@
             !message.author.roles.cache.some(role => config.filters.invite.allowed.roles.includes(role.id))
         ) {
             if ((/(?:https?:\/\/)?discord(?:app)?\.(?:com\/invite|gg)\/[a-zA-Z0-9]+\/?/.test(content))) {
-                message.delete();
-                return toLog(message, 'invite', content.match(/(?:https?:\/\/)?discord(?:app)?\.(?:com\/invite|gg)\/[a-zA-Z0-9]+\/?/))
+                return message.delete();
             }
         }
     }
@@ -34,22 +35,19 @@
                 if(/\.+(webp|png|jpg|jpeg|bmp)/.test(url)) {
                     if (config.filters.images.NSFW && !message.channel.nsfw) {
                         if (await NSFWCheck(url)) {
-                            await message.delete()
-                            return toLog(message, 'NSFW', url)
+                            return await message.delete()
                         }
                     }
                     if (config.filters.images.size) {
                         if(!url.match(/\.+(webp|png|jpg)$/gi)) return
                         if(!await SizeCheck(element)) {
-                            await message.delete()
-                            return toLog(message, 'size', url)
+                            return await message.delete()
                         }
                     }
                 }
                 if (config.filters.malware) {
                     if (!MalwareCheck(url)) {
-                        await message.delete()
-                        return toLog(message, 'malware', url)
+                        return await message.delete()
                     }
                 }
             }
@@ -58,15 +56,13 @@
     if(!message) return;
 
     if (await LinkCheck(message)) {
-        await message.delete()
-        return toLog(message, 'link')
+        return await message.delete()
     }
 
     if (config.filters.wordFilter.enabled) {
         let check = TestString(content, config.filters.wordFilter.words.loose, config.filters.wordFilter.words.strict)
-        if(check != "none") {
-            await message.delete()
-            return toLog(message, 'wordFilter', content)
+        if(check !== null) {
+            return await message.delete()
         }
     }
 
@@ -75,26 +71,19 @@
         !message.author.roles.cache.some(role => config.filters.pings.allowed.roles.includes(role.id))
     ) {
         if (config.filters.pings.everyone && message.mentions.everyone) {
-            message.delete();
-            return toLog(message, 'mention everyone')
+            return message.delete();
         }
         if (config.filters.pings.roles) {
             for(let role of message.mentions.roles) {
                 if(!message) return;
                 if (!config.filters.pings.allowed.roles.includes(role.id)) {
-                    message.delete();
-                    return toLog(message, 'mention role')
+                    return message.delete();
                 }
             }
         }
         if(!message) return;
         if (message.mentions.users.size >= config.filters.pings.mass && config.filters.pings.mass) {
-            message.delete();
-            return toLog(message, 'Mass Pings')
+            return message.delete();
         }
     }
 }
-
-async function toLog(message: Message, reason: string, data?: any) {
-    // log(message.guild.id, {type: reason, data: data})
-}
diff --git a/src/events/messageDelete.ts b/src/events/messageDelete.ts
index 229b126..f0fbb57 100644
--- a/src/events/messageDelete.ts
+++ b/src/events/messageDelete.ts
@@ -25,7 +25,7 @@
                 start: content ? `**Message:**\n\`\`\`${content}\`\`\`` : '**Message:** *Message had no content*',
             },
             list: {
-                id: entry(message.id, `\`${message.id}\``),
+                messageId: entry(message.id, `\`${message.id}\``),
                 sentBy: entry(message.author.id, renderUser(message.author)),
                 sentIn: entry(message.channel.id, renderChannel(message.channel)),
                 deleted: entry(new Date().getTime(), renderDelta(new Date().getTime())),
diff --git a/src/events/messageEdit.ts b/src/events/messageEdit.ts
index 0d42fb9..3502963 100644
--- a/src/events/messageEdit.ts
+++ b/src/events/messageEdit.ts
@@ -7,7 +7,37 @@
         newMessage.reference = newMessage.reference || {}
         let newContent = newMessage.cleanContent.replaceAll("`", "‘")
         let oldContent = oldMessage.cleanContent.replaceAll("`", "‘")
-        if (newContent == oldContent) return;
+        if (newContent == oldContent) {
+            if (!oldMessage.flags.has("CROSSPOSTED") && newMessage.flags.has("CROSSPOSTED")) {
+                let data = {
+                    meta: {
+                        type: 'messageAnnounce',
+                        displayName: 'Message Published',
+                        calculateType: 'messageAnnounce',
+                        color: NucleusColors.yellow,
+                        emoji: 'MESSAGE.CREATE',
+                        timestamp: newMessage.editedTimestamp
+                    },
+                    separate: {
+                        end: `[[Jump to message]](${newMessage.url})`
+                    },
+                    list: {
+                        messageId: entry(newMessage.id, `\`${newMessage.id}\``),
+                        sentBy: entry(newMessage.author.id, renderUser(newMessage.author)),
+                        sentIn: entry(newMessage.channel.id, renderChannel(newMessage.channel)),
+                        sent: entry(new Date(newMessage.createdTimestamp), renderDelta(new Date(newMessage.createdTimestamp))),
+                        published: entry(new Date(newMessage.editedTimestamp), renderDelta(new Date(newMessage.editedTimestamp))),
+                        mentions: renderNumberDelta(oldMessage.mentions.users.size, newMessage.mentions.users.size),
+                        attachments: renderNumberDelta(oldMessage.attachments.size, newMessage.attachments.size)
+                    },
+                    hidden: {
+                        guild: newMessage.channel.guild.id
+                    }
+                }
+                log(data);
+            }
+            return
+        };
         if (newContent.length > 256) newContent = newContent.substring(0, 253) + '...'
         if (oldContent.length > 256) oldContent = oldContent.substring(0, 253) + '...'
         let data = {
@@ -25,7 +55,7 @@
                 end: `[[Jump to message]](${newMessage.url})`
             },
             list: {
-                id: entry(newMessage.id, `\`${newMessage.id}\``),
+                messageId: entry(newMessage.id, `\`${newMessage.id}\``),
                 sentBy: entry(newMessage.author.id, renderUser(newMessage.author)),
                 sentIn: entry(newMessage.channel.id, renderChannel(newMessage.channel)),
                 sent: entry(new Date(newMessage.createdTimestamp), renderDelta(new Date(newMessage.createdTimestamp))),
diff --git a/src/events/roleCreate.ts b/src/events/roleCreate.ts
index 61d0a87..6fded26 100644
--- a/src/events/roleCreate.ts
+++ b/src/events/roleCreate.ts
@@ -17,7 +17,7 @@
                 timestamp: role.createdTimestamp
             },
             list: {
-                id: entry(role.id, `\`${role.id}\``),
+                roleId: entry(role.id, `\`${role.id}\``),
                 role: entry(role.name, renderRole(role)),
                 createdBy: entry(audit.executor.id, renderUser(audit.executor)),
                 created: entry(role.createdTimestamp, renderDelta(role.createdTimestamp))
diff --git a/src/events/roleDelete.ts b/src/events/roleDelete.ts
index b0cb0f7..6a23d9e 100644
--- a/src/events/roleDelete.ts
+++ b/src/events/roleDelete.ts
@@ -19,7 +19,7 @@
                 timestamp: audit.createdTimestamp,
             },
             list: {
-                id: entry(role.id, `\`${role.id}\``),
+                roleId: entry(role.id, `\`${role.id}\``),
                 role: entry(role.name, role.name),
                 color: entry(role.hexColor, `\`${role.hexColor}\``),
                 showInMemberList: entry(role.hoist, role.hoist ? `${getEmojiByName("CONTROL.TICK")} Yes` : `${getEmojiByName("CONTROL.CROSS")} No`),
diff --git a/src/events/roleUpdate.ts b/src/events/roleUpdate.ts
index 982d915..baf4399 100644
--- a/src/events/roleUpdate.ts
+++ b/src/events/roleUpdate.ts
@@ -11,7 +11,7 @@
         if (audit.executor.id == client.user.id) return;
 
         let changes = {
-            id: entry(nr.id, `\`${nr.id}\``),
+            roleId: entry(nr.id, `\`${nr.id}\``),
             role: entry(nr.id, renderRole(nr)),
             edited: entry(nr.createdTimestamp, renderDelta(nr.createdTimestamp)),
             editedBy: entry(audit.executor.id, renderUser((await nr.guild.members.fetch(audit.executor.id)).user)),
diff --git a/src/events/stickerCreate.ts b/src/events/stickerCreate.ts
new file mode 100644
index 0000000..b9511b0
--- /dev/null
+++ b/src/events/stickerCreate.ts
@@ -0,0 +1,30 @@
+export const event = 'stickerCreate'
+
+export async function callback(client, emoji) {
+    try {
+        const { getAuditLog, log, NucleusColors, entry, renderUser, renderDelta } = emoji.client.logger
+        let auditLog = await getAuditLog(emoji.guild, 'STICKER_CREATE');
+        let audit = auditLog.entries.filter(entry => entry.target.id == emoji.id).first();
+        if (audit.executor.id == client.user.id) return;
+        let data = {
+            meta: {
+                type: 'stickerCreate',
+                displayName: 'Sticker Created',
+                calculateType: 'stickerUpdate',
+                color: NucleusColors.green,
+                emoji: "GUILD.EMOJI.CREATE",
+                timestamp: emoji.createdTimestamp
+            },
+            list: {
+                stickerId: entry(emoji.id, `\`${emoji.id}\``),
+                emoji: entry(emoji.name, `\`:${emoji.name}:\``),
+                createdBy: entry(audit.executor.id, renderUser(audit.executor)),
+                created: entry(emoji.createdTimestamp, renderDelta(emoji.createdTimestamp))
+            },
+            hidden: {
+                guild: emoji.guild.id
+            }
+        }
+        log(data);
+    } catch {}
+}
diff --git a/src/events/stickerDelete.ts b/src/events/stickerDelete.ts
new file mode 100644
index 0000000..7490851
--- /dev/null
+++ b/src/events/stickerDelete.ts
@@ -0,0 +1,31 @@
+export const event = 'stickerDelete'
+
+export async function callback(client, emoji) {
+    try{
+        const { getAuditLog, log, NucleusColors, entry, renderUser, renderDelta } = emoji.client.logger
+        let auditLog = await getAuditLog(emoji.guild, 'STICKER_DELETE');
+        let audit = auditLog.entries.filter(entry => entry.target.id == emoji.id).first();
+        if (audit.executor.id == client.user.id) return;
+        let data = {
+            meta: {
+                type: 'stickerDelete',
+                displayName: 'Sticker Deleted',
+                calculateType: 'stickerUpdate',
+                color: NucleusColors.red,
+                emoji: "GUILD.EMOJI.DELETE",
+                timestamp: audit.createdTimestamp,
+            },
+            list: {
+                stickerId:entry(emoji.id, `\`${emoji.id}\``),
+                sticker: entry(emoji.name, `\`${emoji.name}\``),
+                deletedBy: entry(audit.executor.id, renderUser(audit.executor)),
+                created: entry(emoji.createdTimestamp, renderDelta(emoji.createdTimestamp)),
+                deleted: entry(audit.createdTimestamp, renderDelta(audit.createdTimestamp)),
+            },
+            hidden: {
+                guild: emoji.guild.id
+            }
+        }
+        log(data);
+    } catch {}
+}
diff --git a/src/events/stickerUpdate.ts b/src/events/stickerUpdate.ts
new file mode 100644
index 0000000..7cb745f
--- /dev/null
+++ b/src/events/stickerUpdate.ts
@@ -0,0 +1,34 @@
+export const event = 'stickerUpdate';
+
+export async function callback(client, oe, ne) {
+    try {
+        const { getAuditLog, log, NucleusColors, entry, renderDelta, renderUser, renderEmoji } = client.logger
+
+        if (oe.name == ne.name) return
+        let auditLog = await getAuditLog(ne.guild, 'EMOJI_UPDATE');
+        let audit = auditLog.entries.first();
+        if (audit.executor.id == client.user.id) return;
+
+        let changes = {
+            stickerId:entry(ne.id, `\`${ne.id}\``),
+            edited: entry(ne.createdTimestamp, renderDelta(ne.createdTimestamp)),
+            editedBy: entry(audit.executor.id, renderUser((await ne.guild.members.fetch(audit.executor.id)).user)),
+            name: entry([oe.name, ne.name], `\`:${oe.name}:\` -> \`:${ne.name}:\``),
+        }
+        let data = {
+            meta:{
+                type: 'stickerUpdate',
+                displayName: 'Sticker Edited',
+                calculateType: 'stickerUpdate',
+                color: NucleusColors.yellow,
+                emoji: "GUILD.EMOJI.EDIT",
+                timestamp: audit.createdTimestamp
+            },
+            list: changes,
+            hidden: {
+                guild: ne.guild.id
+            }
+        }
+        log(data);
+    } catch {}
+}
\ No newline at end of file
diff --git a/src/events/threadCreate.ts b/src/events/threadCreate.ts
index 5c65d78..ff69e35 100644
--- a/src/events/threadCreate.ts
+++ b/src/events/threadCreate.ts
@@ -17,7 +17,7 @@
                 timestamp: thread.createdTimestamp
             },
             list: {
-                id: entry(thread.id, `\`${thread.id}\``),
+                threadId:entry(thread.id, `\`${thread.id}\``),
                 name: entry(thread.name, renderChannel(thread)),
                 parentChannel: entry(thread.parentId, renderChannel(thread.parent)),
                 category: entry(thread.parent.parent ? thread.parent.parent.name : 'None', thread.parent.parent ? renderChannel(thread.parent.parent) : 'None'),
diff --git a/src/events/threadDelete.ts b/src/events/threadDelete.ts
index 9507469..14c5820 100644
--- a/src/events/threadDelete.ts
+++ b/src/events/threadDelete.ts
@@ -17,7 +17,7 @@
             timestamp: new Date().getTime()
         },
         list: {
-            id: entry(thread.id, `\`${thread.id}\``),
+            threadId:entry(thread.id, `\`${thread.id}\``),
             name: entry(thread.name, thread.name),
             parentChannel: entry(thread.parentId, renderChannel(thread.parent)),
             category: entry(thread.parent.parent ? thread.parent.parent.name : 'None', thread.parent.parent ? renderChannel(thread.parent.parent) : 'None'),
diff --git a/src/events/threadUpdate.ts b/src/events/threadUpdate.ts
index f554a6c..4e13193 100644
--- a/src/events/threadUpdate.ts
+++ b/src/events/threadUpdate.ts
@@ -8,7 +8,7 @@
         let audit = auditLog.entries.filter(entry => entry.target.id == after.id).first();
         if (audit.executor.id == client.user.id) return;
         let list = {
-            id: entry(after.id, `\`${after.id}\``),
+            threadId:entry(after.id, `\`${after.id}\``),
             thread: entry(after.name, renderChannel(after)),
             parentChannel: entry(after.parentId, renderChannel(after.parent)),
         }
diff --git a/src/events/webhookUpdate.ts b/src/events/webhookUpdate.ts
new file mode 100644
index 0000000..a20608c
--- /dev/null
+++ b/src/events/webhookUpdate.ts
@@ -0,0 +1,78 @@
+import humanizeDuration from 'humanize-duration';
+export const event = 'webhookUpdate'
+
+export async function callback(client, channel) {
+    try {
+        const { getAuditLog, log, NucleusColors, entry, renderUser, renderChannel, renderDelta } = client.logger
+        let auditLogCreate = getAuditLog(channel.guild, 'WEBHOOK_CREATE');
+        let auditLogUpdate = getAuditLog(channel.guild, 'WEBHOOK_UPDATE');
+        let auditLogDelete = getAuditLog(channel.guild, 'WEBHOOK_DELETE');
+        [auditLogCreate, auditLogUpdate, auditLogDelete] = await Promise.all([auditLogCreate, auditLogUpdate, auditLogDelete]);
+        let auditCreate = auditLogCreate.entries.filter(entry => entry.target.channelId == channel.id).first();
+        let auditUpdate = auditLogUpdate.entries.filter(entry => entry.target.channelId == channel.id).first();
+        let auditDelete = auditLogDelete.entries.filter(entry => entry.target.channelId == channel.id).first();
+        if (!auditCreate && !auditUpdate && !auditDelete) return;
+        let audit = auditCreate;
+        let action = "Create";
+        let list = {} as any;
+        if (auditUpdate && auditUpdate.createdTimestamp > audit.createdTimestamp) {
+            let {before, after} = auditUpdate.changes.reduce(
+                (acc, change) => { acc.before[change.key] = change.old; acc.after[change.key] = change.new; return acc; },
+                {before: {}, after: {}}
+            );
+            if (before.name !== after.name) list['name'] = entry([before.name, after.name], `${before.name} -> ${after.name}`)
+            if (before.channel_id !== after.channel_id) list['channel'] = entry([before.channel_id, after.channel_id], renderChannel(await client.channels.fetch(before.channel_id)) + ` -> ` + renderChannel(await client.channels.fetch(after.channel_id)))
+            if (!(Object.keys(list)).length) return;
+            list.created = entry(auditUpdate.target.createdTimestamp, renderDelta(auditUpdate.target.createdTimestamp));
+            list.edited = entry(after.editedTimestamp, renderDelta(new Date().getTime()));
+            list.editedBy = entry(auditUpdate.executor.id, renderUser(auditUpdate.executor));
+            audit = auditUpdate;
+            action = "Update"
+        } else if (auditDelete && auditDelete.createdTimestamp > audit.createdTimestamp) {
+            let {before, after} = auditDelete.changes.reduce(
+                (acc, change) => { acc.before[change.key] = change.old; acc.after[change.key] = change.new; return acc; },
+                {before: {}, after: {}}
+            );
+            list = {
+                name: entry(before.name, `${before.name}`),
+                channel: entry(before.channel_id, renderChannel(await client.channels.fetch(before.channel_id))),
+                created: entry(auditDelete.target.createdTimestamp, renderDelta(auditDelete.target.createdTimestamp)),
+                deleted: entry(new Date().getTime(), renderDelta(new Date().getTime())),
+                deletedBy: entry(auditDelete.executor.id, renderUser((await channel.guild.members.fetch(auditDelete.executor.id)).user)),
+            }
+            audit = auditDelete;
+            action = "Delete"
+        } else {
+            let {before, after} = auditDelete.changes.reduce(
+                (acc, change) => { acc.before[change.key] = change.old; acc.after[change.key] = change.new; return acc; },
+                {before: {}, after: {}}
+            );
+            list = {
+                name: entry(before.name, `${before.name}`),
+                channel: entry(before.channel_id, renderChannel(await client.channels.fetch(before.channel_id))),
+                createdBy: entry(auditCreate.executor.id, renderUser((await channel.guild.members.fetch(auditCreate.executor.id)).user)),
+                created: entry(new Date().getTime(), renderDelta(new Date().getTime())),
+            }
+        }
+        let cols = {
+            "Create": "green",
+            "Update": "yellow",
+            "Delete": "red",
+        }
+        let data = {
+            meta: {
+                type: 'webhook' + action,
+                displayName: `Webhook ${action}d`,
+                calculateType: 'webhookUpdate',
+                color: NucleusColors[cols[action]],
+                emoji: "WEBHOOK." + action.toUpperCase(),
+                timestamp: new Date().getTime()
+            },
+            list: list,
+            hidden: {
+                guild: channel.guild.id
+            }
+        } // TODO
+        log(data);
+    } catch(e) { console.log(e) }
+}
diff --git a/src/utils/calculate.ts b/src/utils/calculate.ts
index a58fae1..7f3b16d 100644
--- a/src/utils/calculate.ts
+++ b/src/utils/calculate.ts
@@ -1,8 +1,7 @@
 const logs = [
     "channelUpdate",
-    "channelPinsUpdate", // TODO
     "emojiUpdate",
-    "stickerUpdate", // TODO
+    "stickerUpdate",
     "guildUpdate",
     "guildMemberUpdate",
     "guildMemberPunish",
@@ -14,13 +13,12 @@
     "messageReactionUpdate",
     "messagePing",
     "messageMassPing",
-    "messageAnnounce", // TODO
+    "messageAnnounce",
     "threadUpdate",
-    "webhookUpdate", // TODO
+    "webhookUpdate",
     "guildMemberVerify",
-    "autoModeratorDeleted", // TODO
-    "nucleusSettingsUpdated", // TODO
-    ""
+    "autoModeratorDeleted", // TODO: Not implemented
+    "nucleusSettingsUpdated"
 ]
 
 const tickets = [
@@ -51,7 +49,7 @@
     let permissions = [];
     let int = (BigInt("0x" + permissionsHex)).toString(2).split('').reverse();
     for (let index in int) {
-        if (int[index] == "1") {
+        if (int[index] == "1" && array.length > index) {
             permissions.push(array[index]);
         }
     }
diff --git a/src/utils/log.ts b/src/utils/log.ts
index 55f8f4c..987e256 100644
--- a/src/utils/log.ts
+++ b/src/utils/log.ts
@@ -46,10 +46,10 @@
 
     }
 
-    async getAuditLog(guild: Discord.Guild, event) {
+    async getAuditLog(guild: Discord.Guild, event): Promise<Discord.GuildAuditLogsEntry[]>{
         await wait(250)
         let auditLog = await guild.fetchAuditLogs({type: event});
-        return auditLog;
+        return auditLog as unknown as Discord.GuildAuditLogsEntry[];
     }
 
     async log(log: any): Promise<void> {