Implement leveling and economy features with associated models and commands

- Added new models for leveling and economy functionalities in the Prisma schema, including LevelingConfig, MemberLevel, LevelReward, EconomyConfig, MemberEconomy, ShopItem, and InventoryItem.
- Introduced commands for managing XP, economy transactions, and shop interactions, enhancing user engagement.
- Updated job handling to include reminders and poll closing functionalities.
- Enhanced localization support for new commands and features in both German and English.
- Improved the bot's job processing capabilities with a dedicated reminder worker for scheduled tasks.
This commit is contained in:
smueller
2026-07-22 12:49:17 +02:00
parent 2518119257
commit fa5910ec43
38 changed files with 6759 additions and 144 deletions

View File

@@ -0,0 +1,186 @@
import {
SlashCommandBuilder,
type SlashCommandAttachmentOption,
type SlashCommandBooleanOption,
type SlashCommandChannelOption,
type SlashCommandRoleOption,
type SlashCommandStringOption,
type SlashCommandUserOption
} from 'discord.js';
import {
applyCommandDescription,
applyOptionDescription,
type CommandLocaleKey
} from '@nexumi/shared';
function userOpt(o: SlashCommandUserOption, key: CommandLocaleKey = 'utility.common.options.userOptional') {
return applyOptionDescription(o.setName('user'), key);
}
function channelOpt(o: SlashCommandChannelOption) {
return applyOptionDescription(o.setName('channel'), 'utility.common.options.channelOptional');
}
function roleOpt(o: SlashCommandRoleOption) {
return applyOptionDescription(o.setName('role').setRequired(true), 'utility.roleinfo.options.role');
}
function attachmentOpt(o: SlashCommandAttachmentOption) {
return applyOptionDescription(o.setName('attachment'), 'utility.common.options.attachment');
}
function urlOpt(o: SlashCommandStringOption, key: CommandLocaleKey = 'utility.common.options.url') {
return applyOptionDescription(o.setName('url'), key);
}
function nameOpt(o: SlashCommandStringOption, required = true) {
const option = o.setName('name');
if (required) {
option.setRequired(true);
}
return applyOptionDescription(option, 'utility.common.options.name');
}
export const userinfoCommandData = applyCommandDescription(
new SlashCommandBuilder().setName('userinfo'),
'utility.userinfo.description'
).addUserOption((o) => userOpt(o));
export const serverinfoCommandData = applyCommandDescription(
new SlashCommandBuilder().setName('serverinfo'),
'utility.serverinfo.description'
);
export const roleinfoCommandData = applyCommandDescription(
new SlashCommandBuilder().setName('roleinfo'),
'utility.roleinfo.description'
).addRoleOption((o) => roleOpt(o));
export const channelinfoCommandData = applyCommandDescription(
new SlashCommandBuilder().setName('channelinfo'),
'utility.channelinfo.description'
).addChannelOption((o) => channelOpt(o));
export const avatarCommandData = applyCommandDescription(
new SlashCommandBuilder().setName('avatar'),
'utility.avatar.description'
).addUserOption((o) => userOpt(o));
export const bannerCommandData = applyCommandDescription(
new SlashCommandBuilder().setName('banner'),
'utility.banner.description'
).addUserOption((o) => userOpt(o));
export const pollCommandData = applyCommandDescription(
new SlashCommandBuilder().setName('poll'),
'utility.poll.description'
).addSubcommand((s) =>
applyCommandDescription(s.setName('create'), 'utility.poll.create.description')
.addStringOption((o) =>
applyOptionDescription(o.setName('question').setRequired(true), 'utility.poll.options.question')
)
.addStringOption((o) =>
applyOptionDescription(o.setName('options').setRequired(true), 'utility.poll.options.options')
)
.addBooleanOption((o) =>
applyOptionDescription(o.setName('multiselect'), 'utility.poll.options.multiselect')
)
.addBooleanOption((o) =>
applyOptionDescription(o.setName('anonymous'), 'utility.poll.options.anonymous')
)
.addStringOption((o) =>
applyOptionDescription(o.setName('duration'), 'utility.poll.options.duration')
)
);
export const remindmeCommandData = applyCommandDescription(
new SlashCommandBuilder().setName('remindme'),
'utility.remindme.description'
)
.addStringOption((o) =>
applyOptionDescription(o.setName('when').setRequired(true), 'utility.remindme.options.when')
)
.addStringOption((o) =>
applyOptionDescription(o.setName('content').setRequired(true), 'utility.remindme.options.content')
)
.addStringOption((o) =>
applyOptionDescription(o.setName('recurring_cron'), 'utility.remindme.options.recurring_cron')
);
export const remindersCommandData = applyCommandDescription(
new SlashCommandBuilder().setName('reminders'),
'utility.reminders.description'
)
.addSubcommand((s) =>
applyCommandDescription(s.setName('list'), 'utility.reminders.list.description')
)
.addSubcommand((s) =>
applyCommandDescription(s.setName('delete'), 'utility.reminders.delete.description').addStringOption(
(o) =>
applyOptionDescription(o.setName('id').setRequired(true), 'utility.reminders.options.id')
)
);
export const afkCommandData = applyCommandDescription(
new SlashCommandBuilder().setName('afk'),
'utility.afk.description'
).addSubcommand((s) =>
applyCommandDescription(s.setName('set'), 'utility.afk.set.description').addStringOption((o) =>
applyOptionDescription(o.setName('reason'), 'utility.afk.options.reason')
)
);
export const emojiCommandData = applyCommandDescription(
new SlashCommandBuilder().setName('emoji'),
'utility.emoji.description'
)
.addSubcommand((s) =>
applyCommandDescription(s.setName('add'), 'utility.emoji.add.description')
.addStringOption((o) => nameOpt(o))
.addAttachmentOption((o) => attachmentOpt(o))
.addStringOption((o) => urlOpt(o, 'utility.emoji.options.url'))
)
.addSubcommand((s) =>
applyCommandDescription(s.setName('remove'), 'utility.emoji.remove.description').addStringOption((o) =>
applyOptionDescription(o.setName('emoji').setRequired(true), 'utility.emoji.options.emoji')
)
)
.addSubcommand((s) =>
applyCommandDescription(s.setName('steal'), 'utility.emoji.steal.description').addStringOption((o) =>
applyOptionDescription(o.setName('message_id').setRequired(true), 'utility.emoji.options.message_id')
)
);
export const stickerCommandData = applyCommandDescription(
new SlashCommandBuilder().setName('sticker'),
'utility.sticker.description'
).addSubcommand((s) =>
applyCommandDescription(s.setName('add'), 'utility.sticker.add.description')
.addStringOption((o) => nameOpt(o))
.addAttachmentOption((o) => attachmentOpt(o))
.addStringOption((o) => urlOpt(o, 'utility.sticker.options.url'))
);
export const timestampCommandData = applyCommandDescription(
new SlashCommandBuilder().setName('timestamp'),
'utility.timestamp.description'
).addStringOption((o) =>
applyOptionDescription(o.setName('datetime').setRequired(true), 'utility.timestamp.options.datetime')
);
export const snipeCommandData = applyCommandDescription(
new SlashCommandBuilder().setName('snipe'),
'utility.snipe.description'
);
export const editsnipeCommandData = applyCommandDescription(
new SlashCommandBuilder().setName('editsnipe'),
'utility.editsnipe.description'
);
export const embedCommandData = applyCommandDescription(
new SlashCommandBuilder().setName('embed'),
'utility.embed.description'
).addSubcommand((s) =>
applyCommandDescription(s.setName('builder'), 'utility.embed.builder.description')
);