Rename warnings to notes

This commit is contained in:
Tarrgon
2025-05-29 10:34:11 -04:00
parent b5e631a965
commit 41299da489
8 changed files with 97 additions and 98 deletions
+3 -3
View File
@@ -1,12 +1,12 @@
import { ButtonInteraction, Client } from 'discord.js'; import { ButtonInteraction, Client } from 'discord.js';
import { getWarningMessage } from '../utils/warning-utils'; import { getNoteMessage } from '../utils/note-utils';
export default { export default {
name: 'warning-next', name: 'note-next',
handler: async function (client: Client, interaction: ButtonInteraction, userId: string, page: string) { handler: async function (client: Client, interaction: ButtonInteraction, userId: string, page: string) {
await interaction.deferUpdate(); await interaction.deferUpdate();
const message = await getWarningMessage(userId, parseInt(page) + 1); const message = await getNoteMessage(userId, parseInt(page) + 1);
if (!message) return; if (!message) return;
+3 -3
View File
@@ -1,12 +1,12 @@
import { ButtonInteraction, Client} from 'discord.js'; import { ButtonInteraction, Client} from 'discord.js';
import { getWarningMessage } from '../utils/warning-utils'; import { getNoteMessage } from '../utils/note-utils';
export default { export default {
name: 'warning-previous', name: 'note-previous',
handler: async function (client: Client, interaction: ButtonInteraction, userId: string, page: string) { handler: async function (client: Client, interaction: ButtonInteraction, userId: string, page: string) {
await interaction.deferUpdate(); await interaction.deferUpdate();
const message = await getWarningMessage(userId, parseInt(page) - 1); const message = await getNoteMessage(userId, parseInt(page) - 1);
if (!message) return; if (!message) return;
@@ -1,48 +1,47 @@
import { ApplicationCommandOptionType, ApplicationIntegrationType, AutocompleteInteraction, ChatInputCommandInteraction, Client, GuildBasedChannel, InteractionContextType, MessageFlags, PermissionFlagsBits, SlashCommandBuilder } from 'discord.js'; import { ApplicationCommandOptionType, ApplicationIntegrationType, AutocompleteInteraction, ChatInputCommandInteraction, Client, GuildBasedChannel, InteractionContextType, MessageFlags, PermissionFlagsBits, SlashCommandBuilder } from 'discord.js';
import { Database } from '../shared/Database'; import { Database } from '../shared/Database';
import { channelIsInStaffCategory, getE621User } from '../utils'; import { channelIsInStaffCategory } from '../utils';
import { config } from '../config'; import { getNoteMessage } from '../utils/note-utils';
import { getWarningMessage } from '../utils/warning-utils';
export default { export default {
name: 'warnings', name: 'notes',
data: new SlashCommandBuilder() data: new SlashCommandBuilder()
.setName('warnings') .setName('notes')
.setDescription('Add, view, or remove user warnings.') .setDescription('Add, view, or remove user notes.')
.setIntegrationTypes(ApplicationIntegrationType.GuildInstall) .setIntegrationTypes(ApplicationIntegrationType.GuildInstall)
.setContexts(InteractionContextType.Guild) .setContexts(InteractionContextType.Guild)
.setDefaultMemberPermissions(PermissionFlagsBits.BanMembers) .setDefaultMemberPermissions(PermissionFlagsBits.BanMembers)
.addSubcommand(subcommand => .addSubcommand(subcommand =>
subcommand subcommand
.setName('add') .setName('add')
.setDescription('Add warnings to a user.') .setDescription('Add notes to a user.')
.addUserOption(option => .addUserOption(option =>
option option
.setName('user') .setName('user')
.setDescription('The user to add a warning to.') .setDescription('The user to add a note to.')
.setRequired(true) .setRequired(true)
) )
.addStringOption(option => .addStringOption(option =>
option option
.setName('reason') .setName('reason')
.setDescription('The reason for the warning.') .setDescription('The reason for the note.')
.setRequired(true) .setRequired(true)
) )
) )
.addSubcommand(subcommand => .addSubcommand(subcommand =>
subcommand subcommand
.setName('remove') .setName('remove')
.setDescription('Remove warnings from a user.') .setDescription('Remove notes from a user.')
.addUserOption(option => .addUserOption(option =>
option option
.setName('user') .setName('user')
.setDescription('The user to remove a warning from.') .setDescription('The user to remove a note from.')
.setRequired(true) .setRequired(true)
) )
.addIntegerOption(option => .addIntegerOption(option =>
option option
.setName('warning') .setName('note')
.setDescription('The warning to remove.') .setDescription('The note to remove.')
.setRequired(true) .setRequired(true)
.setAutocomplete(true) .setAutocomplete(true)
) )
@@ -50,11 +49,11 @@ export default {
.addSubcommand(subcommand => .addSubcommand(subcommand =>
subcommand subcommand
.setName('list') .setName('list')
.setDescription("List a user's warnings") .setDescription("List a user's notes")
.addUserOption(option => .addUserOption(option =>
option option
.setName('user') .setName('user')
.setDescription('The user to list the warnings of.') .setDescription('The user to list the notes of.')
.setRequired(true) .setRequired(true)
) )
), ),
@@ -70,26 +69,26 @@ export default {
if (subcommand == 'add') { if (subcommand == 'add') {
const reason = interaction.options.getString('reason', true); const reason = interaction.options.getString('reason', true);
await Database.putWarning(user.id, reason, interaction.user.id); await Database.putNote(user.id, reason, interaction.user.id);
if (isStaffChannel) interaction.editReply('Added warning.'); if (isStaffChannel) interaction.editReply('Added note.');
else interaction.editReply({ content: 'Added warning.' }); else interaction.editReply({ content: 'Added note.' });
} else if (subcommand == 'remove') { } else if (subcommand == 'remove') {
const warningId = interaction.options.getInteger('warning', true); const noteId = interaction.options.getInteger('note', true);
if (await Database.removeWarning(warningId)) { if (await Database.removeNote(noteId)) {
if (isStaffChannel) interaction.editReply('Removed warning.'); if (isStaffChannel) interaction.editReply('Removed note.');
else interaction.editReply({ content: 'Removed warning.' }); else interaction.editReply({ content: 'Removed note.' });
} else { } else {
if (isStaffChannel) interaction.editReply('Warning not found.'); if (isStaffChannel) interaction.editReply('Note not found.');
else interaction.editReply({ content: 'Warning not found.' }); else interaction.editReply({ content: 'Note not found.' });
} }
} else if (subcommand == 'list') { } else if (subcommand == 'list') {
const warningMessage = await getWarningMessage(user.id, 1); const noteMessage = await getNoteMessage(user.id, 1);
if (!warningMessage) return interaction.editReply(`No warnings found for <@${user.id}>`); if (!noteMessage) return interaction.editReply(`No notes found for <@${user.id}>`);
interaction.editReply(warningMessage); interaction.editReply(noteMessage);
} }
}, },
autoComplete: async function (client: Client, interaction: AutocompleteInteraction) { autoComplete: async function (client: Client, interaction: AutocompleteInteraction) {
@@ -101,9 +100,9 @@ export default {
const value = interaction.options.getFocused().toLowerCase(); const value = interaction.options.getFocused().toLowerCase();
const warnings = await Database.getWarnings(userId); const notes = await Database.getNotes(userId);
const toRespond = warnings.filter(w => !value ? true : w.reason.toLowerCase().includes(value)); const toRespond = notes.filter(w => !value ? true : w.reason.toLowerCase().includes(value));
if (toRespond.length > 25) toRespond.length = 25; if (toRespond.length > 25) toRespond.length = 25;
interaction.respond(toRespond.map((w) => { interaction.respond(toRespond.map((w) => {
+10 -10
View File
@@ -3,7 +3,7 @@ import { open, Database as SqliteDatabase } from 'sqlite';
import { config } from '../config'; import { config } from '../config';
import DiscordOAuth2 from 'discord-oauth2'; import DiscordOAuth2 from 'discord-oauth2';
import { serializeMessage, wait } from '../utils'; import { serializeMessage, wait } from '../utils';
import { GuildSettings, LoggedMessage, TicketMessage, TicketPhrase, Warning } from '../types'; import { GuildSettings, LoggedMessage, TicketMessage, TicketPhrase, Note } from '../types';
import { Message } from '../events'; import { Message } from '../events';
const DB_SCHEMA = ` const DB_SCHEMA = `
@@ -53,7 +53,7 @@ const DB_SCHEMA = `
phrase TEXT NOT NULL phrase TEXT NOT NULL
); );
CREATE TABLE IF NOT EXISTS warnings ( CREATE TABLE IF NOT EXISTS notes (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
user_id TEXT, user_id TEXT,
reason TEXT, reason TEXT,
@@ -263,21 +263,21 @@ export class Database {
// -- END TICKETS -- // -- END TICKETS --
// -- START WARNINGS -- // -- START NOTES --
static async putWarning(userId: string, reason: string, modId: string) { static async putNote(userId: string, reason: string, modId: string) {
await Database.db.run('INSERT INTO warnings(user_id, reason, mod_id) VALUES (?, ?, ?)', userId, reason, modId); await Database.db.run('INSERT INTO notes(user_id, reason, mod_id) VALUES (?, ?, ?)', userId, reason, modId);
} }
static async removeWarning(id: number): Promise<boolean> { static async removeNote(id: number): Promise<boolean> {
const res = await Database.db.run('DELETE from warnings WHERE id = ?', id); const res = await Database.db.run('DELETE from notes WHERE id = ?', id);
return (res.changes ?? 0) > 0; return (res.changes ?? 0) > 0;
} }
static async getWarnings(userId: string): Promise<Warning[]> { static async getNotes(userId: string): Promise<Note[]> {
return await Database.db.all<Warning[]>('SELECT * from warnings WHERE user_id = ?', userId); return await Database.db.all<Note[]>('SELECT * from notes WHERE user_id = ?', userId);
} }
// -- END WARNINGS -- // -- END NOTES --
} }
+1 -1
View File
@@ -32,7 +32,7 @@ export type TicketPhrase = {
phrase: string phrase: string
} }
export type Warning = { export type Note = {
id: number id: number
user_id: string user_id: string
reason: string reason: string
+1 -1
View File
@@ -11,5 +11,5 @@ export * from './refresh-commands';
export * from './string-utils'; export * from './string-utils';
export * from './ticket-utils'; export * from './ticket-utils';
export * from './wait'; export * from './wait';
export * from './warning-utils'; export * from './note-utils';
export * from './whois'; export * from './whois';
+51
View File
@@ -0,0 +1,51 @@
import { ActionRowBuilder, APIEmbedField, ButtonBuilder, ButtonStyle, EmbedBuilder, GuildMember, MessageActionRowComponentBuilder, time } from 'discord.js';
import { Database } from '../shared/Database';
import { Note } from '../types';
type MessageContent = { content: string, components: ActionRowBuilder<ButtonBuilder>[] };
const NOTES_PER_PAGE = 5;
function getNoteText(note: Note): string {
const timestamp = time(new Date(note.timestamp));
return `### Note by <@${note.mod_id}> (${timestamp}):\n${note.reason}`;
}
export async function getNoteMessage(userId: string, page: number): Promise<MessageContent | null> {
const notes = await Database.getNotes(userId);
page = page - 1;
const maxPage = Math.floor(notes.length / NOTES_PER_PAGE);
if (notes.length == 0) return null;
const noteTexts: string[] = [];
for (let i = page * NOTES_PER_PAGE; i < page * NOTES_PER_PAGE + NOTES_PER_PAGE; i++) {
if (i >= notes.length) break;
noteTexts.push(getNoteText(notes[i]));
}
const prevPage = new ButtonBuilder()
.setLabel('Previous Page')
.setCustomId(`note-previous_${userId}_${page + 1}`)
.setDisabled(page == 0)
.setStyle(ButtonStyle.Primary);
const nextPage = new ButtonBuilder()
.setLabel('Next Page')
.setCustomId(`note-next_${userId}_${page + 1}`)
.setDisabled(page >= maxPage)
.setStyle(ButtonStyle.Primary);
const row = new ActionRowBuilder<ButtonBuilder>()
.addComponents(prevPage, nextPage);
return {
content: `<@${userId}>'s Notes\n` + noteTexts.join('\n\n') + `\n\n-# Page ${page + 1}/${maxPage + 1}`,
components: [row]
};
}
-51
View File
@@ -1,51 +0,0 @@
import { ActionRowBuilder, APIEmbedField, ButtonBuilder, ButtonStyle, EmbedBuilder, GuildMember, MessageActionRowComponentBuilder, time } from 'discord.js';
import { Database } from '../shared/Database';
import { Warning } from '../types';
type MessageContent = { content: string, components: ActionRowBuilder<ButtonBuilder>[] };
const WARNINGS_PER_PAGE = 5;
function getWarningText(warning: Warning): string {
const timestamp = time(new Date(warning.timestamp));
return `### Warning from <@${warning.mod_id}> (${timestamp}):\n${warning.reason}`;
}
export async function getWarningMessage(userId: string, page: number): Promise<MessageContent | null> {
const warnings = await Database.getWarnings(userId);
page = page - 1;
const maxPage = Math.floor(warnings.length / WARNINGS_PER_PAGE);
if (warnings.length == 0) return null;
const warningTexts: string[] = [];
for (let i = page * WARNINGS_PER_PAGE; i < page * WARNINGS_PER_PAGE + WARNINGS_PER_PAGE; i++) {
if (i >= warnings.length) break;
warningTexts.push(getWarningText(warnings[i]));
}
const prevPage = new ButtonBuilder()
.setLabel('Previous Page')
.setCustomId(`warning-previous_${userId}_${page + 1}`)
.setDisabled(page == 0)
.setStyle(ButtonStyle.Primary);
const nextPage = new ButtonBuilder()
.setLabel('Next Page')
.setCustomId(`warning-next_${userId}_${page + 1}`)
.setDisabled(page >= maxPage)
.setStyle(ButtonStyle.Primary);
const row = new ActionRowBuilder<ButtonBuilder>()
.addComponents(prevPage, nextPage);
return {
content: `<@${userId}>'s Warnings\n` + warningTexts.join('\n\n') + `\n\n-# Page ${page + 1}/${maxPage + 1}`,
components: [row]
};
}