counters interface refactor complete, allowlists done
This commit is contained in:
parent
9c955be502
commit
77f6164e36
|
@ -6,7 +6,6 @@ exports.up = function(knex) {
|
|||
return knex.schema
|
||||
.createTable('counters', table => {
|
||||
table.string('key').notNullable();
|
||||
table.string('name').notNullable();
|
||||
table.string('emoji').notNullable();
|
||||
table.integer('value').defaultTo(0);
|
||||
table.string('channel').notNullable();
|
||||
|
|
|
@ -0,0 +1,313 @@
|
|||
import { Interaction, SlashCommandBuilder } from 'discord.js';
|
||||
import { Counter, CounterUserLink, db } from '../lib/db';
|
||||
import { counterAutocomplete, getCounterData, updateCounter } from '../lib/counter';
|
||||
|
||||
function extendOption(t: string) {
|
||||
return {name: t, value: t};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName('counter')
|
||||
.setDescription('[ADMIN] Counter management')
|
||||
.addSubcommandGroup(grp =>
|
||||
grp
|
||||
.setName('allowlist')
|
||||
.setDescription('[ADMIN] Counter allowlist management')
|
||||
.addSubcommand(sub =>
|
||||
sub
|
||||
.setName('add')
|
||||
.setDescription('[ADMIN] Add a user to the allowlist')
|
||||
.addStringOption(opt =>
|
||||
opt
|
||||
.setName('type')
|
||||
.setDescription('The counter to operate on')
|
||||
.setRequired(true)
|
||||
.setAutocomplete(true)
|
||||
)
|
||||
.addStringOption(opt =>
|
||||
opt
|
||||
.setName('usertype')
|
||||
.setDescription('Type of user in this predicament')
|
||||
.setChoices(...['consumer', 'producer'].map(extendOption))
|
||||
.setRequired(true)
|
||||
)
|
||||
.addUserOption(opt =>
|
||||
opt
|
||||
.setName('user')
|
||||
.setDescription('The user to add')
|
||||
.setRequired(true)
|
||||
)
|
||||
)
|
||||
.addSubcommand(sub =>
|
||||
sub
|
||||
.setName('remove')
|
||||
.setDescription('[ADMIN] Remove a user from the allowlist')
|
||||
.addStringOption(opt =>
|
||||
opt
|
||||
.setName('type')
|
||||
.setDescription('The counter to operate on')
|
||||
.setRequired(true)
|
||||
.setAutocomplete(true)
|
||||
)
|
||||
.addStringOption(opt =>
|
||||
opt
|
||||
.setName('usertype')
|
||||
.setDescription('Type of user in this predicament')
|
||||
.setChoices(...['consumer', 'producer'].map(extendOption))
|
||||
.setRequired(true)
|
||||
)
|
||||
.addUserOption(opt =>
|
||||
opt
|
||||
.setName('user')
|
||||
.setDescription('The user to remove')
|
||||
.setRequired(true)
|
||||
)
|
||||
)
|
||||
.addSubcommand(sub =>
|
||||
sub
|
||||
.setName('toggle')
|
||||
.setDescription('[ADMIN] Enable or disable the allowlist.')
|
||||
.addStringOption(opt =>
|
||||
opt
|
||||
.setName('type')
|
||||
.setDescription('The counter to operate on')
|
||||
.setRequired(true)
|
||||
.setAutocomplete(true)
|
||||
)
|
||||
.addStringOption(opt =>
|
||||
opt
|
||||
.setName('usertype')
|
||||
.setDescription('Type of user in this predicament')
|
||||
.setChoices(...['consumer', 'producer'].map(extendOption))
|
||||
.setRequired(true)
|
||||
)
|
||||
.addBooleanOption(opt =>
|
||||
opt
|
||||
.setName('enabled')
|
||||
.setDescription('Enable or disable the allowlist')
|
||||
.setRequired(true)
|
||||
)
|
||||
)
|
||||
.addSubcommand(sub =>
|
||||
sub
|
||||
.setName('list')
|
||||
.setDescription('[ADMIN] List people in the allowlist')
|
||||
.addStringOption(opt =>
|
||||
opt
|
||||
.setName('type')
|
||||
.setDescription('The counter to operate on')
|
||||
.setRequired(true)
|
||||
.setAutocomplete(true)
|
||||
)
|
||||
.addStringOption(opt =>
|
||||
opt
|
||||
.setName('usertype')
|
||||
.setDescription('Type of user in this predicament')
|
||||
.setChoices(...['consumer', 'producer'].map(extendOption))
|
||||
.setRequired(true)
|
||||
)
|
||||
)
|
||||
)
|
||||
.addSubcommand(sub =>
|
||||
sub
|
||||
.setName('create')
|
||||
.setDescription('[ADMIN] Create a counter')
|
||||
.addChannelOption(option =>
|
||||
option
|
||||
.setName('channel')
|
||||
.setDescription('Channel to put updates into')
|
||||
.setRequired(true)
|
||||
)
|
||||
.addStringOption(option =>
|
||||
option
|
||||
.setName('key')
|
||||
.setDescription('The codename. Best to leave descriptive for later; used in searching for counters')
|
||||
.setRequired(true)
|
||||
)
|
||||
.addStringOption(option =>
|
||||
option
|
||||
.setName('emoji')
|
||||
.setDescription('An emoji or symbol or something to represent the counter')
|
||||
.setMaxLength(32)
|
||||
.setRequired(true)
|
||||
)
|
||||
.addNumberOption(option =>
|
||||
option
|
||||
.setName('value')
|
||||
.setDescription('Initial value to start with')
|
||||
)
|
||||
)
|
||||
.addSubcommand(sub =>
|
||||
sub
|
||||
.setName('delete')
|
||||
.setDescription('[ADMIN] Delete a counter')
|
||||
.addStringOption(opt =>
|
||||
opt
|
||||
.setName('type')
|
||||
.setDescription('The counter to operate on')
|
||||
.setRequired(true)
|
||||
.setAutocomplete(true)
|
||||
)
|
||||
)
|
||||
.setDefaultMemberPermissions('0')
|
||||
.setDMPermission(false),
|
||||
|
||||
execute: async (interaction: Interaction) => {
|
||||
if (!interaction.isChatInputCommand()) return;
|
||||
|
||||
await interaction.deferReply({ephemeral: true});
|
||||
|
||||
const subcommand = interaction.options.getSubcommand(true);
|
||||
const group = interaction.options.getSubcommandGroup();
|
||||
|
||||
if (group === 'allowlist') {
|
||||
const type = interaction.options.getString('type')!;
|
||||
|
||||
let counter;
|
||||
try {
|
||||
counter = await getCounterData(type);
|
||||
} catch(err) {
|
||||
await interaction.followUp({
|
||||
content: 'No such counter!'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (subcommand === 'add') {
|
||||
const user = interaction.options.getUser('user', true);
|
||||
const userType = interaction.options.getString('usertype', true);
|
||||
|
||||
const link = await db<CounterUserLink>('counterUserLink')
|
||||
.where('key', type)
|
||||
.where('user', user.id)
|
||||
.where('producer', userType === 'producer')
|
||||
.first();
|
||||
|
||||
if (link) {
|
||||
await interaction.followUp({
|
||||
content: `<@${user.id}> is already in the ${counter.emoji} **${userType}** allowlist!`
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await db<CounterUserLink>('counterUserLink')
|
||||
.insert({
|
||||
'key': type,
|
||||
'user': user.id,
|
||||
'producer': userType === 'producer'
|
||||
});
|
||||
|
||||
await interaction.followUp({
|
||||
content: `<@${user.id}> added to the ${counter.emoji} **${userType}** allowlist.`
|
||||
});
|
||||
} else if (subcommand === 'remove') {
|
||||
const user = interaction.options.getUser('user', true);
|
||||
const userType = interaction.options.getString('usertype', true);
|
||||
|
||||
const link = await db<CounterUserLink>('counterUserLink')
|
||||
.where('key', type)
|
||||
.where('user', user.id)
|
||||
.where('producer', userType === 'producer')
|
||||
.first();
|
||||
|
||||
if (!link) {
|
||||
await interaction.followUp({
|
||||
content: `<@${user.id}> is not in the ${counter.emoji} **${userType}** allowlist!`
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await interaction.followUp({
|
||||
content: `<@${user.id}> has been removed from the ${counter.emoji} **${userType}** allowlist.`
|
||||
});
|
||||
} else if (subcommand === 'toggle') {
|
||||
const enabled = interaction.options.getBoolean('enabled', true);
|
||||
const userType = interaction.options.getString('usertype', true);
|
||||
|
||||
if (userType === 'producer') {
|
||||
await db<Counter>('counters')
|
||||
.where('key', type)
|
||||
.update({
|
||||
'allowlistProducer': enabled
|
||||
});
|
||||
} else {
|
||||
await db<Counter>('counters')
|
||||
.where('key', type)
|
||||
.update({
|
||||
'allowlistProducer': enabled
|
||||
});
|
||||
}
|
||||
|
||||
await interaction.followUp({
|
||||
content: `${counter.emoji} ${userType.slice(0, 1).toUpperCase() + userType.slice(1)} allowlist is now **${enabled ? 'enabled' : 'disabled'}**.`
|
||||
});
|
||||
} else if (subcommand === 'list') {
|
||||
const userType = interaction.options.getString('usertype', true);
|
||||
|
||||
const users = await db<CounterUserLink>('counterUserLink')
|
||||
.where('key', type)
|
||||
.where('producer', userType === 'producer');
|
||||
|
||||
const enabled = (userType === 'producer') ? counter.allowlistProducer : counter.allowlistConsumer;
|
||||
|
||||
await interaction.followUp({
|
||||
content: `${counter.emoji} ${userType.slice(0, 1).toUpperCase() + userType.slice(1)}s:\n${users.map(u => `- <@${u.user}>`)}\nThe ${userType} allowlist is currently **${enabled ? 'enabled' : 'disabled'}**.`
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (subcommand === 'create') {
|
||||
const channel = interaction.options.getChannel('channel', true);
|
||||
const key = interaction.options.getString('key', true);
|
||||
const emoji = interaction.options.getString('emoji', true);
|
||||
const value = interaction.options.getNumber('value') || 0;
|
||||
const guild = interaction.guildId!;
|
||||
|
||||
await db<Counter>('counters')
|
||||
.insert({
|
||||
'key': key,
|
||||
'emoji': emoji,
|
||||
'value': value,
|
||||
'channel': channel.id,
|
||||
'guild': guild
|
||||
});
|
||||
|
||||
const counter = await db<Counter>('counters')
|
||||
.where('key', key)
|
||||
.first();
|
||||
|
||||
await updateCounter(interaction.client, counter!, value);
|
||||
|
||||
await interaction.followUp({
|
||||
content: `<#${channel.id}> has been **enriched** with your new counter. Congratulations!`
|
||||
});
|
||||
} else if (subcommand === 'delete') {
|
||||
const type = interaction.options.getString('type')!;
|
||||
|
||||
let counter;
|
||||
try {
|
||||
counter = await getCounterData(type);
|
||||
} catch(err) {
|
||||
await interaction.followUp({
|
||||
content: 'No such counter!'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await db<Counter>('counters')
|
||||
.where('key', type)
|
||||
.delete();
|
||||
|
||||
await db<CounterUserLink>('counterUserLink')
|
||||
.where('key', type)
|
||||
.delete();
|
||||
|
||||
await interaction.followUp({
|
||||
content: `The ${counter.emoji} counter has been removed. 😭`
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
autocomplete: counterAutocomplete
|
||||
};
|
|
@ -1,68 +0,0 @@
|
|||
import { Interaction, SlashCommandBuilder } from 'discord.js';
|
||||
import { Counter, db } from '../lib/db';
|
||||
import { updateCounter } from '../lib/counter';
|
||||
|
||||
module.exports = {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName('createcounter')
|
||||
.setDescription('[ADMIN] Create a counter in this channel')
|
||||
.addStringOption(option =>
|
||||
option
|
||||
.setName('key')
|
||||
.setDescription('The codename. Best to leave descriptive for later')
|
||||
.setRequired(true)
|
||||
)
|
||||
.addStringOption(option =>
|
||||
option
|
||||
.setName('name')
|
||||
.setDescription('The name, anything goes')
|
||||
.setRequired(true)
|
||||
)
|
||||
.addStringOption(option =>
|
||||
option
|
||||
.setName('emoji')
|
||||
.setDescription('An emoji or symbol or something to represent the counter')
|
||||
.setMaxLength(10)
|
||||
.setRequired(true)
|
||||
)
|
||||
.addNumberOption(option =>
|
||||
option
|
||||
.setName('value')
|
||||
.setDescription('Initial value to start with')
|
||||
)
|
||||
.setDefaultMemberPermissions('0')
|
||||
.setDMPermission(false),
|
||||
|
||||
execute: async (interaction: Interaction) => {
|
||||
if (!interaction.isChatInputCommand()) return;
|
||||
|
||||
await interaction.deferReply({ephemeral: true});
|
||||
|
||||
const key = interaction.options.getString('key')!;
|
||||
const name = interaction.options.getString('name')!;
|
||||
const emoji = interaction.options.getString('emoji')!;
|
||||
const value = interaction.options.getNumber('value') || 0;
|
||||
const channel = interaction.channelId;
|
||||
const guild = interaction.guildId!;
|
||||
|
||||
await db<Counter>('counters')
|
||||
.insert({
|
||||
'key': key,
|
||||
'name': name,
|
||||
'emoji': emoji,
|
||||
'value': value,
|
||||
'channel': channel,
|
||||
'guild': guild
|
||||
});
|
||||
|
||||
const counter = await db<Counter>('counters')
|
||||
.where('key', key)
|
||||
.first();
|
||||
|
||||
await updateCounter(interaction.client, counter!, value);
|
||||
|
||||
await interaction.followUp({
|
||||
content: `<#${interaction.channelId}> has been **enriched** with your new counter. Congratulations!`
|
||||
});
|
||||
}
|
||||
};
|
|
@ -1,6 +1,6 @@
|
|||
import { Client, CommandInteraction, GuildMember, EmbedBuilder, TextChannel, AutocompleteInteraction } from 'discord.js';
|
||||
import { getSign } from './util';
|
||||
import { Counter, db } from './db';
|
||||
import { Counter, CounterUserLink, db } from './db';
|
||||
|
||||
export async function getCounter(type: string) {
|
||||
const counter = await db<Counter>('counters')
|
||||
|
@ -88,14 +88,41 @@ export async function changeCounterInteraction(interaction: CommandInteraction,
|
|||
try {
|
||||
const counter = await getCounterData(type);
|
||||
|
||||
let canUse = true;
|
||||
if (amount > 0 && counter.allowlistProducer) {
|
||||
const userLink = await db<CounterUserLink>('counterUserLink')
|
||||
.where('key', type)
|
||||
.where('user', member.id)
|
||||
.where('producer', true)
|
||||
.first();
|
||||
|
||||
if (!userLink) canUse = false;
|
||||
}
|
||||
if (amount < 0 && counter.allowlistConsumer) {
|
||||
const userLink = await db<CounterUserLink>('counterUserLink')
|
||||
.where('key', type)
|
||||
.where('user', member.id)
|
||||
.where('producer', false)
|
||||
.first();
|
||||
|
||||
if (!userLink) canUse = false;
|
||||
}
|
||||
|
||||
if (!canUse) {
|
||||
await interaction.followUp({
|
||||
content: `You cannot **${amount > 0 ? 'produce' : 'consume'}** ${counter.emoji}.`
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const newCount = await changeCounter(amount, type);
|
||||
await updateCounter(interaction.client, counter, newCount);
|
||||
await announceCounterUpdate(interaction.client, member, amount, counter, newCount);
|
||||
interaction.followUp({
|
||||
await interaction.followUp({
|
||||
content: `${counter.emoji} **You have ${amount > 0 ? 'increased' : 'decreased'} the counter.**\n\`\`\`diff\n ${newCount - amount}\n${getSign(amount)}${Math.abs(amount)}\n ${newCount}\`\`\``
|
||||
});
|
||||
} catch(err) {
|
||||
interaction.followUp({
|
||||
await interaction.followUp({
|
||||
content: (err as Error).toString()
|
||||
});
|
||||
}
|
||||
|
@ -106,8 +133,8 @@ export async function counterAutocomplete(interaction: AutocompleteInteraction)
|
|||
const guild = interaction.guildId;
|
||||
|
||||
const query = db<Counter>('counters')
|
||||
.select('name', 'key')
|
||||
.whereLike('name', `%${focusedValue.toLowerCase()}%`)
|
||||
.select('emoji', 'key')
|
||||
.whereLike('key', `%${focusedValue.toLowerCase()}%`)
|
||||
.limit(25);
|
||||
|
||||
if (guild) {
|
||||
|
@ -117,6 +144,6 @@ export async function counterAutocomplete(interaction: AutocompleteInteraction)
|
|||
const foundCounters = await query;
|
||||
|
||||
await interaction.respond(
|
||||
foundCounters.map(choice => ({ name: choice.name, value: choice.key }))
|
||||
foundCounters.map(choice => ({ name: choice.emoji, value: choice.key }))
|
||||
);
|
||||
}
|
|
@ -26,7 +26,6 @@ export interface Subscription {
|
|||
}
|
||||
export interface Counter {
|
||||
key: string,
|
||||
name: string,
|
||||
emoji: string,
|
||||
value: number,
|
||||
channel: string,
|
||||
|
|
Loading…
Reference in New Issue