huge changes once again
diff --git a/src/commands/mod/ban.ts b/src/commands/mod/ban.ts
index 8b17db3..4581c0f 100644
--- a/src/commands/mod/ban.ts
+++ b/src/commands/mod/ban.ts
@@ -2,7 +2,7 @@
 import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
 import { WrappedCheck } from "jshaiku";
 import confirmationMessage from "../../utils/confirmationMessage.js";
-import generateEmojiEmbed from "../../utils/generateEmojiEmbed.js";
+import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
 import keyValueList from "../../utils/generateKeyValueList.js";
 import addPlurals from "../../utils/plurals.js";
 import client from "../../utils/client.js";
@@ -18,13 +18,14 @@
     )
     .addIntegerOption(option => option.setName("delete").setDescription("The days of messages to delete | Default 0").setMinValue(0).setMaxValue(7).setRequired(false))
 
-const callback = async (interaction: CommandInteraction) => {
+const callback = async (interaction: CommandInteraction): Promise<any> => {
+    const { renderUser } = client.logger
     // TODO:[Modals] Replace this with a modal
     let confirmation = await new confirmationMessage(interaction)
         .setEmoji("PUNISH.BAN.RED")
         .setTitle("Ban")
         .setDescription(keyValueList({
-            "user": `<@!${(interaction.options.getMember("user") as GuildMember).id}> (${(interaction.options.getMember("user") as GuildMember).user.username})`,
+            "user": renderUser(interaction.options.getUser("user")),
             "reason": `\n> ${interaction.options.getString("reason") ? interaction.options.getString("reason") : "*No reason provided*"}`
         })
         + `The user **will${interaction.options.getString("notify") === "no" ? ' not' : ''}** be notified\n`
@@ -35,11 +36,11 @@
     if (confirmation.success) {
         let dmd = false
         let dm;
-        let config = await client.database.read(interaction.guild.id);
+        let config = await client.database.guilds.read(interaction.guild.id);
         try {
             if (interaction.options.getString("notify") != "no") {
                 dm = await (interaction.options.getMember("user") as GuildMember).send({
-                    embeds: [new generateEmojiEmbed()
+                    embeds: [new EmojiEmbed()
                         .setEmoji("PUNISH.BAN.RED")
                         .setTitle("Banned")
                         .setDescription(`You have been banned in ${interaction.guild.name}` +
@@ -57,13 +58,13 @@
         } catch {}
         try {
             let member = (interaction.options.getMember("user") as GuildMember)
-            let reason = interaction.options.getString("reason") ?? "No reason provided"
+            let reason = interaction.options.getString("reason")
             member.ban({
                 days: Number(interaction.options.getInteger("delete") ?? 0),
-                reason: reason
+                reason: reason ?? "No reason provided"
             })
-            // @ts-ignore
-            const { log, NucleusColors, entry, renderUser, renderDelta } = interaction.user.client.logger
+            try { await client.database.history.create("ban", interaction.guild.id, member.user, interaction.user, reason) } catch {}
+            const { log, NucleusColors, entry, renderUser, renderDelta } = client.logger
             let data = {
                 meta: {
                     type: 'memberBan',
@@ -86,9 +87,9 @@
                     guild: interaction.guild.id
                 }
             }
-            log(data, member.user.client);
+            log(data);
         } catch {
-            await interaction.editReply({embeds: [new generateEmojiEmbed()
+            await interaction.editReply({embeds: [new EmojiEmbed()
                 .setEmoji("PUNISH.BAN.RED")
                 .setTitle(`Ban`)
                 .setDescription("Something went wrong and the user was not banned")
@@ -98,14 +99,14 @@
             return
         }
         let failed = (dmd == false && interaction.options.getString("notify") != "no")
-        await interaction.editReply({embeds: [new generateEmojiEmbed()
+        await interaction.editReply({embeds: [new EmojiEmbed()
             .setEmoji(`PUNISH.BAN.${failed ? "YELLOW" : "GREEN"}`)
             .setTitle(`Ban`)
             .setDescription("The member was banned" + (failed ? ", but could not be notified" : ""))
             .setStatus(failed ? "Warning" : "Success")
         ], components: []})
     } else {
-        await interaction.editReply({embeds: [new generateEmojiEmbed()
+        await interaction.editReply({embeds: [new EmojiEmbed()
             .setEmoji("PUNISH.BAN.GREEN")
             .setTitle(`Ban`)
             .setDescription("No changes were made")
@@ -125,13 +126,13 @@
     // Check if Nucleus can ban the member
     if (! (mePos > applyPos)) throw "I do not have a role higher than that member"
     // Check if Nucleus has permission to ban
-    if (! me.permissions.has("BAN_MEMBERS")) throw "I do not have the `ban_members` permission";
+    if (! me.permissions.has("BAN_MEMBERS")) throw "I do not have the Ban members permission";
     // Do not allow banning Nucleus
     if (member.id == interaction.guild.me.id) throw "I cannot ban myself"
     // Allow the owner to ban anyone
     if (member.id == interaction.guild.ownerId) return true
     // Check if the user has ban_members permission
-    if (! member.permissions.has("BAN_MEMBERS")) throw "You do not have the `ban_members` permission";
+    if (! member.permissions.has("BAN_MEMBERS")) throw "You do not have the Ban members permission";
     // Check if the user is below on the role list
     if (! (memberPos > applyPos)) throw "You do not have a role higher than that member"
     // Allow ban
diff --git a/src/commands/mod/info.ts b/src/commands/mod/info.ts
new file mode 100644
index 0000000..c3a4388
--- /dev/null
+++ b/src/commands/mod/info.ts
@@ -0,0 +1,285 @@
+import { HistorySchema } from '../../utils/database';
+import Discord, { CommandInteraction, GuildMember, MessageActionRow, MessageButton, TextInputComponent } from "discord.js";
+import { SlashCommandSubcommandBuilder, SelectMenuOption } from "@discordjs/builders";
+import { WrappedCheck } from "jshaiku";
+import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
+import getEmojiByName from "../../utils/getEmojiByName.js";
+import client from "../../utils/client.js";
+import { modalInteractionCollector } from '../../utils/dualCollector.js';
+import pageIndicator from '../../utils/createPageIndicator.js';
+
+const command = (builder: SlashCommandSubcommandBuilder) =>
+    builder
+    .setName("info")
+    .setDescription("Shows moderator information about a user")
+    .addUserOption(option => option.setName("user").setDescription("The user to get information about").setRequired(true))
+
+
+const types = {
+    "warn": {emoji: "PUNISH.WARN.YELLOW", text: "Warned"},
+    "mute": {emoji: "PUNISH.MUTE.YELLOW", text: "Muted"},
+    "join": {emoji: "MEMBER.JOIN", text: "Joined"},
+    "leave": {emoji: "MEMBER.LEAVE", text: "Left"},
+    "kick": {emoji: "MEMBER.KICK", text: "Kicked"},
+    "softban": {emoji: "PUNISH.SOFTBAN", text: "Softbanned"},
+    "ban": {emoji: "MEMBER.BAN", text: "Banned"},
+    "unban": {emoji: "MEMBER.UNBAN", text: "Unbanned"},
+    "purge": {emoji: "PUNISH.CLEARHISTORY", text: "Messages cleared"},
+    "nickname": {emoji: "PUNISH.NICKNAME.YELLOW", text: "Nickname changed"}
+}
+
+function historyToString(history: HistorySchema) {
+    let s = `${getEmojiByName(types[history.type].emoji)} ${
+        history.amount ? (history.amount + " ") : ""
+    }${
+        types[history.type].text
+    } on <t:${Math.round(history.occurredAt.getTime() / 1000)}:F>`;
+    if (history.moderator) { s += ` by <@${history.moderator}>`; }
+    if (history.reason) { s += `\n**Reason:**\n> ${history.reason}`; }
+    if (history.before) { s += `\n**Before:**\n> ${history.before}`; }
+    if (history.after) { s += `\n**After:**\n> ${history.after}`; }
+    return s + "\n";
+}
+
+
+class TimelineSection {
+    name: string;
+    content: {data: HistorySchema, rendered: string}[] = []
+
+    addContent = (content: {data: HistorySchema, rendered: string}) => { this.content.push(content); return this; }
+    contentLength = () => { return this.content.reduce((acc, cur) => acc + cur.rendered.length, 0); };
+    generateName = () => {
+        let first = Math.round(this.content[0].data.occurredAt.getTime() / 1000)
+        let last = Math.round(this.content[this.content.length - 1].data.occurredAt.getTime() / 1000)
+        if (first === last) { return this.name = `<t:${first}:F>`; }
+        return this.name = `<t:${first}:F> - <t:${last}:F>`;
+    }
+}
+
+const monthNames = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
+
+async function showHistory(member, interaction: CommandInteraction) {
+    let currentYear = new Date().getFullYear();
+    let pageIndex = null;
+    let m, history, current;
+    let refresh = true;
+    let filteredTypes = [];
+    let openFilterPane = false;
+    while (true) {
+        if (refresh) {
+            history = await client.database.history.read(member.guild.id, member.id, currentYear);
+            history = history.sort((a, b) => b.occurredAt.getTime() - a.occurredAt.getTime()).reverse();
+            if (openFilterPane) {
+                let tempFilteredTypes = filteredTypes
+                if (filteredTypes.length === 0) { tempFilteredTypes = Object.keys(types); }
+                history = history.filter(h => tempFilteredTypes.includes(h.type))
+            };
+            refresh = false;
+        }
+        let groups: TimelineSection[] = []
+        if (history.length > 0) {
+            current = new TimelineSection()
+            history.forEach(event => {
+                if (current.contentLength() + historyToString(event).length > 2000 || current.content.length === 5) {
+                    groups.push(current);
+                    current.generateName();
+                    current = new TimelineSection();
+                }
+                current.addContent({data: event, rendered: historyToString(event)});
+            });
+            current.generateName();
+            groups.push(current);
+            if (pageIndex === null) { pageIndex = groups.length - 1; }
+        }
+        let components = (
+            openFilterPane ? [
+            new MessageActionRow().addComponents([new Discord.MessageSelectMenu().setOptions(
+                Object.entries(types).map(([key, value]) => ({
+                        label: value.text,
+                        value: key,
+                        default: filteredTypes.includes(key),
+                        emoji: client.emojis.resolve(getEmojiByName(value.emoji, "id"))
+                }))
+            ).setMinValues(1).setMaxValues(Object.keys(types).length).setCustomId("filter").setPlaceholder("Select at least one event")])
+        ] : []).concat([
+            new MessageActionRow().addComponents([
+                new MessageButton()
+                    .setCustomId("prevYear")
+                    .setLabel((currentYear - 1).toString())
+                    .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
+                    .setStyle("SECONDARY"),
+                new MessageButton()
+                    .setCustomId("prevPage")
+                    .setLabel("Previous page")
+                    .setStyle("PRIMARY"),
+                new MessageButton()
+                    .setCustomId("today")
+                    .setLabel("Today")
+                    .setStyle("PRIMARY"),
+                new MessageButton()
+                    .setCustomId("nextPage")
+                    .setLabel("Next page")
+                    .setStyle("PRIMARY")
+                    .setDisabled(pageIndex >= groups.length - 1 && currentYear === new Date().getFullYear()),
+                new MessageButton()
+                    .setCustomId("nextYear")
+                    .setLabel((currentYear + 1).toString())
+                    .setEmoji(getEmojiByName("CONTROL.RIGHT", "id"))
+                    .setStyle("SECONDARY")
+                    .setDisabled(currentYear === new Date().getFullYear()),
+            ]), new MessageActionRow().addComponents([
+                new MessageButton()
+                    .setLabel("Mod notes")
+                    .setCustomId("modNotes")
+                    .setStyle("PRIMARY")
+                    .setEmoji(getEmojiByName("ICONS.EDIT", "id")),
+                new MessageButton()
+                    .setLabel("Filter")
+                    .setCustomId("openFilter")
+                    .setStyle(openFilterPane ? "SUCCESS" : "PRIMARY")
+                    .setEmoji(getEmojiByName("ICONS.FILTER", "id"))
+            ])
+        ])
+        let end = "\n\nJanuary " + currentYear.toString() + pageIndicator(
+            Math.max(groups.length, 1),
+            groups.length === 0 ? 1 : pageIndex
+        ) + (currentYear == new Date().getFullYear() ? monthNames[new Date().getMonth()] : "December"
+        ) + " " + currentYear.toString()
+        if (groups.length > 0) {
+            let toRender = groups[Math.min(pageIndex, groups.length - 1)]
+            m = await interaction.editReply({embeds: [new EmojiEmbed()
+                .setEmoji("MEMBER.JOIN")
+                .setTitle("Moderation history for " + member.user.username)
+                .setDescription(`**${toRender.name}**\n\n` + toRender.content.map(c => c.rendered).join("\n") + end)
+                .setStatus("Success")
+                .setFooter({text: (openFilterPane && filteredTypes.length) ? "Filters are currently enabled" : ""})
+            ], components: components});
+        } else {
+            m = await interaction.editReply({embeds: [new EmojiEmbed()
+                .setEmoji("MEMBER.JOIN")
+                .setTitle("Moderation history for " + member.user.username)
+                .setDescription(`**${currentYear}**\n\n*No events*` + `\n\n` + end)
+                .setStatus("Success")
+                .setFooter({text: (openFilterPane && filteredTypes.length) ? "Filters are currently enabled" : ""})
+            ], components: components});
+        }
+        let i;
+        try {
+            i = await m.awaitMessageComponent({ time: 300000 });
+        } catch (e) {
+            interaction.editReply({embeds: [new EmojiEmbed()
+                .setEmoji("MEMBER.JOIN")
+                .setTitle("Moderation history for " + member.user.username)
+                .setDescription(m.embeds[0].description)
+                .setStatus("Danger")
+                .setFooter({text: "Message timed out"})
+            ]});
+            return 0
+        }
+        i.deferUpdate()
+        if (i.customId === "filter") {
+            filteredTypes = i.values;
+            pageIndex = null;
+            refresh = true;
+        }
+        if (i.customId === "prevYear") { currentYear--; pageIndex = null; refresh = true; }
+        if (i.customId === "nextYear") { currentYear++; pageIndex = null; refresh = true; }
+        if (i.customId === "prevPage") {
+            pageIndex--;
+            if (pageIndex < 0) { pageIndex = null; currentYear--; refresh = true; }
+        }
+        if (i.customId === "nextPage") {
+            pageIndex++;
+            if (pageIndex >= groups.length) { pageIndex = 0; currentYear++; refresh = true; }
+        }
+        if (i.customId === "today") { currentYear = new Date().getFullYear(); pageIndex = null; refresh = true; }
+        if (i.customId === "modNotes") { return 1 }
+        if (i.customId === "openFilter") { openFilterPane = !openFilterPane; refresh = true }
+    }
+}
+
+
+const callback = async (interaction: CommandInteraction): Promise<any> => {
+    let m;
+    let member = (interaction.options.getMember("user")) as Discord.GuildMember;
+    await interaction.reply({embeds: [new EmojiEmbed()
+        .setEmoji("NUCLEUS.LOADING")
+        .setTitle("Downloading data...")
+        .setStatus("Success")
+    ], ephemeral: true, fetchReply: true});
+    let note;
+    let firstLoad = true;
+    while (true) {
+        note = await client.database.notes.read(member.guild.id, member.id);
+        if (firstLoad && !note) { await showHistory(member, interaction); }
+        firstLoad = false;
+        m = await interaction.editReply({embeds: [new EmojiEmbed()
+            .setEmoji("MEMBER.JOIN")
+            .setTitle("Mod notes for " + member.user.username)
+            .setDescription(note ? note : "*No note set*")
+            .setStatus("Success")
+        ], components: [new MessageActionRow().addComponents([
+            new MessageButton()
+                .setLabel(`${note ? "Modify" : "Create"} note`)
+                .setStyle("PRIMARY")
+                .setCustomId("modify")
+                .setEmoji(getEmojiByName("ICONS.EDIT", "id")),
+            new MessageButton()
+                .setLabel("View moderation history")
+                .setStyle("PRIMARY")
+                .setCustomId("history")
+                .setEmoji(getEmojiByName("ICONS.HISTORY", "id"))
+        ])]});
+        let i;
+        try {
+            i = await m.awaitMessageComponent({ time: 300000 });
+        } catch (e) { return }
+        if (i.customId === "modify") {
+            await i.showModal(new Discord.Modal().setCustomId("modal").setTitle(`Editing moderator note`).addComponents(
+                // @ts-ignore
+                new MessageActionRow().addComponents(new TextInputComponent()
+                    .setCustomId("note")
+                    .setLabel("Note")
+                    .setMaxLength(4000)
+                    .setRequired(false)
+                    .setStyle("PARAGRAPH")
+                    .setValue(note ? note : "")
+                )
+            ))
+            await interaction.editReply({
+                embeds: [new EmojiEmbed()
+                    .setTitle("Mod notes for " + member.user.username)
+                    .setDescription("Modal opened. If you can't see it, click back and try again.")
+                    .setStatus("Success")
+                    .setEmoji("GUILD.TICKET.OPEN")
+                ], components: [new MessageActionRow().addComponents([new MessageButton()
+                    .setLabel("Back")
+                    .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
+                    .setStyle("PRIMARY")
+                    .setCustomId("back")
+                ])]
+            });
+            let out;
+            try {
+                out = await modalInteractionCollector(m, (m) => m.channel.id == interaction.channel.id, (m) => m.customId == "modify")
+            } catch (e) { continue }
+            if (out.fields) {
+                let toAdd = out.fields.getTextInputValue("note") || null;
+                await client.database.notes.create(member.guild.id, member.id, toAdd);
+            } else { continue }
+        } else if (i.customId === "history") {
+            i.deferUpdate();
+            if (!await showHistory(member, interaction) ) return
+        }
+    }
+}
+
+const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
+    let member = (interaction.member as GuildMember)
+    if (! member.permissions.has("MODERATE_MEMBERS")) throw "You do not have the Moderate members permission";
+    return true
+}
+
+export { command };
+export { callback };
+export { check };
\ No newline at end of file
diff --git a/src/commands/mod/kick.ts b/src/commands/mod/kick.ts
index 20fbc01..97ead7b 100644
--- a/src/commands/mod/kick.ts
+++ b/src/commands/mod/kick.ts
@@ -3,7 +3,7 @@
 import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
 import { WrappedCheck } from "jshaiku";
 import confirmationMessage from "../../utils/confirmationMessage.js";
-import generateEmojiEmbed from "../../utils/generateEmojiEmbed.js";
+import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
 import keyValueList from "../../utils/generateKeyValueList.js";
 import client from "../../utils/client.js";
 
@@ -17,13 +17,14 @@
         .addChoices([["Yes", "yes"], ["No", "no"]])
     )
 
-const callback = async (interaction: CommandInteraction) => {
+const callback = async (interaction: CommandInteraction): Promise<any> => {
+    const { renderUser } = client.logger
     // TODO:[Modals] Replace this with a modal
     let confirmation = await new confirmationMessage(interaction)
         .setEmoji("PUNISH.KICK.RED")
         .setTitle("Kick")
         .setDescription(keyValueList({
-            "user": `<@!${(interaction.options.getMember("user") as GuildMember).id}> (${(interaction.options.getMember("user") as GuildMember).user.username})`,
+            "user": renderUser(interaction.options.getUser("user")),
             "reason": `\n> ${interaction.options.getString("reason") ? interaction.options.getString("reason") : "*No reason provided*"}`
         })
         + `The user **will${interaction.options.getString("notify") === "no" ? ' not' : ''}** be notified\n\n`
@@ -33,11 +34,11 @@
     if (confirmation.success) {
         let dmd = false
         let dm;
-        let config = await client.database.read(interaction.guild.id);
+        let config = await client.database.guilds.read(interaction.guild.id);
         try {
             if (interaction.options.getString("notify") != "no") {
                 dm = await (interaction.options.getMember("user") as GuildMember).send({
-                    embeds: [new generateEmojiEmbed()
+                    embeds: [new EmojiEmbed()
                         .setEmoji("PUNISH.KICK.RED")
                         .setTitle("Kicked")
                         .setDescription(`You have been kicked in ${interaction.guild.name}` +
@@ -57,8 +58,9 @@
             (interaction.options.getMember("user") as GuildMember).kick(interaction.options.getString("reason") ?? "No reason provided.")
             let member = (interaction.options.getMember("user") as GuildMember)
             let reason = interaction.options.getString("reason") ?? null
+            try { await client.database.history.create("kick", interaction.guild.id, member.user, interaction.user, reason) } catch {}
             // @ts-ignore
-            const { getAuditLog, log, NucleusColors, entry, renderUser, renderDelta } = member.client.logger
+            const { log, NucleusColors, entry, renderUser, renderDelta } = member.client.logger
             let data = {
                 meta: {
                     type: 'memberKick',
@@ -83,9 +85,9 @@
                     guild: member.guild.id
                 }
             }
-            log(data, member.client);
+            log(data);
         } catch {
-            await interaction.editReply({embeds: [new generateEmojiEmbed()
+            await interaction.editReply({embeds: [new EmojiEmbed()
                 .setEmoji("PUNISH.KICK.RED")
                 .setTitle(`Kick`)
                 .setDescription("Something went wrong and the user was not kicked")
@@ -95,14 +97,14 @@
             return
         }
         let failed = (dmd == false && interaction.options.getString("notify") != "no")
-        await interaction.editReply({embeds: [new generateEmojiEmbed()
+        await interaction.editReply({embeds: [new EmojiEmbed()
             .setEmoji(`PUNISH.KICK.${failed ? "YELLOW" : "GREEN"}`)
             .setTitle(`Kick`)
             .setDescription("The member was kicked" + (failed ? ", but could not be notified" : ""))
             .setStatus(failed ? "Warning" : "Success")
         ], components: []})
     } else {
-        await interaction.editReply({embeds: [new generateEmojiEmbed()
+        await interaction.editReply({embeds: [new EmojiEmbed()
             .setEmoji("PUNISH.KICK.GREEN")
             .setTitle(`Kick`)
             .setDescription("No changes were made")
@@ -122,13 +124,13 @@
     // Check if Nucleus can kick the member
     if (! (mePos > applyPos)) throw "I do not have a role higher than that member"
     // Check if Nucleus has permission to kick
-    if (! me.permissions.has("KICK_MEMBERS")) throw "I do not have the `kick_members` permission";
+    if (! me.permissions.has("KICK_MEMBERS")) throw "I do not have the Kick members permission";
     // Do not allow kicking Nucleus
     if (member.id == interaction.guild.me.id) throw "I cannot kick myself"
     // Allow the owner to kick anyone
     if (member.id == interaction.guild.ownerId) return true
     // Check if the user has kick_members permission
-    if (! member.permissions.has("KICK_MEMBERS")) throw "You do not have the `kick_members` permission";
+    if (! member.permissions.has("KICK_MEMBERS")) throw "You do not have the Kick members permission";
     // Check if the user is below on the role list
     if (! (memberPos > applyPos)) throw "You do not have a role higher than that member"
     // Allow kick
diff --git a/src/commands/mod/mute.ts b/src/commands/mod/mute.ts
index 79beeb3..5f42b27 100644
--- a/src/commands/mod/mute.ts
+++ b/src/commands/mod/mute.ts
@@ -1,7 +1,7 @@
 import Discord, { CommandInteraction, GuildMember, MessageActionRow, MessageButton } from "discord.js";
 import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
 import { WrappedCheck } from "jshaiku";
-import generateEmojiEmbed from "../../utils/generateEmojiEmbed.js";
+import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
 import getEmojiByName from "../../utils/getEmojiByName.js";
 import confirmationMessage from "../../utils/confirmationMessage.js";
 import keyValueList from "../../utils/generateKeyValueList.js";
@@ -31,14 +31,14 @@
         minutes: interaction.options.getInteger("minutes") || 0,
         seconds: interaction.options.getInteger("seconds") || 0
     }
-    let config = await client.database.read(interaction.guild.id)
+    let config = await client.database.guilds.read(interaction.guild.id)
     let serverSettingsDescription = (config.moderation.mute.timeout ? "given a timeout" : "")
     if (config.moderation.mute.role) serverSettingsDescription += (serverSettingsDescription ? " and " : "") + `given the <@&${config.moderation.mute.role}> role`
 
     let muteTime = (time.days * 24 * 60 * 60) + (time.hours * 60 * 60) + (time.minutes * 60) + time.seconds
     if (muteTime == 0) {
         let m = await interaction.reply({embeds: [
-            new generateEmojiEmbed()
+            new EmojiEmbed()
                 .setEmoji("PUNISH.MUTE.GREEN")
                 .setTitle("Mute")
                 .setDescription("How long should the user be muted")
@@ -93,7 +93,7 @@
             component = await (m as Discord.Message).awaitMessageComponent({filter: (m) => m.user.id === interaction.user.id, time: 300000});
         } catch { return }
         component.deferUpdate();
-        if (component.customId == "cancel") return interaction.editReply({embeds: [new generateEmojiEmbed()
+        if (component.customId == "cancel") return interaction.editReply({embeds: [new EmojiEmbed()
             .setEmoji("PUNISH.MUTE.RED")
             .setTitle("Mute")
             .setDescription("Mute cancelled")
@@ -111,7 +111,7 @@
         }
     } else {
         await interaction.reply({embeds: [
-            new generateEmojiEmbed()
+            new EmojiEmbed()
                 .setEmoji("PUNISH.MUTE.GREEN")
                 .setTitle("Mute")
                 .setDescription("Loading...")
@@ -123,7 +123,7 @@
         .setEmoji("PUNISH.MUTE.RED")
         .setTitle("Mute")
         .setDescription(keyValueList({
-            "user": `<@!${user.id}> (${user.user.username})`,
+            "user": renderUser(user),
             "time": `${humanizeDuration(muteTime * 1000, {round: true})}`,
             "reason": `\n> ${reason ? reason : "*No reason provided*"}`
         })
@@ -135,11 +135,11 @@
     if (confirmation.success) {
         let dmd = false
         let dm;
-        let config = await client.database.read(interaction.guild.id);
+        let config = await client.database.guilds.read(interaction.guild.id);
         try {
             if (interaction.options.getString("notify") != "no") {
                 dm = await (interaction.options.getMember("user") as GuildMember).send({
-                    embeds: [new generateEmojiEmbed()
+                    embeds: [new EmojiEmbed()
                         .setEmoji("PUNISH.MUTE.RED")
                         .setTitle("Muted")
                         .setDescription(`You have been muted in ${interaction.guild.name}` +
@@ -156,15 +156,16 @@
                 dmd = true
             }
         } catch {}
+        let member = (interaction.options.getMember("user") as GuildMember)
         try {
             if (config.moderation.mute.timeout) {
-                (interaction.options.getMember("user") as GuildMember).timeout(muteTime * 1000, interaction.options.getString("reason") || "No reason provided")
+                member.timeout(muteTime * 1000, interaction.options.getString("reason") || "No reason provided")
             }
             if (config.moderation.mute.role) {
-                (interaction.options.getMember("user") as GuildMember).roles.add(config.moderation.mute.role)
+                member.roles.add(config.moderation.mute.role)
             }
         } catch {
-            await interaction.editReply({embeds: [new generateEmojiEmbed()
+            await interaction.editReply({embeds: [new EmojiEmbed()
                 .setEmoji("PUNISH.MUTE.RED")
                 .setTitle(`Mute`)
                 .setDescription("Something went wrong and the user was not mute")
@@ -173,8 +174,9 @@
             if (dmd) await dm.delete()
             return
         }
+        try { await client.database.history.create("mute", interaction.guild.id, member.user, interaction.user, reason) } catch {}
         let failed = (dmd == false && interaction.options.getString("notify") != "no")
-        await interaction.editReply({embeds: [new generateEmojiEmbed()
+        await interaction.editReply({embeds: [new EmojiEmbed()
             .setEmoji(`PUNISH.MUTE.${failed ? "YELLOW" : "GREEN"}`)
             .setTitle(`Mute`)
             .setDescription("The member was muted" + (failed ? ", but could not be notified" : ""))
@@ -190,7 +192,7 @@
                 timestamp: new Date().getTime()
             },
             list: {
-                user: entry((interaction.options.getMember("user") as GuildMember).user.id, renderUser((interaction.options.getMember("user") as GuildMember).user)),
+                user: entry(member.user.id, renderUser(member.user)),
                 mutedBy: entry(interaction.member.user.id, renderUser(interaction.member.user)),
                 time: entry(muteTime, `${humanizeDuration(muteTime * 1000, {round: true})}`),
                 reason: (interaction.options.getString("reason") ? `\n> ${interaction.options.getString("reason")}` : "No reason provided")
@@ -199,9 +201,9 @@
                 guild: interaction.guild.id
             }
         }
-        log(data, client);
+        log(data);
     } else {
-        await interaction.editReply({embeds: [new generateEmojiEmbed()
+        await interaction.editReply({embeds: [new EmojiEmbed()
             .setEmoji("PUNISH.MUTE.GREEN")
             .setTitle(`Mute`)
             .setDescription("No changes were made")
@@ -221,7 +223,7 @@
     // Check if Nucleus can mute the member
     if (! (mePos > applyPos)) throw "I do not have a role higher than that member"
     // Check if Nucleus has permission to mute
-    if (! me.permissions.has("MODERATE_MEMBERS")) throw "I do not have the `moderate_members` permission";
+    if (! me.permissions.has("MODERATE_MEMBERS")) throw "I do not have the Moderate members permission";
     // Do not allow the user to have admin or be the owner
     if (apply.permissions.has("ADMINISTRATOR") || (interaction.options.getMember("user") as GuildMember).id == interaction.guild.ownerId) throw "You cannot mute an admin or the owner"
     // Do not allow muting Nucleus
@@ -229,7 +231,7 @@
     // Allow the owner to mute anyone
     if (member.id == interaction.guild.ownerId) return true
     // Check if the user has moderate_members permission
-    if (! member.permissions.has("MODERATE_MEMBERS")) throw "You do not have the `moderate_members` permission";
+    if (! member.permissions.has("MODERATE_MEMBERS")) throw "You do not have the Moderate members permission";
     // Check if the user is below on the role list
     if (! (memberPos > applyPos)) throw "You do not have a role higher than that member"
     // Allow mute
diff --git a/src/commands/mod/nick.ts b/src/commands/mod/nick.ts
index c09e197..e154277 100644
--- a/src/commands/mod/nick.ts
+++ b/src/commands/mod/nick.ts
@@ -2,9 +2,10 @@
 import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
 import { WrappedCheck } from "jshaiku";
 import confirmationMessage from "../../utils/confirmationMessage.js";
-import generateEmojiEmbed from "../../utils/generateEmojiEmbed.js";
+import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
 import keyValueList from "../../utils/generateKeyValueList.js";
 import { create, areTicketsEnabled } from "../../automations/createModActionTicket.js";
+import client from "../../utils/client.js"
 
 const command = (builder: SlashCommandSubcommandBuilder) =>
     builder
@@ -16,13 +17,14 @@
         .addChoices([["Yes", "yes"], ["No", "no"]])
     )
 
-const callback = async (interaction: CommandInteraction) => {
+const callback = async (interaction: CommandInteraction): Promise<any> => {
+    const { renderUser } = client.logger
     // TODO:[Modals] Replace this with a modal
     let confirmation = await new confirmationMessage(interaction)
         .setEmoji("PUNISH.NICKNAME.RED")
         .setTitle("Nickname")
         .setDescription(keyValueList({
-            "user": `<@!${(interaction.options.getMember("user") as GuildMember).id}> (${(interaction.options.getMember("user") as GuildMember).user.username})`,
+            "user": renderUser(interaction.options.getUser("user")),
             "new nickname": `${interaction.options.getString("name") ? interaction.options.getString("name") : "*No nickname*"}`
         })
         + `The user **will${interaction.options.getString("notify") == "yes" ? '' : ' not'}** be notified\n\n`
@@ -39,7 +41,7 @@
         try {
             if (interaction.options.getString("notify") == "yes") {
                 dm = await (interaction.options.getMember("user") as GuildMember).send({
-                    embeds: [new generateEmojiEmbed()
+                    embeds: [new EmojiEmbed()
                         .setEmoji("PUNISH.NICKNAME.RED")
                         .setTitle("Nickname changed")
                         .setDescription(`Your nickname was ${interaction.options.getString("name") ? "changed" : "cleared"} in ${interaction.guild.name}.` +
@@ -56,6 +58,9 @@
             let before = member.nickname
             let nickname = interaction.options.getString("name")
             member.setNickname(nickname ?? null, "Nucleus Nickname command")
+            try { await client.database.history.create(
+                "nickname", interaction.guild.id, member.user, interaction.user,
+                null, before, nickname) } catch {}
             // @ts-ignore
             const { log, NucleusColors, entry, renderUser, renderDelta, getAuditLog } = client.logger
             let data = {
@@ -78,9 +83,9 @@
                     guild: interaction.guild.id
                 }
             }
-            log(data, client);
+            log(data);
         } catch {
-            await interaction.editReply({embeds: [new generateEmojiEmbed()
+            await interaction.editReply({embeds: [new EmojiEmbed()
                 .setEmoji("PUNISH.NICKNAME.RED")
                 .setTitle(`Nickname`)
                 .setDescription("Something went wrong and the users nickname could not be changed.")
@@ -90,14 +95,14 @@
             return
         }
         let failed = (dmd == false && interaction.options.getString("notify") == "yes")
-        await interaction.editReply({embeds: [new generateEmojiEmbed()
+        await interaction.editReply({embeds: [new EmojiEmbed()
             .setEmoji(`PUNISH.NICKNAME.${failed ? "YELLOW" : "GREEN"}`)
             .setTitle(`Nickname`)
             .setDescription("The members nickname was changed" + (failed ? ", but was not notified" : "") + (confirmation.response ? ` and an appeal ticket was opened in <#${confirmation.response}>` : ``))
             .setStatus(failed ? "Warning" : "Success")
         ], components: []})
     } else {
-        await interaction.editReply({embeds: [new generateEmojiEmbed()
+        await interaction.editReply({embeds: [new EmojiEmbed()
             .setEmoji("PUNISH.NICKNAME.GREEN")
             .setTitle(`Nickname`)
             .setDescription("No changes were made")
@@ -117,11 +122,11 @@
     // Check if Nucleus can change the nickname
     if (! (mePos > applyPos)) throw "I do not have a role higher than that member"
     // Check if Nucleus has permission to change the nickname
-    if (! me.permissions.has("MANAGE_NICKNAMES")) throw "I do not have the `manage_nicknames` permission";
+    if (! me.permissions.has("MANAGE_NICKNAMES")) throw "I do not have the Manage nicknames permission";
     // Allow the owner to change anyone's nickname
     if (member.id == interaction.guild.ownerId) return true
     // Check if the user has manage_nicknames permission
-    if (! member.permissions.has("MANAGE_NICKNAMES")) throw "You do not have the `manage_nicknames` permission";
+    if (! member.permissions.has("MANAGE_NICKNAMES")) throw "You do not have the Manage nicknames permission";
     // Allow changing your own nickname
     if (member == apply) return true
     // Check if the user is below on the role list
diff --git a/src/commands/mod/purge.ts b/src/commands/mod/purge.ts
index c6a44b3..9aab260 100644
--- a/src/commands/mod/purge.ts
+++ b/src/commands/mod/purge.ts
@@ -2,9 +2,10 @@
 import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
 import { WrappedCheck } from "jshaiku";
 import confirmationMessage from "../../utils/confirmationMessage.js";
-import generateEmojiEmbed from "../../utils/generateEmojiEmbed.js";
+import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
 import keyValueList from "../../utils/generateKeyValueList.js";
 import getEmojiByName from "../../utils/getEmojiByName.js";
+import client from "../../utils/client.js";
 
 const command = (builder: SlashCommandSubcommandBuilder) =>
     builder
@@ -25,7 +26,7 @@
     if (!(["GUILD_TEXT", "GUILD_NEWS", "GUILD_NEWS_THREAD", "GUILD_PUBLIC_THREAD", "GUILD_PRIVATE_THREAD"].includes(channel.type.toString()))) {
         return await interaction.reply({
             embeds: [
-                new generateEmojiEmbed()
+                new EmojiEmbed()
                     .setEmoji("CHANNEL.PURGE.RED")
                     .setTitle("Purge")
                     .setDescription("You cannot purge this channel")
@@ -39,7 +40,7 @@
     if ( !interaction.options.getInteger("amount") ) {
         await interaction.reply({
             embeds: [
-                new generateEmojiEmbed()
+                new EmojiEmbed()
                     .setEmoji("CHANNEL.PURGE.RED")
                     .setTitle("Purge")
                     .setDescription("Select how many messages to delete")
@@ -53,7 +54,7 @@
         while (true) {
             let m = await interaction.editReply({
                 embeds: [
-                    new generateEmojiEmbed()
+                    new EmojiEmbed()
                         .setEmoji("CHANNEL.PURGE.RED")
                         .setTitle("Purge")
                         .setDescription("Select how many messages to delete. You can continue clicking until all messages are cleared.")
@@ -118,7 +119,7 @@
         }
         if (deleted.length === 0) return await interaction.editReply({
             embeds: [
-                new generateEmojiEmbed()
+                new EmojiEmbed()
                     .setEmoji("CHANNEL.PURGE.RED")
                     .setTitle("Purge")
                     .setDescription("No messages were deleted")
@@ -126,10 +127,13 @@
             ],
             components: []
         })
+        if (user) {
+            try { await client.database.history.create("purge", interaction.guild.id, user, interaction.options.getString("reason"), null, null, deleted.length) } catch {}
+        }
         let attachmentObject;
         try {
             // @ts-ignore
-            const { log, NucleusColors, entry, renderUser, renderChannel } = interaction.user.client.logger
+            const { log, NucleusColors, entry, renderUser, renderChannel } = client.logger
             let data = {
                 meta: {
                     type: 'channelPurge',
@@ -149,7 +153,7 @@
                     guild: interaction.guild.id
                 }
             }
-            log(data, interaction.user.client);
+            log(data);
             let out = ""
             deleted.reverse().forEach(message => {
                 out += `${message.author.username}#${message.author.discriminator} (${message.author.id}) [${new Date(message.createdTimestamp).toISOString()}]\n`
@@ -163,7 +167,7 @@
                 description: "Purge log"
             }
         } catch {}
-        let m = await interaction.editReply({embeds: [new generateEmojiEmbed()
+        let m = await interaction.editReply({embeds: [new EmojiEmbed()
             .setEmoji(`CHANNEL.PURGE.GREEN`)
             .setTitle(`Purge`)
             .setDescription("Messages cleared")
@@ -180,14 +184,14 @@
             component = await (m as Discord.Message).awaitMessageComponent({filter: (m) => m.user.id === interaction.user.id, time: 300000});
         } catch {}
         if (component && component.customId === "download") {
-            interaction.editReply({embeds: [new generateEmojiEmbed()
+            interaction.editReply({embeds: [new EmojiEmbed()
                 .setEmoji("CHANNEL.PURGE.GREEN")
                 .setTitle(`Purge`)
                 .setDescription("Uploaded")
                 .setStatus("Success")
             ], components: [], files: [attachmentObject]})
         } else {
-            interaction.editReply({embeds: [new generateEmojiEmbed()
+            interaction.editReply({embeds: [new EmojiEmbed()
                 .setEmoji("CHANNEL.PURGE.GREEN")
                 .setTitle(`Purge`)
                 .setDescription("Messages cleared")
@@ -218,17 +222,20 @@
                     messages = await (channel as TextChannel).bulkDelete(toDelete, true);
                 }
             } catch(e) {
-                await interaction.editReply({embeds: [new generateEmojiEmbed()
+                await interaction.editReply({embeds: [new EmojiEmbed()
                     .setEmoji("CHANNEL.PURGE.RED")
                     .setTitle(`Purge`)
                     .setDescription("Something went wrong and no messages were deleted")
                     .setStatus("Danger")
                 ], components: []})
             }
+            if (user) {
+                try { await client.database.history.create("purge", interaction.guild.id, user, interaction.options.getString("reason"), null, null, messages.size) } catch {}
+            }
             let attachmentObject;
             try {
                 // @ts-ignore
-                const { log, NucleusColors, entry, renderUser, renderChannel } = interaction.user.client.logger
+                const { log, NucleusColors, entry, renderUser, renderChannel } = client.logger
                 let data = {
                     meta: {
                         type: 'channelPurge',
@@ -248,7 +255,7 @@
                         guild: interaction.guild.id
                     }
                 }
-                log(data, interaction.user.client);
+                log(data);
                 let out = ""
                 messages.reverse().forEach(message => {
                     out += `${message.author.username}#${message.author.discriminator} (${message.author.id}) [${new Date(message.createdTimestamp).toISOString()}]\n`
@@ -262,7 +269,7 @@
                     description: `Purge log`
                 }
             } catch {}
-            let m = await interaction.editReply({embeds: [new generateEmojiEmbed()
+            let m = await interaction.editReply({embeds: [new EmojiEmbed()
                 .setEmoji(`CHANNEL.PURGE.GREEN`)
                 .setTitle(`Purge`)
                 .setDescription("Messages cleared")
@@ -279,14 +286,14 @@
                 component = await (m as Discord.Message).awaitMessageComponent({filter: (m) => m.user.id === interaction.user.id, time: 300000});
             } catch {}
             if (component && component.customId === "download") {
-                interaction.editReply({embeds: [new generateEmojiEmbed()
+                interaction.editReply({embeds: [new EmojiEmbed()
                     .setEmoji("CHANNEL.PURGE.GREEN")
                     .setTitle(`Purge`)
                     .setDescription("Transcript uploaded above")
                     .setStatus("Success")
                 ], components: [], files: [attachmentObject]})
             } else {
-                interaction.editReply({embeds: [new generateEmojiEmbed()
+                interaction.editReply({embeds: [new EmojiEmbed()
                     .setEmoji("CHANNEL.PURGE.GREEN")
                     .setTitle(`Purge`)
                     .setDescription("Messages cleared")
@@ -294,7 +301,7 @@
                 ], components: []})
             }
         } else {
-            await interaction.editReply({embeds: [new generateEmojiEmbed()
+            await interaction.editReply({embeds: [new EmojiEmbed()
                 .setEmoji("CHANNEL.PURGE.GREEN")
                 .setTitle(`Purge`)
                 .setDescription("No changes were made")
@@ -310,9 +317,9 @@
     // Allow the owner to purge
     if (member.id == interaction.guild.ownerId) return true
     // Check if the user has manage_messages permission
-    if (! member.permissions.has("MANAGE_MESSAGES")) throw "You do not have the `manage_messages` permission";
+    if (! member.permissions.has("MANAGE_MESSAGES")) throw "You do not have the Manage messages permission";
     // Check if nucleus has the manage_messages permission
-    if (! me.permissions.has("MANAGE_MESSAGES")) throw "I do not have the `manage_messages` permission";
+    if (! me.permissions.has("MANAGE_MESSAGES")) throw "I do not have the Manage messages permission";
     // Allow warn
     return true
 }
diff --git a/src/commands/mod/slowmode.ts b/src/commands/mod/slowmode.ts
index 2498746..d9a8421 100644
--- a/src/commands/mod/slowmode.ts
+++ b/src/commands/mod/slowmode.ts
@@ -4,7 +4,8 @@
 import { WrappedCheck } from "jshaiku";
 import keyValueList from "../../utils/generateKeyValueList.js";
 import confirmationMessage from "../../utils/confirmationMessage.js";
-import generateEmojiEmbed from "../../utils/generateEmojiEmbed.js";
+import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
+
 
 const command = (builder: SlashCommandSubcommandBuilder) =>
     builder
@@ -18,11 +19,11 @@
         ["1 hour", "3600"], ["2 hours", "7200"], ["6 hours", "21600"]
     ]))
 
-const callback = async (interaction: CommandInteraction) => {
+const callback = async (interaction: CommandInteraction): Promise<any> => {
     let time = parseInt(interaction.options.getString("time") ?? "0");
     if (time === 0 && (interaction.channel as TextChannel).rateLimitPerUser === 0) { time = 10 }
     let confirmation = await new confirmationMessage(interaction)
-        .setEmoji("CHANNEL.SLOWMODE.RED")
+        .setEmoji("CHANNEL.SLOWMODE.OFF")
         .setTitle("Slowmode")
         .setDescription(keyValueList({
             "time": time ? humanizeDuration(time * 1000, { round: true }) : "No delay",
@@ -34,22 +35,22 @@
         try {
             (interaction.channel as TextChannel).setRateLimitPerUser(time)
         } catch (e) {
-            await interaction.editReply({embeds: [new generateEmojiEmbed()
-                .setEmoji("CHANNEL.SLOWMODE.RED")
+            await interaction.editReply({embeds: [new EmojiEmbed()
+                .setEmoji("CHANNEL.SLOWMODE.OFF")
                 .setTitle(`Slowmode`)
                 .setDescription("Something went wrong while setting the slowmode")
                 .setStatus("Danger")
             ], components: []})
         }
-        await interaction.editReply({embeds: [new generateEmojiEmbed()
-            .setEmoji(`CHANNEL.SLOWMODE.GREEN`)
+        await interaction.editReply({embeds: [new EmojiEmbed()
+            .setEmoji(`CHANNEL.SLOWMODE.ON`)
             .setTitle(`Slowmode`)
             .setDescription("The channel slowmode was set successfully")
             .setStatus("Success")
         ], components: []})
     } else {
-        await interaction.editReply({embeds: [new generateEmojiEmbed()
-            .setEmoji("CHANNEL.SLOWMODE.GREEN")
+        await interaction.editReply({embeds: [new EmojiEmbed()
+            .setEmoji("CHANNEL.SLOWMODE.ON")
             .setTitle(`Slowmode`)
             .setDescription("No changes were made")
             .setStatus("Success")
@@ -60,9 +61,9 @@
 const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
     let member = (interaction.member as GuildMember)
     // Check if Nucleus can set the slowmode
-    if (! interaction.guild.me.permissions.has("MANAGE_CHANNELS")) throw "I do not have the `manage_channels` permission";
+    if (! interaction.guild.me.permissions.has("MANAGE_CHANNELS")) throw "I do not have the Manage channels permission";
     // Check if the user has manage_channel permission
-    if (! member.permissions.has("MANAGE_CHANNELS")) throw "You do not have the `manage_channels` permission";
+    if (! member.permissions.has("MANAGE_CHANNELS")) throw "You do not have the Manage channels permission";
     // Allow slowmode
     return true
 }
diff --git a/src/commands/mod/softban.ts b/src/commands/mod/softban.ts
index 5a01287..ea4a447 100644
--- a/src/commands/mod/softban.ts
+++ b/src/commands/mod/softban.ts
@@ -2,7 +2,7 @@
 import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
 import { WrappedCheck } from "jshaiku";
 import confirmationMessage from "../../utils/confirmationMessage.js";
-import generateEmojiEmbed from "../../utils/generateEmojiEmbed.js";
+import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
 import keyValueList from "../../utils/generateKeyValueList.js";
 import client from "../../utils/client.js";
 import addPlural from "../../utils/plurals.js";
@@ -18,13 +18,14 @@
     )
     .addIntegerOption(option => option.setName("delete").setDescription("The days of messages to delete | Default 0").setMinValue(0).setMaxValue(7).setRequired(false))
 
-const callback = async (interaction: CommandInteraction) => {
+const callback = async (interaction: CommandInteraction): Promise<any> => {
+    const { renderUser } = client.logger
     // TODO:[Modals] Replace this with a modal
     let confirmation = await new confirmationMessage(interaction)
         .setEmoji("PUNISH.BAN.RED")
         .setTitle("Softban")
         .setDescription(keyValueList({
-            "user": `<@!${(interaction.options.getMember("user") as GuildMember).id}> (${(interaction.options.getMember("user") as GuildMember).user.username})`,
+            "user": renderUser(interaction.options.getUser("user")),
             "reason": `\n> ${interaction.options.getString("reason") ? interaction.options.getString("reason") : "*No reason provided*"}`
         })
         + `The user **will${interaction.options.getString("notify") === "no" ? ' not' : ''}** be notified\n`
@@ -34,11 +35,11 @@
     .send()
     if (confirmation.success) {
         let dmd = false;
-        let config = await client.database.read(interaction.guild.id);
+        let config = await client.database.guilds.read(interaction.guild.id);
         try {
             if (interaction.options.getString("notify") != "no") {
                 await (interaction.options.getMember("user") as GuildMember).send({
-                    embeds: [new generateEmojiEmbed()
+                    embeds: [new EmojiEmbed()
                         .setEmoji("PUNISH.BAN.RED")
                         .setTitle("Softbanned")
                         .setDescription(`You have been softbanned from ${interaction.guild.name}` +
@@ -54,29 +55,31 @@
                 dmd = true
             }
         } catch {}
+        let member = (interaction.options.getMember("user") as GuildMember)
         try {
-            await (interaction.options.getMember("user") as GuildMember).ban({
+            await member.ban({
                 days: Number(interaction.options.getInteger("delete") ?? 0),
                 reason: interaction.options.getString("reason")
             });
-            await interaction.guild.members.unban(interaction.options.getMember("user") as GuildMember, "Softban");
+            await interaction.guild.members.unban(member, "Softban");
         } catch {
-            await interaction.editReply({embeds: [new generateEmojiEmbed()
+            await interaction.editReply({embeds: [new EmojiEmbed()
                 .setEmoji("PUNISH.BAN.RED")
                 .setTitle(`Softban`)
                 .setDescription("Something went wrong and the user was not softbanned")
                 .setStatus("Danger")
             ], components: []})
         }
+        try { await client.database.history.create("softban", interaction.guild.id, member.user, interaction.options.getString("reason")) } catch {}
         let failed = (dmd == false && interaction.options.getString("notify") != "no")
-        await interaction.editReply({embeds: [new generateEmojiEmbed()
+        await interaction.editReply({embeds: [new EmojiEmbed()
             .setEmoji(`PUNISH.BAN.${failed ? "YELLOW" : "GREEN"}`)
             .setTitle(`Softban`)
             .setDescription("The member was softbanned" + (failed ? ", but could not be notified" : ""))
             .setStatus(failed ? "Warning" : "Success")
         ], components: []})
     } else {
-        await interaction.editReply({embeds: [new generateEmojiEmbed()
+        await interaction.editReply({embeds: [new EmojiEmbed()
             .setEmoji("PUNISH.BAN.GREEN")
             .setTitle(`Softban`)
             .setDescription("No changes were made")
@@ -96,13 +99,13 @@
     // Check if Nucleus can ban the member
     if (! (mePos > applyPos)) throw "I do not have a role higher than that member"
     // Check if Nucleus has permission to ban
-    if (!me.permissions.has("BAN_MEMBERS")) throw "I do not have the `ban_members` permission";
+    if (!me.permissions.has("BAN_MEMBERS")) throw "I do not have the Ban members permission";
     // Do not allow softbanning Nucleus
     if (member.id == me.id) throw "I cannot softban myself"
     // Allow the owner to ban anyone
     if (member.id == interaction.guild.ownerId) return true
     // Check if the user has ban_members permission
-    if (! member.permissions.has("BAN_MEMBERS")) throw "You do not have the `ban_members` permission";
+    if (! member.permissions.has("BAN_MEMBERS")) throw "You do not have the Ban members permission";
     // Check if the user is below on the role list
     if (! (memberPos > applyPos)) throw "You do not have a role higher than that member"
     // Allow softban
diff --git a/src/commands/mod/unban.ts b/src/commands/mod/unban.ts
index f7bf74f..7f605d9 100644
--- a/src/commands/mod/unban.ts
+++ b/src/commands/mod/unban.ts
@@ -1,9 +1,10 @@
 import { CommandInteraction, GuildMember, User } from "discord.js";
 import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
 import { WrappedCheck } from "jshaiku";
-import generateEmojiEmbed from "../../utils/generateEmojiEmbed.js";
+import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
 import keyValueList from "../../utils/generateKeyValueList.js";
 import confirmationMessage from "../../utils/confirmationMessage.js";
+import client from "../../utils/client.js";
 
 const command = (builder: SlashCommandSubcommandBuilder) =>
     builder
@@ -11,14 +12,14 @@
     .setDescription("Unbans a user")
     .addStringOption(option => option.setName("user").setDescription("The user to unban (Username or ID)").setRequired(true))
 
-const callback = async (interaction: CommandInteraction) => {
+const callback = async (interaction: CommandInteraction): Promise<any> => {
     let bans = await interaction.guild.bans.fetch()
     let user = interaction.options.getString("user")
     let resolved = bans.find(ban => ban.user.id == user)
     if (!resolved) resolved = bans.find(ban => ban.user.username.toLowerCase() == user.toLowerCase())
     if (!resolved) resolved = bans.find(ban => ban.user.tag.toLowerCase() == user.toLowerCase())
     if (!resolved) {
-        return interaction.reply({embeds: [new generateEmojiEmbed()
+        return interaction.reply({embeds: [new EmojiEmbed()
             .setTitle("Unban")
             .setDescription(`Could not find any user called \`${user}\``)
             .setEmoji("PUNISH.UNBAN.RED")
@@ -39,8 +40,9 @@
         try {
             await interaction.guild.members.unban(resolved.user as User, "Unban");
             let member = (resolved.user as User)
+            try { await client.database.history.create("unban", interaction.guild.id, member, interaction.user) } catch {}
             // @ts-ignore
-            const { log, NucleusColors, entry, renderUser, renderDelta } = interaction.user.client.logger
+            const { log, NucleusColors, entry, renderUser, renderDelta } = client.logger
             let data = {
                 meta: {
                     type: 'memberUnban',
@@ -61,23 +63,23 @@
                     guild: interaction.guild.id
                 }
             }
-            log(data, member.client);
+            log(data);
         } catch {
-            await interaction.editReply({embeds: [new generateEmojiEmbed()
+            await interaction.editReply({embeds: [new EmojiEmbed()
                 .setEmoji("PUNISH.UNBAN.RED")
                 .setTitle(`Unban`)
                 .setDescription("Something went wrong and the user was not unbanned")
                 .setStatus("Danger")
             ], components: []})
         }
-        await interaction.editReply({embeds: [new generateEmojiEmbed()
+        await interaction.editReply({embeds: [new EmojiEmbed()
             .setEmoji(`PUNISH.UNBAN.GREEN`)
             .setTitle(`Unban`)
             .setDescription("The member was unbanned")
             .setStatus("Success")
         ], components: []})
     } else {
-        await interaction.editReply({embeds: [new generateEmojiEmbed()
+        await interaction.editReply({embeds: [new EmojiEmbed()
             .setEmoji("PUNISH.UNBAN.GREEN")
             .setTitle(`Unban`)
             .setDescription("No changes were made")
@@ -90,11 +92,11 @@
     let member = (interaction.member as GuildMember)
     let me = (interaction.guild.me as GuildMember)
     // Check if Nucleus can unban members
-    if (! me.permissions.has("BAN_MEMBERS")) throw "I do not have the `ban_members` permission";
+    if (! me.permissions.has("BAN_MEMBERS")) throw "I do not have the Ban members permission";
     // Allow the owner to unban anyone
     if (member.id == interaction.guild.ownerId) return true
     // Check if the user has ban_members permission
-    if (! member.permissions.has("BAN_MEMBERS")) throw "You do not have the `ban_members` permission";
+    if (! member.permissions.has("BAN_MEMBERS")) throw "You do not have the Ban members permission";
     // Allow unban
     return true
 }
diff --git a/src/commands/mod/unmute.ts b/src/commands/mod/unmute.ts
index 2a98c54..5a1b67c 100644
--- a/src/commands/mod/unmute.ts
+++ b/src/commands/mod/unmute.ts
@@ -2,8 +2,9 @@
 import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
 import { WrappedCheck } from "jshaiku";
 import confirmationMessage from "../../utils/confirmationMessage.js";
-import generateEmojiEmbed from "../../utils/generateEmojiEmbed.js";
+import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
 import keyValueList from "../../utils/generateKeyValueList.js";
+import client from "../../utils/client.js";
 
 const command = (builder: SlashCommandSubcommandBuilder) =>
     builder
@@ -15,13 +16,14 @@
         .addChoices([["Yes", "yes"], ["No", "no"]])
     )
 
-const callback = async (interaction: CommandInteraction) => {
+const callback = async (interaction: CommandInteraction): Promise<any> => {
+    const { renderUser } = client.logger
     // TODO:[Modals] Replace this with a modal
     let confirmation =  await new confirmationMessage(interaction)
         .setEmoji("PUNISH.MUTE.RED")
         .setTitle("Unmute")
         .setDescription(keyValueList({
-            "user": `<@!${(interaction.options.getMember("user") as GuildMember).id}> (${(interaction.options.getMember("user") as GuildMember).user.username})`,
+            "user": renderUser(interaction.options.getUser("user")),
             "reason": `\n> ${interaction.options.getString("reason") ? interaction.options.getString("reason") : "*No reason provided*"}`
         })
         + `The user **will${interaction.options.getString("notify") === "yes" ? '' : ' not'}** be notified\n\n`
@@ -34,7 +36,7 @@
         try {
             if (interaction.options.getString("notify") != "no") {
                 dm = await (interaction.options.getMember("user") as GuildMember).send({
-                    embeds: [new generateEmojiEmbed()
+                    embeds: [new EmojiEmbed()
                         .setEmoji("PUNISH.MUTE.GREEN")
                         .setTitle("Unmuted")
                         .setDescription(`You have been unmuted in ${interaction.guild.name}` +
@@ -48,7 +50,7 @@
         try {
             (interaction.options.getMember("user") as GuildMember).timeout(0, interaction.options.getString("reason") || "No reason provided")
         } catch {
-            await interaction.editReply({embeds: [new generateEmojiEmbed()
+            await interaction.editReply({embeds: [new EmojiEmbed()
                 .setEmoji("PUNISH.MUTE.RED")
                 .setTitle(`Unmute`)
                 .setDescription("Something went wrong and the user was not unmuted")
@@ -57,15 +59,16 @@
             if (dmd) await dm.delete()
             return
         }
+        try { await client.database.history.create("unmute", interaction.guild.id, (interaction.options.getMember("user") as GuildMember).user, interaction.user, interaction.options.getString("reason")) } catch {}
         let failed = (dmd == false && interaction.options.getString("notify") != "no")
-        await interaction.editReply({embeds: [new generateEmojiEmbed()
+        await interaction.editReply({embeds: [new EmojiEmbed()
             .setEmoji(`PUNISH.MUTE.${failed ? "YELLOW" : "GREEN"}`)
             .setTitle(`Unmute`)
             .setDescription("The member was unmuted" + (failed ? ", but could not be notified" : ""))
             .setStatus(failed ? "Warning" : "Success")
         ], components: []})
     } else {
-        await interaction.editReply({embeds: [new generateEmojiEmbed()
+        await interaction.editReply({embeds: [new EmojiEmbed()
             .setEmoji("PUNISH.MUTE.GREEN")
             .setTitle(`Unmute`)
             .setDescription("No changes were made")
@@ -85,13 +88,13 @@
     // Check if Nucleus can unmute the member
     if (! (mePos > applyPos)) throw "I do not have a role higher than that member"
     // Check if Nucleus has permission to unmute
-    if (! me.permissions.has("MODERATE_MEMBERS")) throw "I do not have the `moderate_members` permission";
+    if (! me.permissions.has("MODERATE_MEMBERS")) throw "I do not have the Moderate members permission";
     // Do not allow the user to have admin or be the owner
     if (apply.permissions.has("ADMINISTRATOR") || apply.id == interaction.guild.ownerId) throw "You cannot unmute an admin or the owner"
     // Allow the owner to unmute anyone
     if (member.id == interaction.guild.ownerId) return true
     // Check if the user has moderate_members permission
-    if (! member.permissions.has("MODERATE_MEMBERS")) throw "You do not have the `moderate_members` permission";
+    if (! member.permissions.has("MODERATE_MEMBERS")) throw "You do not have the Moderate members permission";
     // Check if the user is below on the role list
     if (! (memberPos > applyPos)) throw "You do not have a role higher than that member"
     // Allow unmute
diff --git a/src/commands/mod/viewas.ts b/src/commands/mod/viewas.ts
index 705c04a..b3875a7 100644
--- a/src/commands/mod/viewas.ts
+++ b/src/commands/mod/viewas.ts
@@ -1,8 +1,9 @@
-import Discord, { CategoryChannel, CommandInteraction } from "discord.js";
+import Discord, { CategoryChannel, CommandInteraction, GuildMember, MessageActionRow, MessageButton, MessageSelectMenu } from "discord.js";
 import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
-import generateEmojiEmbed from "../../utils/generateEmojiEmbed.js";
+import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
 import { WrappedCheck } from "jshaiku";
 import getEmojiByName from "../../utils/getEmojiByName.js";
+import pageIndicator from "../../utils/createPageIndicator.js";
 
 const command = (builder: SlashCommandSubcommandBuilder) =>
     builder
@@ -10,8 +11,9 @@
     .setDescription("View the server as a specific member")
     .addUserOption(option => option.setName("member").setDescription("The member to view as").setRequired(true))
 
-const callback = async (interaction: CommandInteraction) => {
-    let channels = []
+const callback = async (interaction: CommandInteraction): Promise<any> => {
+    let channels = [];
+    let m;
     interaction.guild.channels.cache.forEach(channel => {
         if (!channel.parent && channel.type !== "GUILD_CATEGORY") channels.push(channel)
     })
@@ -22,39 +24,83 @@
     )
     let autoSortBelow = ["GUILD_VOICE", "GUILD_STAGE_VOICE"]
     channels = channels.map(c => c.sort((a, b) => {
-        if (autoSortBelow.includes(a.type) && autoSortBelow.includes(b.type)) return a.name.localeCompare(b.name)
-        if (autoSortBelow.includes(a.type)) return -1
-        if (autoSortBelow.includes(b.type)) return 1
+        if (autoSortBelow.includes(a.type) && autoSortBelow.includes(b.type)) return a.position - b.position
+        if (autoSortBelow.includes(a.type)) return 1
+        if (autoSortBelow.includes(b.type)) return -1
         return a.position - b.position
     }))
+    // Sort all arrays by the position of the first channels parent position
+    channels = channels.sort((a, b) => {
+        if (!a[0].parent) return -1
+        if (!b[0].parent) return 1
+        return a[0].parent.position - b[0].parent.position
+    })
     let member = interaction.options.getMember("member") as Discord.GuildMember
-    await interaction.reply({embeds: [new generateEmojiEmbed()
+    m = await interaction.reply({embeds: [new EmojiEmbed()
         .setEmoji("MEMBER.JOIN")
         .setTitle("Viewing as " + member.displayName)
         .setStatus("Success")
-    ], ephemeral: true})
+    ], ephemeral: true, fetchReply: true})
     let page = 0;
     while (true) {
-        await interaction.editReply({embeds: [new generateEmojiEmbed()
+        m = await interaction.editReply({embeds: [new EmojiEmbed()
             .setEmoji("MEMBER.JOIN")
             .setTitle("Viewing as " + member.displayName)
             .setStatus("Success")
             .setDescription(
-                `${channels[page][0].parent ? channels[page][0].parent.name  : "Uncategorised"}` +
-                "Visible:\n" +
+                `**${channels[page][0].parent ? channels[page][0].parent.name  : "Uncategorised"}**` + "\n" +
                 channels[page].map(c => {
-                    console.log(c)
-                    return (channels[page] as Discord.GuildChannel).permissionsFor(member).has("VIEW_CHANNEL") ?
-                        `${getEmojiByName("ICONS.CHANNEL." + c.type)} ${c.name}\n` : ""
-                }).join("")
+                    let channelType = c.type
+                    if (interaction.guild.rulesChannelId == c.id) channelType = "RULES"
+                    else if ("nsfw" in c && c.nsfw) channelType += "_NSFW"
+                    return c.permissionsFor(member).has("VIEW_CHANNEL") ? (
+                        `${getEmojiByName("ICONS.CHANNEL." + channelType)} ${c.name}\n` + (() => {
+                            if ("threads" in c && c.threads.cache.size > 0) {
+                                return c.threads.cache.map(t => ` ${
+                                    getEmojiByName("ICONS.CHANNEL.THREAD_PIPE") + " " +
+                                    getEmojiByName("ICONS.CHANNEL.THREAD_CHANNEL")} ${t.name}`).join("\n") + "\n"
+                            }return ""
+                        })()) : ""
+                }).join("") + "\n" + pageIndicator(channels.length, page)
             )
+        ], components: [
+            new MessageActionRow().addComponents([new MessageSelectMenu().setOptions(channels.map((c, index) => ({
+                label: c[0].parent ? c[0].parent.name : "Uncategorised",
+                value: index.toString(),
+                default: page === index
+            }))).setCustomId("select").setMaxValues(1).setMinValues(1).setPlaceholder("Select a category")]),
+            new MessageActionRow().addComponents([
+                new MessageButton()
+                    .setLabel(page === 0 ? "" : (channels[page - 1][0].parent ? channels[page - 1][0].parent.name : "Uncategorised"))
+                    .setDisabled(page === 0)
+                    .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
+                    .setStyle("PRIMARY")
+                    .setCustomId("previous"),
+                new MessageButton()
+                    .setLabel(page === channels.length - 1 ? "" : (channels[page + 1][0].parent ? channels[page + 1][0].parent.name : "Uncategorised"))
+                    .setDisabled(page === channels.length - 1)
+                    .setEmoji(getEmojiByName("CONTROL.RIGHT", "id"))
+                    .setStyle("PRIMARY")
+                    .setCustomId("next")
+            ])
         ]})
-        break
+        let i;
+        try {
+            i = await m.awaitMessageComponent({ time: 300000 });
+        } catch (e) { return }
+        i.deferUpdate()
+        if (i.customId === "next") { page++; }
+        else if (i.customId === "previous") { page--; }
+        else if (i.customId === "select") { page = parseInt(i.values[0]); }
     }
 }
 
+
 const check = (interaction: CommandInteraction, defaultCheck: WrappedCheck) => {
-    return true;
+    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
 }
 
 export { command, callback, check };
\ No newline at end of file
diff --git a/src/commands/mod/warn.ts b/src/commands/mod/warn.ts
index b8fb98f..370f347 100644
--- a/src/commands/mod/warn.ts
+++ b/src/commands/mod/warn.ts
@@ -2,9 +2,10 @@
 import { SlashCommandSubcommandBuilder } from "@discordjs/builders";
 import { WrappedCheck } from "jshaiku";
 import confirmationMessage from "../../utils/confirmationMessage.js";
-import generateEmojiEmbed from "../../utils/generateEmojiEmbed.js";
+import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
 import keyValueList from "../../utils/generateKeyValueList.js";
 import { create, areTicketsEnabled } from "../../automations/createModActionTicket.js";
+import client from "../../utils/client.js"
 
 const command = (builder: SlashCommandSubcommandBuilder) =>
     builder
@@ -23,7 +24,7 @@
         .setEmoji("PUNISH.WARN.RED")
         .setTitle("Warn")
         .setDescription(keyValueList({
-            "user": `<@!${(interaction.options.getMember("user") as GuildMember).id}> (${(interaction.options.getMember("user") as GuildMember).user.username})`,
+            "user": renderUser(interaction.options.getUser("user")),
             "reason": `\n> ${interaction.options.getString("reason") ? interaction.options.getString("reason") : "*No reason provided*"}`
         })
         + `The user **will${interaction.options.getString("notify") === "no" ? ' not' : ''}** be notified\n\n`
@@ -39,7 +40,7 @@
         try {
             if (interaction.options.getString("notify") != "no") {
                 await (interaction.options.getMember("user") as GuildMember).send({
-                    embeds: [new generateEmojiEmbed()
+                    embeds: [new EmojiEmbed()
                         .setEmoji("PUNISH.WARN.RED")
                         .setTitle("Warned")
                         .setDescription(`You have been warned in ${interaction.guild.name}` +
@@ -51,7 +52,7 @@
                 dmd = true
             }
         } catch {
-            await interaction.editReply({embeds: [new generateEmojiEmbed()
+            await interaction.editReply({embeds: [new EmojiEmbed()
                 .setEmoji("PUNISH.WARN.RED")
                 .setTitle(`Warn`)
                 .setDescription("Something went wrong and the user was not warned")
@@ -76,10 +77,15 @@
                 guild: interaction.guild.id
             }
         }
-        log(data, client);
+        try { await client.database.history.create(
+            "warn", interaction.guild.id,
+            (interaction.options.getMember("user") as GuildMember).user,
+            interaction.user, interaction.options.getString("reason")
+        )} catch {}
+        log(data);
         let failed = (dmd == false && interaction.options.getString("notify") != "no")
         if (!failed) {
-            await interaction.editReply({embeds: [new generateEmojiEmbed()
+            await interaction.editReply({embeds: [new EmojiEmbed()
                 .setEmoji(`PUNISH.WARN.GREEN`)
                 .setTitle(`Warn`)
                 .setDescription("The user was warned" + (confirmation.response ? ` and an appeal ticket was opened in <#${confirmation.response}>` : ``))
@@ -87,7 +93,7 @@
             ], components: []})
         } else {
             let m = await interaction.editReply({
-                embeds: [new generateEmojiEmbed()
+                embeds: [new EmojiEmbed()
                     .setEmoji(`PUNISH.WARN.RED`)
                     .setTitle(`Warn`)
                     .setDescription("The user's DMs are not open\n\nWhat would you like to do?")
@@ -110,7 +116,7 @@
             try {
                 component = await (m as Discord.Message).awaitMessageComponent({filter: (m) => m.user.id === interaction.user.id, time: 300000});
             } catch (e) {
-                return await interaction.editReply({embeds: [new generateEmojiEmbed()
+                return await interaction.editReply({embeds: [new EmojiEmbed()
                     .setEmoji(`PUNISH.WARN.GREEN`)
                     .setTitle(`Warn`)
                     .setDescription("No changes were made")
@@ -119,7 +125,7 @@
             }
             if ( component.customId == "here" ) {
                 await interaction.channel.send({
-                    embeds: [new generateEmojiEmbed()
+                    embeds: [new EmojiEmbed()
                         .setEmoji(`PUNISH.WARN.RED`)
                         .setTitle(`Warn`)
                         .setDescription(`You have been warned` +
@@ -129,14 +135,14 @@
                     content: `<@!${(interaction.options.getMember("user") as GuildMember).id}>`,
                     allowedMentions: {users: [(interaction.options.getMember("user") as GuildMember).id]}
                 })
-                return await interaction.editReply({embeds: [new generateEmojiEmbed()
+                return await interaction.editReply({embeds: [new EmojiEmbed()
                     .setEmoji(`PUNISH.WARN.GREEN`)
                     .setTitle(`Warn`)
                     .setDescription("The user was warned" + (confirmation.response ? ` and an appeal ticket was opened in <#${confirmation.response}>` : ``))
                     .setStatus("Success")
                 ], components: []})
             } else {
-                await interaction.editReply({embeds: [new generateEmojiEmbed()
+                await interaction.editReply({embeds: [new EmojiEmbed()
                     .setEmoji(`PUNISH.WARN.GREEN`)
                     .setTitle(`Warn`)
                     .setDescription("The warn was logged")
@@ -145,7 +151,7 @@
             }
         }
     } else {
-        await interaction.editReply({embeds: [new generateEmojiEmbed()
+        await interaction.editReply({embeds: [new EmojiEmbed()
             .setEmoji("PUNISH.WARN.GREEN")
             .setTitle(`Warn`)
             .setDescription("No changes were made")
@@ -167,7 +173,7 @@
     // Allow the owner to warn anyone
     if (member.id == interaction.guild.ownerId) return true
     // Check if the user has moderate_members permission
-    if (! member.permissions.has("MODERATE_MEMBERS")) throw "You do not have the `moderate_members` permission";
+    if (! member.permissions.has("MODERATE_MEMBERS")) throw "You do not have the Moderate members permission";
     // Check if the user is below on the role list
     if (! (memberPos > applyPos)) throw "You do not have a role higher than that member"
     // Allow warn