feat: make /stopwatch status public & restrict start/stop to mods
All checks were successful
Auto Build and Push Docker Image / build (push) Successful in 7s
All checks were successful
Auto Build and Push Docker Image / build (push) Successful in 7s
This commit is contained in:
@@ -90,10 +90,10 @@ npm run deploy
|
|||||||
- `/timer help` – Timer-Hilfe
|
- `/timer help` – Timer-Hilfe
|
||||||
|
|
||||||
### Stoppuhr (Hochzählender Timer)
|
### Stoppuhr (Hochzählender Timer)
|
||||||
- `/stopwatch start <name> [startzeit]` – Startet eine neue Stoppuhr mit Namen (optional mit vergangener Startzeit z.B. `14:30`, `2h`)
|
- `/stopwatch start <name> [startzeit]` – Startet eine neue Stoppuhr mit Namen (Mod)
|
||||||
- `/stopwatch status [name]` – Abgelaufene Zeit abfragen
|
- `/stopwatch status [name]` – Abgelaufene Zeit öffentlich abfragen (Für alle sichtbar)
|
||||||
- `/stopwatch stop <name>` – Stoppuhr beenden & Laufzeit ausgeben
|
- `/stopwatch stop <name>` – Stoppuhr beenden & Laufzeit ausgeben (Mod)
|
||||||
- `/stopwatch list` – Aktive Stoppuhren auflisten
|
- `/stopwatch list` – Aktive Stoppuhren des Servers öffentlich auflisten (Für alle sichtbar)
|
||||||
- `/stopwatch help` – Stoppuhr-Hilfe
|
- `/stopwatch help` – Stoppuhr-Hilfe
|
||||||
|
|
||||||
### Trigger (Auto-Antworten)
|
### Trigger (Auto-Antworten)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { SlashCommandBuilder, EmbedBuilder } from 'discord.js';
|
import { SlashCommandBuilder, EmbedBuilder, PermissionFlagsBits } from 'discord.js';
|
||||||
import { Command } from '../../structures/Command.js';
|
import { Command } from '../../structures/Command.js';
|
||||||
import { ExtendedClient } from '../../structures/ExtendedClient.js';
|
import { ExtendedClient } from '../../structures/ExtendedClient.js';
|
||||||
|
|
||||||
@@ -92,7 +92,7 @@ const command: Command = {
|
|||||||
.addSubcommand(subcommand =>
|
.addSubcommand(subcommand =>
|
||||||
subcommand
|
subcommand
|
||||||
.setName('start')
|
.setName('start')
|
||||||
.setDescription('Startet eine neue Stoppuhr.')
|
.setDescription('Startet eine neue Stoppuhr (Nur für Moderatoren).')
|
||||||
.addStringOption(option =>
|
.addStringOption(option =>
|
||||||
option.setName('name')
|
option.setName('name')
|
||||||
.setDescription('Der Name der Stoppuhr (z.B. "Gaming", "Lernen")')
|
.setDescription('Der Name der Stoppuhr (z.B. "Gaming", "Lernen")')
|
||||||
@@ -104,7 +104,7 @@ const command: Command = {
|
|||||||
.addSubcommand(subcommand =>
|
.addSubcommand(subcommand =>
|
||||||
subcommand
|
subcommand
|
||||||
.setName('status')
|
.setName('status')
|
||||||
.setDescription('Zeigt den aktuellen Stand einer oder aller Stoppuhren an.')
|
.setDescription('Zeigt den aktuellen Stand einer oder aller Stoppuhren öffentlich an.')
|
||||||
.addStringOption(option =>
|
.addStringOption(option =>
|
||||||
option.setName('name')
|
option.setName('name')
|
||||||
.setDescription('Der Name der Stoppuhr (optional)')
|
.setDescription('Der Name der Stoppuhr (optional)')
|
||||||
@@ -112,7 +112,7 @@ const command: Command = {
|
|||||||
.addSubcommand(subcommand =>
|
.addSubcommand(subcommand =>
|
||||||
subcommand
|
subcommand
|
||||||
.setName('stop')
|
.setName('stop')
|
||||||
.setDescription('Stoppt eine laufende Stoppuhr.')
|
.setDescription('Stoppt eine laufende Stoppuhr (Nur für Moderatoren).')
|
||||||
.addStringOption(option =>
|
.addStringOption(option =>
|
||||||
option.setName('name')
|
option.setName('name')
|
||||||
.setDescription('Der Name der zu stoppenden Stoppuhr')
|
.setDescription('Der Name der zu stoppenden Stoppuhr')
|
||||||
@@ -120,7 +120,7 @@ const command: Command = {
|
|||||||
.addSubcommand(subcommand =>
|
.addSubcommand(subcommand =>
|
||||||
subcommand
|
subcommand
|
||||||
.setName('list')
|
.setName('list')
|
||||||
.setDescription('Listet alle deine aktiven Stoppuhren auf.'))
|
.setDescription('Listet alle aktiven Stoppuhren auf diesem Server öffentlich auf.'))
|
||||||
.addSubcommand(subcommand =>
|
.addSubcommand(subcommand =>
|
||||||
subcommand
|
subcommand
|
||||||
.setName('help')
|
.setName('help')
|
||||||
@@ -135,17 +135,21 @@ const command: Command = {
|
|||||||
const channelId = interaction.channelId;
|
const channelId = interaction.channelId;
|
||||||
const DB = client.DB;
|
const DB = client.DB;
|
||||||
|
|
||||||
|
const isMod = interaction.memberPermissions?.has(PermissionFlagsBits.ModerateMembers) ||
|
||||||
|
interaction.memberPermissions?.has(PermissionFlagsBits.ManageGuild) ||
|
||||||
|
interaction.memberPermissions?.has(PermissionFlagsBits.Administrator);
|
||||||
|
|
||||||
if (subcommand === 'help') {
|
if (subcommand === 'help') {
|
||||||
const embed = new EmbedBuilder()
|
const embed = new EmbedBuilder()
|
||||||
.setTitle('⏱️ Stoppuhr Hilfe')
|
.setTitle('⏱️ Stoppuhr Hilfe')
|
||||||
.setColor(0x3498db)
|
.setColor(0x3498db)
|
||||||
.setDescription('Verwalte hochzählende Timer (Stoppuhren).')
|
.setDescription('Verwalte hochzählende Timer (Stoppuhren). Status und Abfragen sind für alle Mitglieder öffentlich sichtbar.')
|
||||||
.addFields(
|
.addFields(
|
||||||
{ name: '`/stopwatch start <name> [startzeit]`', value: 'Startet eine neue Stoppuhr mit Namen.\nOptional kann eine vergangene Startzeit angegeben werden (z.B. `14:30`, `03.08.2026 14:30` oder `2h`).', inline: false },
|
{ name: '`/stopwatch start <name> [startzeit]` 🛡️', value: '*(Mods/Admins)* Startet eine neue Stoppuhr mit Namen.\nOptional kann eine vergangene Startzeit angegeben werden (z.B. `14:30`, `03.08.2026 14:30` oder `2h`).', inline: false },
|
||||||
{ name: '`/stopwatch status [name]`', value: 'Zeigt die aktuelle Laufzeit einer oder aller Stoppuhren an.', inline: false },
|
{ name: '`/stopwatch status [name]` 📢', value: '*(Für alle sichtbar)* Zeigt die aktuelle Laufzeit einer oder aller Stoppuhren öffentlich im Kanal an.', inline: false },
|
||||||
{ name: '`/stopwatch stop <name>`', value: 'Stoppt eine Stoppuhr und gibt die finale Laufzeit aus.', inline: false },
|
{ name: '`/stopwatch stop <name>` 🛡️', value: '*(Mods/Admins)* Stoppt eine Stoppuhr und gibt die finale Laufzeit aus.', inline: false },
|
||||||
{ name: '`/stopwatch list`', value: 'Listet alle deine aktiven Stoppuhren auf diesem Server auf.', inline: false },
|
{ name: '`/stopwatch list` 📢', value: '*(Für alle sichtbar)* Listet alle aktiven Stoppuhren auf diesem Server öffentlich auf.', inline: false },
|
||||||
{ name: 'Beispiele', value: '`/stopwatch start name: Zocksession`\n`/stopwatch start name: Lernen startzeit: 14:00`\n`/stopwatch start name: Workout startzeit: 30m`\n`/stopwatch status name: Zocksession`\n`/stopwatch stop name: Zocksession`', inline: false }
|
{ name: 'Beispiele', value: '`/stopwatch start name: Zocksession`\n`/stopwatch start name: Lernen startzeit: 14:00`\n`/stopwatch status name: Zocksession`\n`/stopwatch stop name: Zocksession`', inline: false }
|
||||||
)
|
)
|
||||||
.setTimestamp();
|
.setTimestamp();
|
||||||
|
|
||||||
@@ -154,14 +158,21 @@ const command: Command = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (subcommand === 'start') {
|
if (subcommand === 'start') {
|
||||||
|
if (!isMod) {
|
||||||
|
await interaction.reply({
|
||||||
|
content: '❌ Du benötigst Moderations-Berechtigungen (z.B. Mitglieder verwalten / Server verwalten), um Stoppuhren zu starten.',
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const name = interaction.options.getString('name')!.trim();
|
const name = interaction.options.getString('name')!.trim();
|
||||||
const startInput = interaction.options.getString('startzeit')?.trim();
|
const startInput = interaction.options.getString('startzeit')?.trim();
|
||||||
|
|
||||||
// Duplicate check (case-insensitive)
|
// Duplicate check on this guild (case-insensitive)
|
||||||
const existing: any = DB.get(
|
const existing: any = DB.get(
|
||||||
'SELECT * FROM stopwatches WHERE guild_id = ? AND user_id = ? AND LOWER(name) = ?',
|
'SELECT * FROM stopwatches WHERE guild_id = ? AND LOWER(name) = ?',
|
||||||
guildId,
|
guildId,
|
||||||
userId,
|
|
||||||
name.toLowerCase()
|
name.toLowerCase()
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -169,7 +180,7 @@ const command: Command = {
|
|||||||
const startTime = new Date(existing.start_time);
|
const startTime = new Date(existing.start_time);
|
||||||
const unixTs = Math.floor(startTime.getTime() / 1000);
|
const unixTs = Math.floor(startTime.getTime() / 1000);
|
||||||
await interaction.reply({
|
await interaction.reply({
|
||||||
content: `⚠️ Du hast bereits eine Stoppuhr namens **"${existing.name}"** laufen (gestartet <t:${unixTs}:R>).\nNutze \`/stopwatch status name:${existing.name}\` oder \`/stopwatch stop name:${existing.name}\`.`,
|
content: `⚠️ Es gibt auf diesem Server bereits eine Stoppuhr namens **"${existing.name}"** (gestartet <t:${unixTs}:R>).\nNutze \`/stopwatch status name:${existing.name}\` oder \`/stopwatch stop name:${existing.name}\`.`,
|
||||||
ephemeral: true
|
ephemeral: true
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@@ -218,7 +229,7 @@ const command: Command = {
|
|||||||
)
|
)
|
||||||
.setTimestamp();
|
.setTimestamp();
|
||||||
|
|
||||||
await interaction.reply({ embeds: [embed], ephemeral: true });
|
await interaction.reply({ embeds: [embed], ephemeral: false });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,15 +238,14 @@ const command: Command = {
|
|||||||
|
|
||||||
if (name) {
|
if (name) {
|
||||||
const sw: any = DB.get(
|
const sw: any = DB.get(
|
||||||
'SELECT * FROM stopwatches WHERE guild_id = ? AND user_id = ? AND LOWER(name) = ?',
|
'SELECT * FROM stopwatches WHERE guild_id = ? AND LOWER(name) = ?',
|
||||||
guildId,
|
guildId,
|
||||||
userId,
|
|
||||||
name.toLowerCase()
|
name.toLowerCase()
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!sw) {
|
if (!sw) {
|
||||||
await interaction.reply({
|
await interaction.reply({
|
||||||
content: `❌ Keine aktive Stoppuhr namens **"${name}"** gefunden.`,
|
content: `❌ Keine aktive Stoppuhr namens **"${name}"** auf diesem Server gefunden.`,
|
||||||
ephemeral: true
|
ephemeral: true
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@@ -255,18 +265,18 @@ const command: Command = {
|
|||||||
)
|
)
|
||||||
.setTimestamp();
|
.setTimestamp();
|
||||||
|
|
||||||
await interaction.reply({ embeds: [embed], ephemeral: true });
|
// Public output for status query
|
||||||
|
await interaction.reply({ embeds: [embed], ephemeral: false });
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
const stopwatches: any[] = DB.all(
|
const stopwatches: any[] = DB.all(
|
||||||
'SELECT * FROM stopwatches WHERE guild_id = ? AND user_id = ? ORDER BY start_time ASC',
|
'SELECT * FROM stopwatches WHERE guild_id = ? ORDER BY start_time ASC',
|
||||||
guildId,
|
guildId
|
||||||
userId
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (stopwatches.length === 0) {
|
if (stopwatches.length === 0) {
|
||||||
await interaction.reply({
|
await interaction.reply({
|
||||||
content: 'ℹ️ Du hast aktuell keine aktiven Stoppuhren.',
|
content: 'ℹ️ Auf diesem Server gibt es aktuell keine aktiven Stoppuhren.',
|
||||||
ephemeral: true
|
ephemeral: true
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@@ -281,29 +291,37 @@ const command: Command = {
|
|||||||
}).join('\n');
|
}).join('\n');
|
||||||
|
|
||||||
const embed = new EmbedBuilder()
|
const embed = new EmbedBuilder()
|
||||||
.setTitle(`⏱️ Deine aktiven Stoppuhren (${stopwatches.length})`)
|
.setTitle(`⏱️ Aktive Stoppuhren auf diesem Server (${stopwatches.length})`)
|
||||||
.setColor(0x3498db)
|
.setColor(0x3498db)
|
||||||
.setDescription(listStr)
|
.setDescription(listStr)
|
||||||
.setTimestamp();
|
.setTimestamp();
|
||||||
|
|
||||||
await interaction.reply({ embeds: [embed], ephemeral: true });
|
// Public output for list query
|
||||||
|
await interaction.reply({ embeds: [embed], ephemeral: false });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subcommand === 'stop') {
|
if (subcommand === 'stop') {
|
||||||
|
if (!isMod) {
|
||||||
|
await interaction.reply({
|
||||||
|
content: '❌ Du benötigst Moderations-Berechtigungen (z.B. Mitglieder verwalten / Server verwalten), um Stoppuhren zu stoppen.',
|
||||||
|
ephemeral: true
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const name = interaction.options.getString('name')!.trim();
|
const name = interaction.options.getString('name')!.trim();
|
||||||
|
|
||||||
const sw: any = DB.get(
|
const sw: any = DB.get(
|
||||||
'SELECT * FROM stopwatches WHERE guild_id = ? AND user_id = ? AND LOWER(name) = ?',
|
'SELECT * FROM stopwatches WHERE guild_id = ? AND LOWER(name) = ?',
|
||||||
guildId,
|
guildId,
|
||||||
userId,
|
|
||||||
name.toLowerCase()
|
name.toLowerCase()
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!sw) {
|
if (!sw) {
|
||||||
await interaction.reply({
|
await interaction.reply({
|
||||||
content: `❌ Keine aktive Stoppuhr namens **"${name}"** gefunden.`,
|
content: `❌ Keine aktive Stoppuhr namens **"${name}"** auf diesem Server gefunden.`,
|
||||||
ephemeral: true
|
ephemeral: true
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@@ -326,20 +344,19 @@ const command: Command = {
|
|||||||
)
|
)
|
||||||
.setTimestamp();
|
.setTimestamp();
|
||||||
|
|
||||||
await interaction.reply({ embeds: [embed], ephemeral: true });
|
await interaction.reply({ embeds: [embed], ephemeral: false });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subcommand === 'list') {
|
if (subcommand === 'list') {
|
||||||
const stopwatches: any[] = DB.all(
|
const stopwatches: any[] = DB.all(
|
||||||
'SELECT * FROM stopwatches WHERE guild_id = ? AND user_id = ? ORDER BY start_time ASC',
|
'SELECT * FROM stopwatches WHERE guild_id = ? ORDER BY start_time ASC',
|
||||||
guildId,
|
guildId
|
||||||
userId
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (stopwatches.length === 0) {
|
if (stopwatches.length === 0) {
|
||||||
await interaction.reply({
|
await interaction.reply({
|
||||||
content: 'ℹ️ Du hast aktuell keine aktiven Stoppuhren.',
|
content: 'ℹ️ Auf diesem Server gibt es aktuell keine aktiven Stoppuhren.',
|
||||||
ephemeral: true
|
ephemeral: true
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@@ -359,7 +376,7 @@ const command: Command = {
|
|||||||
.setDescription(listStr)
|
.setDescription(listStr)
|
||||||
.setTimestamp();
|
.setTimestamp();
|
||||||
|
|
||||||
await interaction.reply({ embeds: [embed], ephemeral: true });
|
await interaction.reply({ embeds: [embed], ephemeral: false });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user