Files
Papo/src/commands/utility/gallery.ts
Pepe44DEV aa246cd7ea
Some checks failed
Deploy Discord Bot / deploy (push) Failing after -1m12s
SonarQube / sonar (push) Successful in 4s
add badges, weekly plans, polls, suggestions, mod-case system, branding, partner system, alt-account detection, gallery, growth tracking
Two feature batches plus a deploy fix:

Moderation & engagement: persistent ModCase history (retrofits ban/kick/
mute/timeout/tempban to record cases), /warn, /watch watchlist with
automatic alerts on deletions/tickets/automod hits, /case file lookup,
achievement badges (/badges, /profile) with message/streak/ticket/
birthday/event/booster triggers, /weekplan RSVP boards, /poll with
anonymous mode and scheduled auto-close, /suggest with vote/comment/
decide flow.

Branding & growth: /branding (per-guild embed color/logo/footer/bot
name/theme, applied across logging/ticket/register/embed-builder
embeds and the dashboard sidebar/accent color at runtime), two new
/setup server-type presets (Roleplay, Creator), /rules generate
(template-based rule sets), /partner apply/list/config with invite
validation and showcase posting, alt-account suspicion scoring on
join (account age, avatar, name pattern, join bursts, ban-list
similarity), /gallery submit with voting and weekly-winner scheduler,
invite-attributed join/leave tracking with a new Wachstum dashboard
page, and an expanded Admin dashboard (guild list, feature-usage
counters).

Also fixes production: the Docker container never ran `prisma migrate
deploy`, so schema changes never reached the live database. The
compose command now applies pending migrations on every start.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-03 23:15:35 +02:00

57 lines
2.3 KiB
TypeScript

import { ChannelType, ChatInputCommandInteraction, PermissionFlagsBits, SlashCommandBuilder } from 'discord.js';
import { SlashCommand } from '../../utils/types';
import { context } from '../../config/context';
import { settingsStore } from '../../config/state';
const command: SlashCommand = {
guildOnly: true,
data: new SlashCommandBuilder()
.setName('gallery')
.setDescription('Screenshot-/Kunst-Galerie.')
.addSubcommand((sub) =>
sub
.setName('submit')
.setDescription('Reicht ein Bild für die Galerie ein.')
.addAttachmentOption((opt) => opt.setName('image').setDescription('Bild').setRequired(true))
.addStringOption((opt) => opt.setName('caption').setDescription('Beschreibung'))
)
.addSubcommand((sub) =>
sub
.setName('config')
.setDescription('Konfiguriert Galerie-Kanal und Künstler-Rolle.')
.addChannelOption((opt) => opt.setName('channel').setDescription('Galerie-Kanal').addChannelTypes(ChannelType.GuildText))
.addRoleOption((opt) => opt.setName('artist_role').setDescription('Rolle für Künstler'))
),
async execute(interaction: ChatInputCommandInteraction) {
if (!interaction.guildId) return;
const sub = interaction.options.getSubcommand();
if (sub === 'submit') {
const attachment = interaction.options.getAttachment('image', true);
const caption = interaction.options.getString('caption') ?? undefined;
await context.gallery.submit(interaction, attachment, caption);
return;
}
if (sub === 'config') {
if (!interaction.memberPermissions?.has(PermissionFlagsBits.ManageGuild)) {
await interaction.reply({ content: 'Du benötigst die Berechtigung "Server verwalten".', ephemeral: true });
return;
}
const channel = interaction.options.getChannel('channel');
const role = interaction.options.getRole('artist_role');
const current = settingsStore.get(interaction.guildId)?.galleryConfig || {};
await settingsStore.set(interaction.guildId, {
galleryConfig: {
channelId: channel?.id ?? current.channelId,
artistRoleId: role?.id ?? current.artistRoleId,
lastWinnerAt: current.lastWinnerAt
}
});
await interaction.reply({ content: 'Galerie-Konfiguration aktualisiert.', ephemeral: true });
}
}
};
export default command;