Compare commits
1 Commits
main
..
7da2c782af
| Author | SHA1 | Date | |
|---|---|---|---|
| 7da2c782af |
@@ -1,6 +0,0 @@
|
|||||||
D_ID=
|
|
||||||
D_Token=
|
|
||||||
D_Prefix=
|
|
||||||
D_GuildID=
|
|
||||||
M_URI=
|
|
||||||
M_DB=
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
.env
|
|
||||||
node_modules
|
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
MIT No Attribution
|
||||||
|
|
||||||
|
Copyright <YEAR> <COPYRIGHT HOLDER>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||||||
|
software and associated documentation files (the "Software"), to deal in the Software
|
||||||
|
without restriction, including without limitation the rights to use, copy, modify,
|
||||||
|
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||||
|
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||||
|
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
@@ -1,60 +1,2 @@
|
|||||||
# Arthonor-Neo
|
# Arthonor-Neo
|
||||||
|
|
||||||
**Moderately Advanced Discord Bot for Friends**
|
|
||||||
|
|
||||||
Arthonor-Neo is a custom Discord bot designed for community interaction and fun. It offers an assortment of commands for economy, social engagement, and server utilities. Suitable for small to medium-sized friend servers.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
### Core Interactions
|
|
||||||
- Nut Economy - Earn and spend nuts in server activities
|
|
||||||
- Honor System - Show recognition and respect to users
|
|
||||||
- Quotes - Save and retrieve memorable quotes
|
|
||||||
|
|
||||||
### Community & Events
|
|
||||||
- Automatic Welcome Messages - Greet new members
|
|
||||||
- Birthday System - Track and celebrate birthdays
|
|
||||||
- Automatic Birthday Cards - Personalized greetings on birthdays
|
|
||||||
- Wednesday Frog - Midweek server event
|
|
||||||
- WGE Core - With Periodic Reminders and Random Function
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Differences from Version 2.x
|
|
||||||
|
|
||||||
### Legacy Commands (Chat Messages)
|
|
||||||
These have been mostly removed with certain exceptions:
|
|
||||||
|
|
||||||
- Quoteadd has been kept due to the technicaly incompabiltity of replying using slash commands.
|
|
||||||
- Nuts has been kept due to frequent usage
|
|
||||||
|
|
||||||
### Removed
|
|
||||||
- Timers
|
|
||||||
- Weather commands
|
|
||||||
- GIF commands
|
|
||||||
- Certain developer tools
|
|
||||||
- WOKCommands Core
|
|
||||||
- Friday Reminder
|
|
||||||
|
|
||||||
### Upgraded to Slash Commands
|
|
||||||
- Nuts
|
|
||||||
- Quotes
|
|
||||||
- Honor
|
|
||||||
- Birthdays
|
|
||||||
- Role Selection
|
|
||||||
- Channel Selection
|
|
||||||
- Meme Commands
|
|
||||||
- WGE (NEW)
|
|
||||||
|
|
||||||
### New and Improved
|
|
||||||
- Interactive Honor Menu
|
|
||||||
- Interactive Quote Menu
|
|
||||||
|
|
||||||
### Database Migration
|
|
||||||
Some structurual changes to the command schema, and removal of predefined schematics
|
|
||||||
|
|
||||||
- Tables renamed with prefixes, e.g. items_, config_, stats_, etc.
|
|
||||||
- Split tables into a relation-ish style
|
|
||||||
- made some data more machine-friendly
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
### ToDo?:
|
|
||||||
- quotes filter by channel
|
|
||||||
- event creation + reminder 1h before
|
|
||||||
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 242 KiB |
|
Before Width: | Height: | Size: 914 KiB |
|
Before Width: | Height: | Size: 102 KiB |
|
Before Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 411 KiB |
|
Before Width: | Height: | Size: 371 KiB |
|
Before Width: | Height: | Size: 254 KiB |
|
Before Width: | Height: | Size: 176 KiB |
|
Before Width: | Height: | Size: 167 KiB |
|
Before Width: | Height: | Size: 158 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 158 KiB |
|
Before Width: | Height: | Size: 536 KiB |
@@ -1,18 +0,0 @@
|
|||||||
const { EmbedBuilder } = require("discord.js")
|
|
||||||
function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'abort',
|
|
||||||
description: 'abort it',
|
|
||||||
async execute(interaction) {
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setTitle('Aborted')
|
|
||||||
.setDescription('Schließe Menü. . .')
|
|
||||||
|
|
||||||
await interaction.update({
|
|
||||||
embeds: [embed],
|
|
||||||
components: []
|
|
||||||
})
|
|
||||||
await delay(2000).then(interaction.deleteReply())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, MessageFlags } = require("discord.js")
|
|
||||||
const { mClient } = require("../..")
|
|
||||||
require('dotenv').config()
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'honor_menu_dishonor',
|
|
||||||
description: 'honor menu dishonor button',
|
|
||||||
async execute(interaction) {
|
|
||||||
let description = interaction.message.embeds[0].data.description
|
|
||||||
const target = await interaction.guild.members.fetch(description.split(' ')[0].slice(2, -1))
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const honorsColl = db.collection('items_honors')
|
|
||||||
const reason = `[-] Quick Menu Dishonor`
|
|
||||||
const theirHonorLevel = await honorsColl.findOne({ userID: target.id })
|
|
||||||
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setTitle('- Honor Menu WIP -')
|
|
||||||
.setDescription(`Willst du wirklich <@${target.id}> einen **Dishonor** geben?\r\n[Grund: ${reason}]`)
|
|
||||||
.addFields({
|
|
||||||
name: 'Current Honor Level', value: `${theirHonorLevel?.honors ?? 0} (**-1**)`
|
|
||||||
})
|
|
||||||
.setThumbnail(target.displayAvatarURL())
|
|
||||||
const row = new ActionRowBuilder()
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setLabel('✔')
|
|
||||||
.setCustomId('honor_multi_confirm')
|
|
||||||
.setStyle(ButtonStyle.Success)
|
|
||||||
)
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setLabel('✖')
|
|
||||||
.setCustomId('abort')
|
|
||||||
.setStyle(ButtonStyle.Danger)
|
|
||||||
)
|
|
||||||
await interaction.reply({
|
|
||||||
embeds: [embed],
|
|
||||||
components: [row],
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, MessageFlags } = require("discord.js")
|
|
||||||
const { mClient } = require("../..")
|
|
||||||
require('dotenv').config()
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'honor_menu_history',
|
|
||||||
description: 'show selected user honor history',
|
|
||||||
async execute(interaction) {
|
|
||||||
let description = interaction.message.embeds[0].data.description
|
|
||||||
const target = await interaction.guild.members.fetch(description.split(' ')[0].slice(2, -1))
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const reasonsColl = db.collection('history_honors')
|
|
||||||
const history = await reasonsColl.findOne({ userID: target.user.id })
|
|
||||||
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setTitle('- Honor History -')
|
|
||||||
.setDescription(`${target} - ${target.user.globalName ?? target.user.username}`)
|
|
||||||
.setThumbnail(target.displayAvatarURL())
|
|
||||||
.setFooter({text: 'Um zurückzukehren, wähle einen Nutzer!'})
|
|
||||||
if(history){
|
|
||||||
let temp = ''
|
|
||||||
history.reasons.forEach(reason => {
|
|
||||||
temp += reason + '\r\n'
|
|
||||||
})
|
|
||||||
embed.setDescription(temp)
|
|
||||||
}
|
|
||||||
const select = await interaction.message.components[0]
|
|
||||||
const row = await interaction.message.components[1]
|
|
||||||
|
|
||||||
await interaction.reply({
|
|
||||||
embeds: [embed],
|
|
||||||
components: [select, row],
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
const { EmbedBuilder, ButtonBuilder, ActionRowBuilder, ButtonStyle, MessageFlags } = require("discord.js")
|
|
||||||
const { mClient } = require("../..")
|
|
||||||
require('dotenv').config()
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'honor_menu_honor',
|
|
||||||
description: 'honor menu honor button',
|
|
||||||
async execute(interaction) {
|
|
||||||
let description = interaction.message.embeds[0].data.description
|
|
||||||
const target = await interaction.guild.members.fetch(description.split(' ')[0].slice(2, -1))
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const honorsColl = db.collection('items_honors')
|
|
||||||
const reason = `[+] Quick Menu Honor`
|
|
||||||
const theirHonorLevel = await honorsColl.findOne({ userID: target.id })
|
|
||||||
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setTitle('- Honor Up! -')
|
|
||||||
.setDescription(`Willst du wirklich <@${target.id}> einen **Honor** geben?\r\n[Grund: ${reason}]`)
|
|
||||||
.addFields({
|
|
||||||
name: 'Current Honor Level', value: `${theirHonorLevel?.honors ?? 0} (**+1**)`
|
|
||||||
})
|
|
||||||
.setThumbnail(target.displayAvatarURL())
|
|
||||||
//.setFooter('Honor Level updaten sich nicht automatisch!')
|
|
||||||
const row = new ActionRowBuilder()
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setLabel('✔')
|
|
||||||
.setCustomId('honor_multi_confirm')
|
|
||||||
.setStyle(ButtonStyle.Success)
|
|
||||||
)
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setLabel('✖')
|
|
||||||
.setCustomId('abort')
|
|
||||||
.setStyle(ButtonStyle.Danger)
|
|
||||||
)
|
|
||||||
await interaction.reply({
|
|
||||||
embeds: [embed],
|
|
||||||
components: [row],
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
const { EmbedBuilder, MessageFlags } = require("discord.js")
|
|
||||||
const { mClient } = require("../..")
|
|
||||||
require('dotenv').config()
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'honor_multi_confirm',
|
|
||||||
description: 'confirm it',
|
|
||||||
async execute(interaction) {
|
|
||||||
let temp = await interaction.message.embeds[0].description.split(' ')
|
|
||||||
var honor
|
|
||||||
if (temp[5] === '**Honor**') {
|
|
||||||
honor = 1
|
|
||||||
} else if (temp[5] === '**Dishonor**'){
|
|
||||||
honor = -1
|
|
||||||
} else {
|
|
||||||
return await interaction.reply({content: "ERROR", flags: MessageFlags.Ephemeral})
|
|
||||||
}
|
|
||||||
const target = await interaction.message.guild.members.fetch(temp[3].slice(2, -1))
|
|
||||||
temp = interaction.message.embeds[0].description.split('\r\n')
|
|
||||||
const reason = `${temp[1].slice(7, -1)}`
|
|
||||||
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const honorsColl = db.collection('items_honors')
|
|
||||||
const reasonsColl = db.collection('history_honors')
|
|
||||||
const theirHonorLevel = await honorsColl.findOne({ userID: target.id })
|
|
||||||
|
|
||||||
await honorsColl.findOneAndUpdate({ userID: target.id }, { $inc: { honors: honor } }, { upsert: true })
|
|
||||||
await reasonsColl.findOneAndUpdate({ userID: target.id }, { $push: { reasons: reason } }, { upsert: true })
|
|
||||||
|
|
||||||
var description
|
|
||||||
var newTitle
|
|
||||||
var newDescription
|
|
||||||
var newThumbnail
|
|
||||||
|
|
||||||
if (honor == 1) {
|
|
||||||
description = `Willst du wirklich <@${target.id}> einen **Honor** geben?\r\n[Grund: ${reason}]`
|
|
||||||
newTitle = 'Honor Up!'
|
|
||||||
newDescription = `<@${target.id}> erhält einen Honor!\r\n[Grund: ${reason}]`
|
|
||||||
newThumbnail = "https://cdn.discordapp.com/emojis/748176295535443968.webp"
|
|
||||||
} else {
|
|
||||||
description = `Willst du wirklich <@${target.id}> einen **Dishonor** geben?\r\n[Grund: ${reason}]`
|
|
||||||
newTitle = 'Honor Down!'
|
|
||||||
newDescription = `<@${target.id}> erhält einen Dishonor!\r\n[Grund: ${reason}]`
|
|
||||||
newThumbnail = "https://cdn.discordapp.com/emojis/748176295132790786.webp"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setTitle('- Honor Menu -')
|
|
||||||
.setDescription(description)
|
|
||||||
.addFields({
|
|
||||||
name: 'Current Honor Level', value: `${theirHonorLevel?.honors ?? 0} ${honor == 1 ? '(**+1**)' : '(**-1**)'}`
|
|
||||||
})
|
|
||||||
.setThumbnail(target.displayAvatarURL())
|
|
||||||
await interaction.update({
|
|
||||||
embeds: [embed]
|
|
||||||
})
|
|
||||||
|
|
||||||
const newEmbed = new EmbedBuilder()
|
|
||||||
.setTitle(newTitle)
|
|
||||||
.setDescription(newDescription)
|
|
||||||
.setThumbnail(newThumbnail)
|
|
||||||
await interaction.followUp({
|
|
||||||
embeds: [newEmbed],
|
|
||||||
components: [],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
const { EmbedBuilder } = require("discord.js")
|
|
||||||
const { mClient } = require("../..")
|
|
||||||
require('dotenv').config()
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'honors_leaderboard_left',
|
|
||||||
description: 'navigate a page up',
|
|
||||||
async execute(interaction) {
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const honorsColl = db.collection('items_honors')
|
|
||||||
const min = 0
|
|
||||||
let skip = interaction.message.embeds[0].data.description.split('.')
|
|
||||||
skip = Number(skip[0]) - 6
|
|
||||||
skip = skip - ( skip % 5)
|
|
||||||
if ( skip < 4){
|
|
||||||
skip = 0
|
|
||||||
}
|
|
||||||
const honorsData = await honorsColl.find().sort({ honors: -1 }).skip(skip).limit(5).toArray()
|
|
||||||
let fields
|
|
||||||
honorsData.forEach((data) => {
|
|
||||||
skip++
|
|
||||||
fields = (fields ? fields : '') + (`${skip}. <@${data.userID}> : ${data.honors} Honors\r\n`)
|
|
||||||
})
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setTitle('Honors Leaderboard')
|
|
||||||
.setThumbnail(interaction.guild.iconURL({ dynamic: true}))
|
|
||||||
.setDescription(fields.toString())
|
|
||||||
.setColor('#5865F2') // Discord's blurple color
|
|
||||||
.setFooter({ text: 'Use ◄ ► to navigate' });
|
|
||||||
await interaction.update({
|
|
||||||
embeds: [embed],
|
|
||||||
components: [interaction.message.components[0]]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
const { EmbedBuilder } = require("discord.js")
|
|
||||||
const { mClient } = require("../..")
|
|
||||||
require('dotenv').config()
|
|
||||||
module.exports = {
|
|
||||||
name: 'honors_leaderboard_right',
|
|
||||||
description: 'navigate a page down',
|
|
||||||
async execute(interaction) {
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const honorsColl = db.collection('items_honors')
|
|
||||||
const max = await honorsColl.countDocuments()
|
|
||||||
let skip = interaction.message.embeds[0].data.description.split('.')
|
|
||||||
skip = Number(skip[0]) +4
|
|
||||||
if (skip >= (max - (max % 5))) {
|
|
||||||
skip = max - (max % 5)
|
|
||||||
}
|
|
||||||
const honorsData = await honorsColl.find().sort({ honors: -1 }).skip(skip).limit(5).toArray()
|
|
||||||
let fields
|
|
||||||
honorsData.forEach((data) => {
|
|
||||||
skip++
|
|
||||||
fields = (fields ? fields : '') + (`${skip}. <@${data.userID}> : ${data.honors} Honors\r\n`)
|
|
||||||
})
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setTitle('Honors Leaderboard')
|
|
||||||
.setThumbnail(interaction.guild.iconURL({ dynamic: true}))
|
|
||||||
.setDescription(fields.toString())
|
|
||||||
.setColor('#5865F2') // Discord's blurple color
|
|
||||||
.setFooter({ text: 'Use ◄ ► to navigate' });
|
|
||||||
await interaction.update({
|
|
||||||
embeds: [embed],
|
|
||||||
components: [interaction.message.components[0]]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
const { EmbedBuilder } = require("discord.js")
|
|
||||||
const { mClient } = require("../..")
|
|
||||||
require('dotenv').config()
|
|
||||||
module.exports = {
|
|
||||||
name: 'honors_leaderboard_self',
|
|
||||||
description: 'navigate to your own placement',
|
|
||||||
async execute(interaction) {
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const honorsColl = db.collection('items_honors')
|
|
||||||
|
|
||||||
const self = await honorsColl.find({ userID: interaction.user.id }).toArray()
|
|
||||||
const all = await honorsColl.find().sort({ honors: -1 }).toArray()
|
|
||||||
|
|
||||||
function findIndex(){
|
|
||||||
let index = 0
|
|
||||||
for (let i = 0; i < all.length; i++) {
|
|
||||||
index++
|
|
||||||
if (all[i].honors === self[0].honors) {
|
|
||||||
return index
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let selfIndex = findIndex()
|
|
||||||
let skip = selfIndex - ( selfIndex % 5)
|
|
||||||
|
|
||||||
const honorsData = await honorsColl.find().sort({ honors: -1 }).skip(skip).limit(5).toArray()
|
|
||||||
let fields
|
|
||||||
honorsData.forEach((data) => {
|
|
||||||
skip++
|
|
||||||
fields = (fields ? fields : '') + (`${skip}. <@${data.userID}> : ${data.honors} Honors\r\n`)
|
|
||||||
})
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setTitle('Honors Leaderboard')
|
|
||||||
.setThumbnail(interaction.guild.iconURL({ dynamic: true}))
|
|
||||||
.setDescription(fields.toString())
|
|
||||||
.setColor('#5865F2') // Discord's blurple color
|
|
||||||
.setFooter({ text: 'Use ◄ ► to navigate' });
|
|
||||||
|
|
||||||
await interaction.update({
|
|
||||||
embeds: [embed],
|
|
||||||
components: [interaction.message.components[0]]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
const {
|
|
||||||
showNutHub
|
|
||||||
} = require("../../utils/nutHub");
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: "nutHubBack",
|
|
||||||
|
|
||||||
async execute(interaction) {
|
|
||||||
return showNutHub(
|
|
||||||
interaction
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
const {
|
|
||||||
showNutBlackjack
|
|
||||||
} = require(
|
|
||||||
"../../utils/nutBlackjack"
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name:
|
|
||||||
"nutHubBlackjack",
|
|
||||||
|
|
||||||
async execute(
|
|
||||||
interaction
|
|
||||||
) {
|
|
||||||
return showNutBlackjack(
|
|
||||||
interaction
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
const {
|
|
||||||
startNutBlackjack
|
|
||||||
} = require(
|
|
||||||
"../../utils/nutBlackjack"
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name:
|
|
||||||
"nutBlackjackBet10",
|
|
||||||
|
|
||||||
async execute(
|
|
||||||
interaction
|
|
||||||
) {
|
|
||||||
return startNutBlackjack(
|
|
||||||
interaction,
|
|
||||||
10
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
const {
|
|
||||||
startNutBlackjack
|
|
||||||
} = require(
|
|
||||||
"../../utils/nutBlackjack"
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name:
|
|
||||||
"nutBlackjackBet100",
|
|
||||||
|
|
||||||
async execute(
|
|
||||||
interaction
|
|
||||||
) {
|
|
||||||
return startNutBlackjack(
|
|
||||||
interaction,
|
|
||||||
100
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
const {
|
|
||||||
startNutBlackjack
|
|
||||||
} = require(
|
|
||||||
"../../utils/nutBlackjack"
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name:
|
|
||||||
"nutBlackjackBet1000",
|
|
||||||
|
|
||||||
async execute(
|
|
||||||
interaction
|
|
||||||
) {
|
|
||||||
return startNutBlackjack(
|
|
||||||
interaction,
|
|
||||||
1000
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
const {
|
|
||||||
startNutBlackjack
|
|
||||||
} = require(
|
|
||||||
"../../utils/nutBlackjack"
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name:
|
|
||||||
"nutBlackjackBet50",
|
|
||||||
|
|
||||||
async execute(
|
|
||||||
interaction
|
|
||||||
) {
|
|
||||||
return startNutBlackjack(
|
|
||||||
interaction,
|
|
||||||
50
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
const {
|
|
||||||
startNutBlackjack
|
|
||||||
} = require(
|
|
||||||
"../../utils/nutBlackjack"
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name:
|
|
||||||
"nutBlackjackBet500",
|
|
||||||
|
|
||||||
async execute(
|
|
||||||
interaction
|
|
||||||
) {
|
|
||||||
return startNutBlackjack(
|
|
||||||
interaction,
|
|
||||||
500
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
const {
|
|
||||||
doubleNutBlackjack
|
|
||||||
} = require(
|
|
||||||
"../../utils/nutBlackjack"
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name:
|
|
||||||
"nutBlackjackDouble",
|
|
||||||
|
|
||||||
async execute(
|
|
||||||
interaction
|
|
||||||
) {
|
|
||||||
return doubleNutBlackjack(
|
|
||||||
interaction
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
const {
|
|
||||||
hitNutBlackjack
|
|
||||||
} = require(
|
|
||||||
"../../utils/nutBlackjack"
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name:
|
|
||||||
"nutBlackjackHit",
|
|
||||||
|
|
||||||
async execute(
|
|
||||||
interaction
|
|
||||||
) {
|
|
||||||
return hitNutBlackjack(
|
|
||||||
interaction
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
const {
|
|
||||||
standNutBlackjack
|
|
||||||
} = require(
|
|
||||||
"../../utils/nutBlackjack"
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name:
|
|
||||||
"nutBlackjackStand",
|
|
||||||
|
|
||||||
async execute(
|
|
||||||
interaction
|
|
||||||
) {
|
|
||||||
return standNutBlackjack(
|
|
||||||
interaction
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
const {
|
|
||||||
showNutHeist
|
|
||||||
} = require(
|
|
||||||
"../../utils/nutHeist"
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name:
|
|
||||||
"nutHubHeist",
|
|
||||||
|
|
||||||
async execute(
|
|
||||||
interaction
|
|
||||||
) {
|
|
||||||
return showNutHeist(
|
|
||||||
interaction
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
// buttons/nutHub/heistHack.js
|
|
||||||
|
|
||||||
const {
|
|
||||||
performNutHeist
|
|
||||||
} = require(
|
|
||||||
"../../utils/nutHeist"
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name:
|
|
||||||
"nutHeistHack",
|
|
||||||
|
|
||||||
async execute(
|
|
||||||
interaction
|
|
||||||
) {
|
|
||||||
return performNutHeist(
|
|
||||||
interaction,
|
|
||||||
"Hack"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
// buttons/nutHub/heistSmash.js
|
|
||||||
|
|
||||||
const {
|
|
||||||
performNutHeist
|
|
||||||
} = require(
|
|
||||||
"../../utils/nutHeist"
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name:
|
|
||||||
"nutHeistSmash",
|
|
||||||
|
|
||||||
async execute(
|
|
||||||
interaction
|
|
||||||
) {
|
|
||||||
return performNutHeist(
|
|
||||||
interaction,
|
|
||||||
"Smash"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
// buttons/nutHub/heistSneak.js
|
|
||||||
|
|
||||||
const {
|
|
||||||
performNutHeist
|
|
||||||
} = require(
|
|
||||||
"../../utils/nutHeist"
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name:
|
|
||||||
"nutHeistSneak",
|
|
||||||
|
|
||||||
async execute(
|
|
||||||
interaction
|
|
||||||
) {
|
|
||||||
return performNutHeist(
|
|
||||||
interaction,
|
|
||||||
"Sneak"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
// buttons/nutHub/roulette.js
|
|
||||||
|
|
||||||
const {
|
|
||||||
showNutRoulette
|
|
||||||
} = require(
|
|
||||||
"../../utils/nutRoulette"
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name:
|
|
||||||
"nutHubRoulette",
|
|
||||||
|
|
||||||
async execute(
|
|
||||||
interaction
|
|
||||||
) {
|
|
||||||
return showNutRoulette(
|
|
||||||
interaction
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
// buttons/nutHub/rouletteBet10.js
|
|
||||||
const {
|
|
||||||
chooseNutRouletteBet
|
|
||||||
} = require("../../utils/nutRoulette");
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: "nutRouletteBet10",
|
|
||||||
|
|
||||||
async execute(interaction) {
|
|
||||||
return chooseNutRouletteBet(
|
|
||||||
interaction,
|
|
||||||
10
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
// buttons/nutHub/rouletteBet100.js
|
|
||||||
const {
|
|
||||||
chooseNutRouletteBet
|
|
||||||
} = require("../../utils/nutRoulette");
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: "nutRouletteBet100",
|
|
||||||
|
|
||||||
async execute(interaction) {
|
|
||||||
return chooseNutRouletteBet(
|
|
||||||
interaction,
|
|
||||||
100
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
// buttons/nutHub/rouletteBet1000.js
|
|
||||||
const {
|
|
||||||
chooseNutRouletteBet
|
|
||||||
} = require("../../utils/nutRoulette");
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: "nutRouletteBet1000",
|
|
||||||
|
|
||||||
async execute(interaction) {
|
|
||||||
return chooseNutRouletteBet(
|
|
||||||
interaction,
|
|
||||||
1000
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
// buttons/nutHub/rouletteBet50.js
|
|
||||||
const {
|
|
||||||
chooseNutRouletteBet
|
|
||||||
} = require("../../utils/nutRoulette");
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: "nutRouletteBet50",
|
|
||||||
|
|
||||||
async execute(interaction) {
|
|
||||||
return chooseNutRouletteBet(
|
|
||||||
interaction,
|
|
||||||
50
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
// buttons/nutHub/rouletteBet500.js
|
|
||||||
const {
|
|
||||||
chooseNutRouletteBet
|
|
||||||
} = require("../../utils/nutRoulette");
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: "nutRouletteBet500",
|
|
||||||
|
|
||||||
async execute(interaction) {
|
|
||||||
return chooseNutRouletteBet(
|
|
||||||
interaction,
|
|
||||||
500
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
// buttons/nutHub/rouletteBlack.js
|
|
||||||
const {
|
|
||||||
playNutRoulette
|
|
||||||
} = require("../../utils/nutRoulette");
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: "nutRouletteBlack",
|
|
||||||
|
|
||||||
async execute(interaction) {
|
|
||||||
return playNutRoulette(
|
|
||||||
interaction,
|
|
||||||
"Black"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
// buttons/nutHub/rouletteEven.js
|
|
||||||
const {
|
|
||||||
playNutRoulette
|
|
||||||
} = require("../../utils/nutRoulette");
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: "nutRouletteEven",
|
|
||||||
|
|
||||||
async execute(interaction) {
|
|
||||||
return playNutRoulette(
|
|
||||||
interaction,
|
|
||||||
"Even"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
// buttons/nutHub/rouletteOdd.js
|
|
||||||
const {
|
|
||||||
playNutRoulette
|
|
||||||
} = require("../../utils/nutRoulette");
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: "nutRouletteOdd",
|
|
||||||
|
|
||||||
async execute(interaction) {
|
|
||||||
return playNutRoulette(
|
|
||||||
interaction,
|
|
||||||
"Odd"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
// buttons/nutHub/rouletteRed.js
|
|
||||||
const {
|
|
||||||
playNutRoulette
|
|
||||||
} = require("../../utils/nutRoulette");
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: "nutRouletteRed",
|
|
||||||
|
|
||||||
async execute(interaction) {
|
|
||||||
return playNutRoulette(
|
|
||||||
interaction,
|
|
||||||
"Red"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
// buttons/nutHub/rouletteZero.js
|
|
||||||
const {
|
|
||||||
playNutRoulette
|
|
||||||
} = require("../../utils/nutRoulette");
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: "nutRouletteZero",
|
|
||||||
|
|
||||||
async execute(interaction) {
|
|
||||||
return playNutRoulette(
|
|
||||||
interaction,
|
|
||||||
"Zero"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
const {
|
|
||||||
playNutSlots
|
|
||||||
} = require(
|
|
||||||
"../../utils/nutSlots"
|
|
||||||
);
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name:
|
|
||||||
"nutSlotsBet10",
|
|
||||||
|
|
||||||
async execute(
|
|
||||||
interaction
|
|
||||||
) {
|
|
||||||
return playNutSlots(
|
|
||||||
interaction,
|
|
||||||
10
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
const {
|
|
||||||
playNutSlots
|
|
||||||
} = require(
|
|
||||||
"../../utils/nutSlots"
|
|
||||||
);
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name:
|
|
||||||
"nutSlotsBet100",
|
|
||||||
|
|
||||||
async execute(
|
|
||||||
interaction
|
|
||||||
) {
|
|
||||||
return playNutSlots(
|
|
||||||
interaction,
|
|
||||||
100
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
const {
|
|
||||||
playNutSlots
|
|
||||||
} = require(
|
|
||||||
"../../utils/nutSlots"
|
|
||||||
);
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name:
|
|
||||||
"nutSlotsBet1000",
|
|
||||||
|
|
||||||
async execute(
|
|
||||||
interaction
|
|
||||||
) {
|
|
||||||
return playNutSlots(
|
|
||||||
interaction,
|
|
||||||
1000
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
const {
|
|
||||||
playNutSlots
|
|
||||||
} = require(
|
|
||||||
"../../utils/nutSlots"
|
|
||||||
);
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name:
|
|
||||||
"nutSlotsBet50",
|
|
||||||
|
|
||||||
async execute(
|
|
||||||
interaction
|
|
||||||
) {
|
|
||||||
return playNutSlots(
|
|
||||||
interaction,
|
|
||||||
50
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
const {
|
|
||||||
playNutSlots
|
|
||||||
} = require(
|
|
||||||
"../../utils/nutSlots"
|
|
||||||
);
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name:
|
|
||||||
"nutSlotsBet500",
|
|
||||||
|
|
||||||
async execute(
|
|
||||||
interaction
|
|
||||||
) {
|
|
||||||
return playNutSlots(
|
|
||||||
interaction,
|
|
||||||
500
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
// buttons/nutHub/slots.js
|
|
||||||
|
|
||||||
const {
|
|
||||||
showNutSlots
|
|
||||||
} = require(
|
|
||||||
"../../utils/nutSlots"
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name:
|
|
||||||
"nutHubSlots",
|
|
||||||
|
|
||||||
async execute(
|
|
||||||
interaction
|
|
||||||
) {
|
|
||||||
return showNutSlots(
|
|
||||||
interaction
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
const { EmbedBuilder } = require("discord.js")
|
|
||||||
const { mClient } = require("../..")
|
|
||||||
require('dotenv').config()
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'nuts_give_confirm',
|
|
||||||
description: 'confirm it',
|
|
||||||
async execute(interaction) {
|
|
||||||
const from = interaction.user
|
|
||||||
let temp = await interaction.message.embeds[0].description.split(' ')
|
|
||||||
const amount = Number(temp[3].split('**')[1])
|
|
||||||
const to = await interaction.message.guild.members.fetch(temp[6].slice(2,-1))
|
|
||||||
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const nutsColl = db.collection('items_nuts')
|
|
||||||
await nutsColl.findOneAndUpdate({ userId: from.id }, { $inc: { nuts: -amount } }, { upsert: true })
|
|
||||||
await nutsColl.findOneAndUpdate({ userId: to.id }, { $inc: { nuts: +amount } }, { upsert: true })
|
|
||||||
|
|
||||||
const yourBalance = await nutsColl.findOne({ userId: from.id })
|
|
||||||
const theirBalance = await nutsColl.findOne({ userId: to.id })
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setTitle('Gib Nuss!')
|
|
||||||
.setDescription(`Willst du wirklich **${amount}** Nüsse an <@${to.id}> senden?`)
|
|
||||||
.addFields(
|
|
||||||
{ name: `Your Current Balance`, value: `${yourBalance.nuts} (**-${amount}**)`, inline: true },
|
|
||||||
{ name: `Your New Balance`, value: `${yourBalance.nuts - amount}`, inline: true },
|
|
||||||
{ name: '\u200B', value: '\u200B' },
|
|
||||||
{ name: `Their Current Balance`, value: `${theirBalance.nuts} (**+${amount}**)`, inline: true },
|
|
||||||
{ name: `Their New Balance`, value: `${theirBalance.nuts + amount}`, inline: true }
|
|
||||||
)
|
|
||||||
.setThumbnail(to.displayAvatarURL())
|
|
||||||
await interaction.update({
|
|
||||||
embeds: [ embed ]
|
|
||||||
})
|
|
||||||
|
|
||||||
const newEmbed = new EmbedBuilder()
|
|
||||||
.setTitle('Gib Nuss!')
|
|
||||||
.setDescription(`Du hast **${amount}** Nuts an <@${to.id}> gesendet!`)
|
|
||||||
.setFooter({ text: 'Um den gleichen Wert zu senden, klick einfach nochmal auf ✔' })
|
|
||||||
.setThumbnail(to.user.displayAvatarURL())
|
|
||||||
await interaction.followUp({
|
|
||||||
embeds: [ newEmbed ],
|
|
||||||
components: [],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
const { EmbedBuilder } = require("discord.js")
|
|
||||||
const { mClient } = require("../..")
|
|
||||||
module.exports = {
|
|
||||||
name: 'nuts_give_fake',
|
|
||||||
description: 'fake it',
|
|
||||||
async execute(interaction) {
|
|
||||||
const from = interaction.user
|
|
||||||
let temp = await interaction.message.embeds[0].description.split(' ')
|
|
||||||
const amount = Number(temp[3].split('**')[1])
|
|
||||||
const to = await interaction.message.guild.members.fetch(temp[6].slice(2,-1))
|
|
||||||
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const nutsColl = db.collection('items_nuts')
|
|
||||||
|
|
||||||
const yourBalance = await nutsColl.findOne({ userId: from.id })
|
|
||||||
const theirBalance = await nutsColl.findOne({ userId: to.id })
|
|
||||||
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setTitle('Gib Nuss!')
|
|
||||||
.setDescription(`Willst du wirklich **${amount}** Nüsse an <@${to.id}> senden?`)
|
|
||||||
.addFields(
|
|
||||||
{ name: `Your Current Balance`, value: `${yourBalance.nuts} (**-${amount}**)`, inline: true },
|
|
||||||
{ name: `Your New Balance`, value: `${yourBalance.nuts - amount}`, inline: true },
|
|
||||||
{ name: '\u200B', value: '\u200B' },
|
|
||||||
{ name: `Their Current Balance`, value: `${theirBalance.nuts} (**+${amount}**)`, inline: true },
|
|
||||||
{ name: `Their New Balance`, value: `${theirBalance.nuts + amount}`, inline: true }
|
|
||||||
)
|
|
||||||
.setThumbnail(to.displayAvatarURL())
|
|
||||||
await interaction.update({
|
|
||||||
embeds: [ embed ]
|
|
||||||
})
|
|
||||||
|
|
||||||
const newEmbed = new EmbedBuilder()
|
|
||||||
.setTitle('Du Fieser Gauner!')
|
|
||||||
.setDescription(`Yee Haw! Was tust du hier?!`)
|
|
||||||
.setThumbnail(interaction.client.user.displayAvatarURL())
|
|
||||||
await interaction.followUp({
|
|
||||||
embeds: [ newEmbed ],
|
|
||||||
components: [],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
const { EmbedBuilder } = require("discord.js")
|
|
||||||
const { mClient } = require("../..")
|
|
||||||
require('dotenv').config()
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'nuts_leaderboard_left',
|
|
||||||
description: 'navigate a page up',
|
|
||||||
async execute(interaction) {
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const nutsColl = db.collection('items_nuts')
|
|
||||||
const min = 0
|
|
||||||
let skip = interaction.message.embeds[0].data.description.split('.')
|
|
||||||
skip = Number(skip[0]) - 6
|
|
||||||
skip = skip - ( skip % 5)
|
|
||||||
if ( skip < 4){
|
|
||||||
skip = 0
|
|
||||||
}
|
|
||||||
const nutsData = await nutsColl.find({ nuts: { $gt: 0 } }).sort({ nuts: -1 }).skip(skip).limit(5).toArray()
|
|
||||||
let fields
|
|
||||||
nutsData.forEach((data) => {
|
|
||||||
skip++
|
|
||||||
fields = (fields ? fields : '') + (`${skip}. <@${data.userId}> : ${data.nuts} Nuts\r\n`)
|
|
||||||
})
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setTitle('Nuts Leaderboard')
|
|
||||||
.setThumbnail(interaction.guild.iconURL({ dynamic: true}))
|
|
||||||
.setDescription(fields.toString())
|
|
||||||
.setColor('#5865F2') // Discord's blurple color
|
|
||||||
.setFooter({ text: 'Use ◄ ► to navigate' });
|
|
||||||
await interaction.update({
|
|
||||||
embeds: [embed],
|
|
||||||
components: [interaction.message.components[0]]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
const { EmbedBuilder } = require("discord.js")
|
|
||||||
const { mClient } = require("../..")
|
|
||||||
require('dotenv').config()
|
|
||||||
module.exports = {
|
|
||||||
name: 'nuts_leaderboard_right',
|
|
||||||
description: 'navigate a page down',
|
|
||||||
async execute(interaction) {
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const nutsColl = db.collection('items_nuts')
|
|
||||||
const max = await nutsColl.countDocuments({ nuts: { $gt: 0 } })
|
|
||||||
let skip = interaction.message.embeds[0].data.description.split('.')
|
|
||||||
skip = Number(skip[0]) +4
|
|
||||||
if (skip >= (max - (max % 5))) {
|
|
||||||
skip = max - (max % 5)
|
|
||||||
}
|
|
||||||
const nutsData = await nutsColl.find({ nuts: { $gt: 0 } }).sort({ nuts: -1 }).skip(skip).limit(5).toArray()
|
|
||||||
let fields
|
|
||||||
nutsData.forEach((data) => {
|
|
||||||
skip++
|
|
||||||
fields = (fields ? fields : '') + (`${skip}. <@${data.userId}> : ${data.nuts} Nuts\r\n`)
|
|
||||||
})
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setTitle('Nuts Leaderboard')
|
|
||||||
.setThumbnail(interaction.guild.iconURL({ dynamic: true}))
|
|
||||||
.setDescription(fields.toString())
|
|
||||||
.setColor('#5865F2') // Discord's blurple color
|
|
||||||
.setFooter({ text: 'Use ◄ ► to navigate' });
|
|
||||||
await interaction.update({
|
|
||||||
embeds: [embed],
|
|
||||||
components: [interaction.message.components[0]]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
const { EmbedBuilder } = require("discord.js")
|
|
||||||
const { mClient } = require("../..")
|
|
||||||
require('dotenv').config()
|
|
||||||
module.exports = {
|
|
||||||
name: 'nuts_leaderboard_self',
|
|
||||||
description: 'navigate to your own placement',
|
|
||||||
async execute(interaction) {
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const nutsColl = db.collection('items_nuts')
|
|
||||||
|
|
||||||
const self = await nutsColl.find({ userId: interaction.user.id }).toArray()
|
|
||||||
const all = await nutsColl.find({ nuts: { $gt: 0 } }).sort({ nuts: -1 }).toArray()
|
|
||||||
|
|
||||||
function findIndex(){
|
|
||||||
let index = 0
|
|
||||||
for (let i = 0; i < all.length; i++) {
|
|
||||||
index++
|
|
||||||
if (all[i].nuts === self[0].nuts) {
|
|
||||||
return index - 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let selfIndex = findIndex()
|
|
||||||
let skip = selfIndex - ( selfIndex % 5)
|
|
||||||
|
|
||||||
const nutsData = await nutsColl.find({ nuts: { $gt: 0 } }).sort({ nuts: -1 }).skip(skip).limit(5).toArray()
|
|
||||||
let fields
|
|
||||||
nutsData.forEach((data) => {
|
|
||||||
skip++
|
|
||||||
fields = (fields ? fields : '') + (`${skip}. <@${data.userId}> : ${data.nuts} Nuts\r\n`)
|
|
||||||
})
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setTitle('Nuts Leaderboard')
|
|
||||||
.setThumbnail(interaction.guild.iconURL({ dynamic: true}))
|
|
||||||
.setDescription(fields.toString())
|
|
||||||
.setColor('#5865F2') // Discord's blurple color
|
|
||||||
.setFooter({ text: 'Use ◄ ► to navigate' });
|
|
||||||
await interaction.update({
|
|
||||||
embeds: [embed],
|
|
||||||
components: [interaction.message.components[0]]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
const { quotesLeaderboard } = require("../../commands/slash/applications/quotes");
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'quotes_leaderboard_left',
|
|
||||||
description: 'Navigate left through the quotes leaderboard',
|
|
||||||
async execute(interaction) {
|
|
||||||
await interaction.deferReply();
|
|
||||||
|
|
||||||
// Parse current page from footer
|
|
||||||
let page = 1;
|
|
||||||
const footerText = interaction.message.embeds[0]?.footer?.text || '';
|
|
||||||
const match = footerText.match(/Page (\d+) of (\d+)/);
|
|
||||||
if (match) page = Number(match[1]);
|
|
||||||
|
|
||||||
page--; // move to previous page
|
|
||||||
|
|
||||||
await quotesLeaderboard(interaction, page);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
const { quotesLeaderboard } = require("../../commands/slash/applications/quotes");
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'quotes_leaderboard_right',
|
|
||||||
description: 'Navigate right through the quotes leaderboard',
|
|
||||||
async execute(interaction) {
|
|
||||||
await interaction.deferReply();
|
|
||||||
|
|
||||||
// Parse current page from footer
|
|
||||||
let page = 1;
|
|
||||||
const footerText = interaction.message.embeds[0]?.footer?.text || '';
|
|
||||||
const match = footerText.match(/Page (\d+) of (\d+)/);
|
|
||||||
if (match) page = Number(match[1]);
|
|
||||||
|
|
||||||
page++; // move to next page
|
|
||||||
|
|
||||||
await quotesLeaderboard(interaction, page);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
const { EmbedBuilder, UserSelectMenuBuilder, ActionRowBuilder, MessageFlags } = require("discord.js")
|
|
||||||
const { mClient } = require("../..")
|
|
||||||
require('dotenv').config()
|
|
||||||
module.exports = {
|
|
||||||
name: 'quotes_list_left',
|
|
||||||
description: 'navigate left',
|
|
||||||
async execute(interaction) {
|
|
||||||
let oldEmbed = interaction.message.embeds[0].data
|
|
||||||
if (!oldEmbed.footer) { return interaction.reply({ content: 'Please use a Filter', flags: MessageFlags.Ephemeral }) }
|
|
||||||
if (oldEmbed.fields && oldEmbed.fields[0].value == 0) { return interaction.reply({ content: 'This User has no Quotes', flags: MessageFlags.Ephemeral }) }
|
|
||||||
|
|
||||||
let userID = interaction.message.embeds[0].data.footer.text.split(' ')[5].slice(2, -1)
|
|
||||||
const target = await interaction.guild.members.fetch(userID)
|
|
||||||
if (!target) { return interaction.reply({ content: 'Please use a Filter', flags: MessageFlags.Ephemeral }) }
|
|
||||||
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const quotesColl = db.collection('items_quotes')
|
|
||||||
const quotes = await quotesColl.find({ userID: target.id }).toArray()
|
|
||||||
|
|
||||||
var index = Number((await interaction.message.embeds[0].data.title).split(' ')[2].slice(1))
|
|
||||||
if (!index) { index = 0 }
|
|
||||||
index = index - 2
|
|
||||||
if (index < 1) { index = 0 }
|
|
||||||
|
|
||||||
|
|
||||||
const found = quotes[index]
|
|
||||||
|
|
||||||
const guild = await interaction.client.guilds.fetch(found.guildID)
|
|
||||||
const channel = await guild.channels.fetch(found.channelID)
|
|
||||||
const message = await channel.messages.fetch(found.messageID)
|
|
||||||
|
|
||||||
var msgData = {
|
|
||||||
content: message.content,
|
|
||||||
author: await message.author,
|
|
||||||
reference: await message.reference,
|
|
||||||
embed: await message.embeds ? 'embed' : null
|
|
||||||
} // debug
|
|
||||||
if (msgData.reference) {
|
|
||||||
let refMessage = await channel.messages.fetch(msgData.reference.messageId)
|
|
||||||
var refData = {
|
|
||||||
content: refMessage.content,
|
|
||||||
author: await refMessage.author,
|
|
||||||
embed: await refMessage.embeds.length > 0 ? 'embed' : null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var description = ''
|
|
||||||
if (refData) {
|
|
||||||
description += `> ${refData.author}`
|
|
||||||
if (refData.embed) {
|
|
||||||
description += '*an embed / a command* '
|
|
||||||
} else {
|
|
||||||
description += refData.content
|
|
||||||
}
|
|
||||||
description += `\r\n↳`
|
|
||||||
}
|
|
||||||
let messageLink = `https://discord.com/channels/${found.guildID}/${found.channelID}/${found.messageID}`
|
|
||||||
description += `${msgData.author} ${msgData.content}\r\n\r\n${messageLink}`
|
|
||||||
let timestamp = new Date(message.createdTimestamp)
|
|
||||||
let footer = timestamp.toDateString().toString()
|
|
||||||
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setThumbnail(msgData.author.displayAvatarURL())
|
|
||||||
.setURL(messageLink)
|
|
||||||
.setTitle(`- Quote #${index + 1} -`)
|
|
||||||
.setDescription(description)
|
|
||||||
.setFooter({ text: (`${footer} #${found.messageID} <@${found.userID}>`) })
|
|
||||||
const select = new ActionRowBuilder()
|
|
||||||
.addComponents(
|
|
||||||
new UserSelectMenuBuilder()
|
|
||||||
.setCustomId('quotes_list_mentionable')
|
|
||||||
.setPlaceholder('Filter By User')
|
|
||||||
)
|
|
||||||
|
|
||||||
const row = interaction.message.components[1]
|
|
||||||
await interaction.update({
|
|
||||||
embeds: [embed],
|
|
||||||
components: [select, row]
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
const { EmbedBuilder, UserSelectMenuBuilder, ActionRowBuilder, MessageFlags } = require("discord.js")
|
|
||||||
const { mClient } = require("../..")
|
|
||||||
require('dotenv').config()
|
|
||||||
module.exports = {
|
|
||||||
name: 'quotes_list_right',
|
|
||||||
description: 'navigate right',
|
|
||||||
async execute(interaction) {
|
|
||||||
let oldEmbed = interaction.message.embeds[0].data
|
|
||||||
if (!oldEmbed.footer) { return interaction.reply({ content: 'Please use a Filter', flags: MessageFlags.Ephemeral }) }
|
|
||||||
if (oldEmbed.fields && oldEmbed.fields[0].value == 0) { return interaction.reply({ content: 'This User has no Quotes', flags: MessageFlags.Ephemeral }) }
|
|
||||||
|
|
||||||
let userID = interaction.message.embeds[0].data.footer.text.split(' ')[5].slice(2, -1)
|
|
||||||
const target = await interaction.guild.members.fetch(userID)
|
|
||||||
if (!target) { return interaction.reply({ content: 'Please use a Filter', flags: MessageFlags.Ephemeral }) }
|
|
||||||
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const quotesColl = db.collection('items_quotes')
|
|
||||||
const quotes = await quotesColl.find({ userID: target.id }).toArray()
|
|
||||||
|
|
||||||
var index = Number((await interaction.message.embeds[0].data.title).split(' ')[2].slice(1))
|
|
||||||
if (!index) { index = 0 }
|
|
||||||
//if (index >= quotes.length){ return interaction.reply({content: 'Max Quotes Reached', flags: MessageFlags.Ephemeral})}
|
|
||||||
if (index >= quotes.length) { index-- }
|
|
||||||
|
|
||||||
// will automatically reflect the next index due to how arrays think
|
|
||||||
|
|
||||||
const found = quotes[index]
|
|
||||||
const guild = await interaction.client.guilds.fetch(found.guildID)
|
|
||||||
const channel = await guild.channels.fetch(found.channelID)
|
|
||||||
const message = await channel.messages.fetch(found.messageID)
|
|
||||||
|
|
||||||
var msgData = {
|
|
||||||
content: message.content,
|
|
||||||
author: await message.author,
|
|
||||||
reference: await message.reference,
|
|
||||||
embed: await message.embeds ? 'embed' : null
|
|
||||||
} // debug
|
|
||||||
if (msgData.reference) {
|
|
||||||
let refMessage = await channel.messages.fetch(msgData.reference.messageId)
|
|
||||||
var refData = {
|
|
||||||
content: refMessage.content,
|
|
||||||
author: await refMessage.author,
|
|
||||||
embed: await refMessage.embeds.length > 0 ? 'embed' : null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var description = ''
|
|
||||||
if (refData) {
|
|
||||||
description += `> ${refData.author}`
|
|
||||||
if (refData.embed) {
|
|
||||||
description += '*an embed / a command* '
|
|
||||||
} else {
|
|
||||||
description += refData.content
|
|
||||||
}
|
|
||||||
description += `\r\n↳`
|
|
||||||
}
|
|
||||||
let messageLink = `https://discord.com/channels/${found.guildID}/${found.channelID}/${found.messageID}`
|
|
||||||
description += `${msgData.author} ${msgData.content}\r\n\r\n${messageLink}`
|
|
||||||
let timestamp = new Date(message.createdTimestamp)
|
|
||||||
let footer = timestamp.toDateString().toString()
|
|
||||||
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setThumbnail(msgData.author.displayAvatarURL())
|
|
||||||
.setURL(messageLink)
|
|
||||||
.setTitle(`- Quote #${index + 1} -`)
|
|
||||||
.setDescription(description)
|
|
||||||
.setFooter({ text: (`${footer} #${found.messageID} <@${found.userID}>`) })
|
|
||||||
const select = new ActionRowBuilder()
|
|
||||||
.addComponents(
|
|
||||||
new UserSelectMenuBuilder()
|
|
||||||
.setCustomId('quotes_list_mentionable')
|
|
||||||
.setPlaceholder('Filter By User')
|
|
||||||
)
|
|
||||||
|
|
||||||
const row = interaction.message.components[1]
|
|
||||||
await interaction.update({
|
|
||||||
embeds: [embed],
|
|
||||||
components: [select, row]
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
const ping = require("../../../utils/ping")
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'ping',
|
|
||||||
description: 'dev tool',
|
|
||||||
aliases: ['p'],
|
|
||||||
async execute(message, args) {
|
|
||||||
return ping(message, args, 'legacy')
|
|
||||||
}}
|
|
||||||
@@ -1,158 +0,0 @@
|
|||||||
const {
|
|
||||||
EmbedBuilder
|
|
||||||
} = require("discord.js");
|
|
||||||
|
|
||||||
const {
|
|
||||||
getNutBalance
|
|
||||||
} = require(
|
|
||||||
"../../../utils/nutEconomy"
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
function delay(ms) {
|
|
||||||
return new Promise(
|
|
||||||
resolve =>
|
|
||||||
setTimeout(
|
|
||||||
resolve,
|
|
||||||
ms
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name:
|
|
||||||
"checknuts",
|
|
||||||
|
|
||||||
description:
|
|
||||||
"get nuts",
|
|
||||||
|
|
||||||
aliases: [
|
|
||||||
"chn"
|
|
||||||
],
|
|
||||||
|
|
||||||
|
|
||||||
async execute(
|
|
||||||
message,
|
|
||||||
args
|
|
||||||
) {
|
|
||||||
let target =
|
|
||||||
message.author;
|
|
||||||
|
|
||||||
|
|
||||||
let addressing =
|
|
||||||
"Du hast";
|
|
||||||
|
|
||||||
|
|
||||||
if (
|
|
||||||
args[0]
|
|
||||||
) {
|
|
||||||
if (
|
|
||||||
!args[0].startsWith("<@")
|
|
||||||
||
|
|
||||||
!args[0].endsWith(">")
|
|
||||||
) {
|
|
||||||
return message.reply(
|
|
||||||
"Invalid User Specification"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
|
||||||
target =
|
|
||||||
await message.guild.members.fetch(
|
|
||||||
args[0].slice(
|
|
||||||
2,
|
|
||||||
-1
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
return message.reply({
|
|
||||||
content:
|
|
||||||
`User: ${args[0]} nicht gefunden!`
|
|
||||||
})
|
|
||||||
.then(
|
|
||||||
async msg => {
|
|
||||||
await delay(
|
|
||||||
4000
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
message.delete();
|
|
||||||
msg.delete();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (
|
|
||||||
target.user.id !==
|
|
||||||
message.author.id
|
|
||||||
) {
|
|
||||||
if (
|
|
||||||
!target.user.globalName
|
|
||||||
) {
|
|
||||||
addressing =
|
|
||||||
`${target.user.username} hat`;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
else {
|
|
||||||
addressing =
|
|
||||||
`${target.user.globalName} hat`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const targetId =
|
|
||||||
target.id
|
|
||||||
??
|
|
||||||
target.user?.id;
|
|
||||||
|
|
||||||
|
|
||||||
const balance =
|
|
||||||
await getNutBalance(
|
|
||||||
targetId
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
let content;
|
|
||||||
|
|
||||||
|
|
||||||
if (
|
|
||||||
balance <=
|
|
||||||
0
|
|
||||||
) {
|
|
||||||
content =
|
|
||||||
`${addressing} noch keine Nüsse gesammelt :(`;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
else {
|
|
||||||
content =
|
|
||||||
`${addressing} bereits **${balance}** Nüsse gesammelt!`;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const embed =
|
|
||||||
new EmbedBuilder()
|
|
||||||
.setTitle(
|
|
||||||
"Checknuts!"
|
|
||||||
)
|
|
||||||
.setThumbnail(
|
|
||||||
target.displayAvatarURL()
|
|
||||||
)
|
|
||||||
.setDescription(
|
|
||||||
content
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
return message.reply({
|
|
||||||
embeds: [
|
|
||||||
embed
|
|
||||||
]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
const {
|
|
||||||
EmbedBuilder
|
|
||||||
} = require("discord.js");
|
|
||||||
|
|
||||||
const {
|
|
||||||
getCooldown,
|
|
||||||
getUnixTime
|
|
||||||
} = require(
|
|
||||||
"../../../utils/nutEconomy"
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name:
|
|
||||||
"nutsCooldown",
|
|
||||||
|
|
||||||
description:
|
|
||||||
"shows nut cooldown",
|
|
||||||
|
|
||||||
aliases: [
|
|
||||||
"ncd"
|
|
||||||
],
|
|
||||||
|
|
||||||
|
|
||||||
async execute(
|
|
||||||
message,
|
|
||||||
args
|
|
||||||
) {
|
|
||||||
const cooldown =
|
|
||||||
await getCooldown(
|
|
||||||
message.author.id,
|
|
||||||
"nut"
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
const now =
|
|
||||||
getUnixTime();
|
|
||||||
|
|
||||||
|
|
||||||
let content =
|
|
||||||
"Du kannst wieder nussen! :)";
|
|
||||||
|
|
||||||
|
|
||||||
let thumbnail =
|
|
||||||
"https://cdn-icons-png.flaticon.com/512/7451/7451659.png";
|
|
||||||
|
|
||||||
|
|
||||||
let title =
|
|
||||||
"Go Nuts!";
|
|
||||||
|
|
||||||
|
|
||||||
if (
|
|
||||||
cooldown >
|
|
||||||
now
|
|
||||||
) {
|
|
||||||
content =
|
|
||||||
`<t:${cooldown}:R> kannst du wieder nussen! ;)`;
|
|
||||||
|
|
||||||
|
|
||||||
thumbnail =
|
|
||||||
"https://cdn.discordapp.com/attachments/1152723542836772914/1152987472788193361/No-nuts-PhotoRoom.png-PhotoRoom.png";
|
|
||||||
|
|
||||||
|
|
||||||
title =
|
|
||||||
"To Nut or Not to Nut...";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const embed =
|
|
||||||
new EmbedBuilder()
|
|
||||||
.setThumbnail(
|
|
||||||
thumbnail
|
|
||||||
)
|
|
||||||
.setTitle(
|
|
||||||
title
|
|
||||||
)
|
|
||||||
.setDescription(
|
|
||||||
content
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
await message.reply({
|
|
||||||
embeds: [
|
|
||||||
embed
|
|
||||||
]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
const {
|
|
||||||
getCollections,
|
|
||||||
changeNuts,
|
|
||||||
claimCooldown,
|
|
||||||
randomInteger
|
|
||||||
} = require(
|
|
||||||
"../../../utils/nutEconomy"
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name:
|
|
||||||
"nuts",
|
|
||||||
|
|
||||||
description:
|
|
||||||
"get nuts",
|
|
||||||
|
|
||||||
aliases: [
|
|
||||||
"n",
|
|
||||||
"nget",
|
|
||||||
"nutsget"
|
|
||||||
],
|
|
||||||
|
|
||||||
|
|
||||||
async execute(
|
|
||||||
message,
|
|
||||||
args
|
|
||||||
) {
|
|
||||||
const {
|
|
||||||
db
|
|
||||||
} =
|
|
||||||
getCollections();
|
|
||||||
|
|
||||||
|
|
||||||
const nutsStatsColl =
|
|
||||||
db.collection(
|
|
||||||
"stats_nuts"
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
const cooldown =
|
|
||||||
await claimCooldown(
|
|
||||||
message.author.id,
|
|
||||||
"nut",
|
|
||||||
60 * 60
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
if (
|
|
||||||
!cooldown.claimed
|
|
||||||
) {
|
|
||||||
return message.reply({
|
|
||||||
content:
|
|
||||||
`Du kannst erst <t:${cooldown.next}:R> wieder nussen :(`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const amount =
|
|
||||||
randomInteger(
|
|
||||||
0,
|
|
||||||
9
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
await changeNuts(
|
|
||||||
message.author.id,
|
|
||||||
amount
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
await nutsStatsColl.findOneAndUpdate(
|
|
||||||
{
|
|
||||||
userId:
|
|
||||||
message.author.id
|
|
||||||
},
|
|
||||||
{
|
|
||||||
$inc: {
|
|
||||||
[`stat.${amount}`]:
|
|
||||||
1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
upsert:
|
|
||||||
true
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
await nutsStatsColl.findOneAndUpdate(
|
|
||||||
{
|
|
||||||
userId:
|
|
||||||
"__global"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
$inc: {
|
|
||||||
[`stat.${amount}`]:
|
|
||||||
1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
upsert:
|
|
||||||
true
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
const formatNut =
|
|
||||||
amount =>
|
|
||||||
`${amount === 1 ? "eine" : amount} ${amount === 1 ? "Nuss" : "Nüsse"}`;
|
|
||||||
|
|
||||||
|
|
||||||
let nutText =
|
|
||||||
`Du hast ${formatNut(amount)} bekommen! :chestnut:`;
|
|
||||||
|
|
||||||
|
|
||||||
if (
|
|
||||||
amount <=
|
|
||||||
0
|
|
||||||
) {
|
|
||||||
nutText =
|
|
||||||
"Du hast keine Nuss bekommen! :yoink_help:";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return message.reply({
|
|
||||||
content:
|
|
||||||
nutText
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,224 +0,0 @@
|
|||||||
const {
|
|
||||||
EmbedBuilder
|
|
||||||
} = require("discord.js");
|
|
||||||
|
|
||||||
const {
|
|
||||||
getNutBalance,
|
|
||||||
transferNuts
|
|
||||||
} = require(
|
|
||||||
"../../../utils/nutEconomy"
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
function delay(ms) {
|
|
||||||
return new Promise(
|
|
||||||
resolve =>
|
|
||||||
setTimeout(
|
|
||||||
resolve,
|
|
||||||
ms
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name:
|
|
||||||
"givenuts",
|
|
||||||
|
|
||||||
description:
|
|
||||||
"give nuts",
|
|
||||||
|
|
||||||
aliases: [
|
|
||||||
"gn"
|
|
||||||
],
|
|
||||||
|
|
||||||
|
|
||||||
async execute(
|
|
||||||
message,
|
|
||||||
args
|
|
||||||
) {
|
|
||||||
const from =
|
|
||||||
message.author;
|
|
||||||
|
|
||||||
|
|
||||||
if (
|
|
||||||
args[0] ==
|
|
||||||
`<@${message.author.id}>`
|
|
||||||
||
|
|
||||||
!args[0]
|
|
||||||
) {
|
|
||||||
return message.reply({
|
|
||||||
content:
|
|
||||||
"Du musst einen anderen User erwähnen"
|
|
||||||
})
|
|
||||||
.then(
|
|
||||||
async msg => {
|
|
||||||
await delay(
|
|
||||||
4000
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
message.delete();
|
|
||||||
msg.delete();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (
|
|
||||||
!args[0].startsWith("<@")
|
|
||||||
||
|
|
||||||
!args[0].endsWith(">")
|
|
||||||
) {
|
|
||||||
return message.reply(
|
|
||||||
"Invalid User Specification"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
let target;
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
|
||||||
target =
|
|
||||||
await message.guild.members.fetch(
|
|
||||||
args[0].slice(
|
|
||||||
2,
|
|
||||||
-1
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
return message.reply({
|
|
||||||
content:
|
|
||||||
`User: ${args[0]} nicht gefunden!`
|
|
||||||
})
|
|
||||||
.then(
|
|
||||||
async msg => {
|
|
||||||
await delay(
|
|
||||||
4000
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
message.delete();
|
|
||||||
msg.delete();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const to =
|
|
||||||
target;
|
|
||||||
|
|
||||||
|
|
||||||
let amount;
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
|
||||||
amount =
|
|
||||||
Number(
|
|
||||||
args[1]
|
|
||||||
);
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.log(
|
|
||||||
error
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
return message.reply({
|
|
||||||
content:
|
|
||||||
"Du musst eine Menge angeben!"
|
|
||||||
})
|
|
||||||
.then(
|
|
||||||
async msg => {
|
|
||||||
await delay(
|
|
||||||
4000
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
message.delete();
|
|
||||||
msg.delete();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (
|
|
||||||
!amount
|
|
||||||
) {
|
|
||||||
return message.reply({
|
|
||||||
content:
|
|
||||||
"Danke für nichts, du Hu-"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const yourBalance =
|
|
||||||
await getNutBalance(
|
|
||||||
from.id
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
if (
|
|
||||||
amount <=
|
|
||||||
0
|
|
||||||
) {
|
|
||||||
return message.reply({
|
|
||||||
content:
|
|
||||||
`Hier wird nicht geklaut >:(\r\nDas gibt **${yourBalance}** Abzug!`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (
|
|
||||||
yourBalance <
|
|
||||||
amount
|
|
||||||
) {
|
|
||||||
return message.reply({
|
|
||||||
content:
|
|
||||||
"Du kannst nicht mehr geben als du hast!"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
let content =
|
|
||||||
`Du sendest **${amount}** Nüsse an <@${target.id}>`;
|
|
||||||
|
|
||||||
|
|
||||||
if (
|
|
||||||
amount ==
|
|
||||||
1
|
|
||||||
) {
|
|
||||||
content =
|
|
||||||
`Du sendest **eine** Nuss an <@${target.id}>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
await transferNuts(
|
|
||||||
from.id,
|
|
||||||
to.id,
|
|
||||||
amount
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
const embed =
|
|
||||||
new EmbedBuilder()
|
|
||||||
.setTitle(
|
|
||||||
"Gib Nuss!"
|
|
||||||
)
|
|
||||||
.setDescription(
|
|
||||||
content
|
|
||||||
)
|
|
||||||
.setThumbnail(
|
|
||||||
target.displayAvatarURL()
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
return message.reply({
|
|
||||||
embeds: [
|
|
||||||
embed
|
|
||||||
]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
const {
|
|
||||||
EmbedBuilder,
|
|
||||||
ActionRowBuilder,
|
|
||||||
ButtonBuilder,
|
|
||||||
ButtonStyle
|
|
||||||
} = require("discord.js");
|
|
||||||
|
|
||||||
const {
|
|
||||||
getCollections
|
|
||||||
} = require(
|
|
||||||
"../../../utils/nutEconomy"
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name:
|
|
||||||
"nutsleaderboard",
|
|
||||||
|
|
||||||
description:
|
|
||||||
"show nuts leaderboard",
|
|
||||||
|
|
||||||
aliases: [
|
|
||||||
"nl",
|
|
||||||
"tn",
|
|
||||||
"topnuts"
|
|
||||||
],
|
|
||||||
|
|
||||||
|
|
||||||
async execute(
|
|
||||||
message,
|
|
||||||
args
|
|
||||||
) {
|
|
||||||
const row =
|
|
||||||
new ActionRowBuilder()
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setLabel(
|
|
||||||
"◄"
|
|
||||||
)
|
|
||||||
.setStyle(
|
|
||||||
ButtonStyle.Primary
|
|
||||||
)
|
|
||||||
.setCustomId(
|
|
||||||
"nuts_leaderboard_left"
|
|
||||||
),
|
|
||||||
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setLabel(
|
|
||||||
"🧑"
|
|
||||||
)
|
|
||||||
.setStyle(
|
|
||||||
ButtonStyle.Primary
|
|
||||||
)
|
|
||||||
.setCustomId(
|
|
||||||
"nuts_leaderboard_self"
|
|
||||||
),
|
|
||||||
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setLabel(
|
|
||||||
"►"
|
|
||||||
)
|
|
||||||
.setStyle(
|
|
||||||
ButtonStyle.Primary
|
|
||||||
)
|
|
||||||
.setCustomId(
|
|
||||||
"nuts_leaderboard_right"
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
const {
|
|
||||||
nuts
|
|
||||||
} =
|
|
||||||
getCollections();
|
|
||||||
|
|
||||||
|
|
||||||
const skip =
|
|
||||||
0;
|
|
||||||
|
|
||||||
|
|
||||||
const nutsData =
|
|
||||||
await nuts
|
|
||||||
.find({
|
|
||||||
nuts: {
|
|
||||||
$gt:
|
|
||||||
0
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.sort({
|
|
||||||
nuts:
|
|
||||||
-1
|
|
||||||
})
|
|
||||||
.skip(
|
|
||||||
skip
|
|
||||||
)
|
|
||||||
.limit(
|
|
||||||
5
|
|
||||||
)
|
|
||||||
.toArray();
|
|
||||||
|
|
||||||
|
|
||||||
let fields;
|
|
||||||
|
|
||||||
|
|
||||||
let placements =
|
|
||||||
skip +
|
|
||||||
1;
|
|
||||||
|
|
||||||
|
|
||||||
nutsData.forEach(
|
|
||||||
data => {
|
|
||||||
fields =
|
|
||||||
(
|
|
||||||
fields
|
|
||||||
?
|
|
||||||
fields
|
|
||||||
:
|
|
||||||
""
|
|
||||||
)
|
|
||||||
+
|
|
||||||
`${placements}. <@${data.userId}> : ${data.nuts} Nuts\r\n`;
|
|
||||||
|
|
||||||
|
|
||||||
placements++;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
const embed =
|
|
||||||
new EmbedBuilder()
|
|
||||||
.setTitle(
|
|
||||||
"Nuts Leaderboard"
|
|
||||||
)
|
|
||||||
.setThumbnail(
|
|
||||||
message.guild.iconURL({
|
|
||||||
dynamic:
|
|
||||||
true
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.setDescription(
|
|
||||||
fields.toString()
|
|
||||||
)
|
|
||||||
.setColor(
|
|
||||||
"#5865F2"
|
|
||||||
)
|
|
||||||
.setFooter({
|
|
||||||
text:
|
|
||||||
"Use ◄ ► to navigate"
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
await message.reply({
|
|
||||||
embeds: [
|
|
||||||
embed
|
|
||||||
],
|
|
||||||
|
|
||||||
components: [
|
|
||||||
row
|
|
||||||
]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
const { EmbedBuilder, MessageFlags } = require("discord.js");
|
|
||||||
const { client, mClient } = require("../../../index");
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: "quotesadd",
|
|
||||||
description: "Adds a quote to the database by replying to a message.",
|
|
||||||
aliases: ["qadd", "qa"],
|
|
||||||
async execute(message) {
|
|
||||||
// Ensure the command is used as a reply.
|
|
||||||
if (!message.reference?.messageId) {
|
|
||||||
return message.reply({
|
|
||||||
content: "Please reply to the message you want to quote.",
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const { messageId, channelId, guildId } = message.reference;
|
|
||||||
|
|
||||||
let quoteMessage;
|
|
||||||
let quoteChannel;
|
|
||||||
let quoteGuild;
|
|
||||||
|
|
||||||
try {
|
|
||||||
quoteGuild = await client.guilds.fetch(guildId);
|
|
||||||
quoteChannel = await quoteGuild.channels.fetch(channelId);
|
|
||||||
quoteMessage = await quoteChannel.messages.fetch(messageId);
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
return message.reply({
|
|
||||||
content: "Unable to fetch the quoted message.",
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const msgData = {
|
|
||||||
content: quoteMessage.content,
|
|
||||||
author: quoteMessage.author,
|
|
||||||
hasEmbed: quoteMessage.embeds.length > 0,
|
|
||||||
reference: quoteMessage.reference
|
|
||||||
};
|
|
||||||
|
|
||||||
// Only populated if the quoted message is itself a reply.
|
|
||||||
let refData = null;
|
|
||||||
|
|
||||||
if (msgData.reference?.messageId) {
|
|
||||||
try {
|
|
||||||
const refGuild = await client.guilds.fetch(msgData.reference.guildId);
|
|
||||||
const refChannel = await refGuild.channels.fetch(msgData.reference.channelId);
|
|
||||||
const refMessage = await refChannel.messages.fetch(msgData.reference.messageId);
|
|
||||||
|
|
||||||
refData = {
|
|
||||||
content: refMessage.content,
|
|
||||||
author: refMessage.author,
|
|
||||||
hasEmbed: refMessage.embeds.length > 0
|
|
||||||
};
|
|
||||||
} catch (err) {
|
|
||||||
// Referenced message couldn't be fetched (deleted, inaccessible, etc.)
|
|
||||||
refData = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const db = mClient.db(process.env.M_DB);
|
|
||||||
const quotesColl = db.collection("items_quotes");
|
|
||||||
|
|
||||||
const existing = await quotesColl.findOne({
|
|
||||||
messageID: quoteMessage.id
|
|
||||||
});
|
|
||||||
|
|
||||||
if (existing) {
|
|
||||||
return message.reply({
|
|
||||||
content: "Quote already exists in the database.",
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
await quotesColl.findOneAndUpdate(
|
|
||||||
{ messageID: quoteMessage.id },
|
|
||||||
{
|
|
||||||
$set: {
|
|
||||||
messageID: quoteMessage.id,
|
|
||||||
channelID: quoteChannel.id,
|
|
||||||
guildID: quoteGuild.id,
|
|
||||||
userID: msgData.author.id,
|
|
||||||
count: 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ upsert: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
const messageLink = `https://discord.com/channels/${quoteGuild.id}/${quoteChannel.id}/${quoteMessage.id}`;
|
|
||||||
|
|
||||||
let description = "";
|
|
||||||
|
|
||||||
// Only show the replied-to message if one actually exists.
|
|
||||||
if (refData) {
|
|
||||||
description += `> ${refData.author} `;
|
|
||||||
|
|
||||||
if (refData.hasEmbed) {
|
|
||||||
description += "*an embed / a command*";
|
|
||||||
} else if (refData.content) {
|
|
||||||
description += refData.content;
|
|
||||||
} else {
|
|
||||||
description += "*no text*";
|
|
||||||
}
|
|
||||||
|
|
||||||
description += "\n↳ ";
|
|
||||||
}
|
|
||||||
|
|
||||||
description += `${msgData.author} `;
|
|
||||||
|
|
||||||
if (msgData.hasEmbed && !msgData.content) {
|
|
||||||
description += "*an embed / a command*";
|
|
||||||
} else {
|
|
||||||
description += msgData.content || "*no text*";
|
|
||||||
}
|
|
||||||
|
|
||||||
description += `\n\n${messageLink}`;
|
|
||||||
|
|
||||||
const footer = `${new Date(quoteMessage.createdTimestamp).toDateString()} #${quoteMessage.id}`;
|
|
||||||
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setTitle("- Quote Added! -")
|
|
||||||
.setURL(messageLink)
|
|
||||||
.setThumbnail(msgData.author.displayAvatarURL())
|
|
||||||
.setDescription(description)
|
|
||||||
.setFooter({ text: footer });
|
|
||||||
|
|
||||||
return message.reply({ embeds: [embed] });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,201 +0,0 @@
|
|||||||
const { SlashCommandBuilder, EmbedBuilder, MessageFlags, PermissionFlagsBits } = require('discord.js')
|
|
||||||
const { mClient } = require('../../../index')
|
|
||||||
const { configDotenv } = require('dotenv')
|
|
||||||
configDotenv()
|
|
||||||
|
|
||||||
function isValidDate(day, month) {
|
|
||||||
// Define the number of days in each month
|
|
||||||
const daysInMonth = {
|
|
||||||
1: 31, // January
|
|
||||||
2: 28, // February (fuck leap years, me an' the homies hate that)
|
|
||||||
3: 31, // March
|
|
||||||
4: 30, // April
|
|
||||||
5: 31, // May
|
|
||||||
6: 30, // June
|
|
||||||
7: 31, // July
|
|
||||||
8: 31, // August
|
|
||||||
9: 30, // September
|
|
||||||
10: 31, // October
|
|
||||||
11: 30, // November
|
|
||||||
12: 31 // December
|
|
||||||
};
|
|
||||||
|
|
||||||
// Check if month is valid
|
|
||||||
if (month < 1 || month > 12) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if day is valid for the given month
|
|
||||||
if (day < 1 || day > daysInMonth[month]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
function getNextBirthdayTimestamp(day, month) {
|
|
||||||
const now = new Date();
|
|
||||||
now.setHours(0, 0, 0, 0);
|
|
||||||
|
|
||||||
const currentYear = now.getFullYear();
|
|
||||||
|
|
||||||
let nextBirthday = new Date(currentYear, month - 1, day);
|
|
||||||
|
|
||||||
// If birthday already passed this year → next year
|
|
||||||
if (nextBirthday < now) {
|
|
||||||
nextBirthday.setFullYear(currentYear + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Math.floor(nextBirthday.getTime() / 1000); // Unix timestamp
|
|
||||||
}
|
|
||||||
async function birthdaySet(interaction) {
|
|
||||||
let target = await interaction.options.getUser('user')
|
|
||||||
let day = await interaction.options.getNumber('day')
|
|
||||||
let month = await interaction.options.getNumber('month')
|
|
||||||
|
|
||||||
|
|
||||||
if (!isValidDate(day, month)) {
|
|
||||||
return interaction.reply({ content: "Invalid Date", flags: MessageFlags.Ephemeral })
|
|
||||||
}
|
|
||||||
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const bdayColl = db.collection('items_birthdays')
|
|
||||||
|
|
||||||
const found = await bdayColl.findOne({ userID: target.id })
|
|
||||||
if (found) {
|
|
||||||
return interaction.reply({ content: "Already in Database", flags: MessageFlags.Ephemeral })
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
guildID: interaction.guild.id,
|
|
||||||
userID: target.id,
|
|
||||||
day: day,
|
|
||||||
month: month
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = await bdayColl.insertOne(data)
|
|
||||||
if (res.acknowledged) {
|
|
||||||
return interaction.reply({ content: "Birthday added successfully!" })
|
|
||||||
} else {
|
|
||||||
return interaction.reply({ content: "There was an issue!" })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function birthdayDelete(interaction) {
|
|
||||||
var target = await interaction.options.getUser('user')
|
|
||||||
const guild = await interaction.client.guilds.cache.get(interaction.guild.id)
|
|
||||||
if (!target) {
|
|
||||||
target = await guild.members.cache.get(await interaction.options.getString('id'))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!target) {
|
|
||||||
return interaction.reply({ content: "Invalid or No User specified!" })
|
|
||||||
}
|
|
||||||
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const bdayColl = db.collection('items_birthdays')
|
|
||||||
|
|
||||||
const found = await bdayColl.findOne({ userID: target.id })
|
|
||||||
if (!found) {
|
|
||||||
return interaction.reply({ content: "Not yet in Database", flags: MessageFlags.Ephemeral })
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = await bdayColl.deleteOne({ userID: target.id })
|
|
||||||
if (res.acknowledged) {
|
|
||||||
return interaction.reply({ content: "Birthday removed successfully!" })
|
|
||||||
} else {
|
|
||||||
return interaction.reply({ content: "There was an issue!" })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function birthdayGet(interaction) {
|
|
||||||
const target = await interaction.options.getUser('user');
|
|
||||||
const db = mClient.db(process.env.M_DB);
|
|
||||||
const bdayColl = db.collection('items_birthdays');
|
|
||||||
|
|
||||||
const found = await bdayColl.findOne({ userID: target.id });
|
|
||||||
if (!found) {
|
|
||||||
return interaction.reply({
|
|
||||||
content: "Date not in Database!",
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const now = new Date();
|
|
||||||
const isToday =
|
|
||||||
now.getDate() === found.day &&
|
|
||||||
now.getMonth() === (found.month - 1);
|
|
||||||
|
|
||||||
let description;
|
|
||||||
|
|
||||||
if (isToday) {
|
|
||||||
description = `IS TODAY! 🥳🎉`;
|
|
||||||
} else {
|
|
||||||
const unix = getNextBirthdayTimestamp(found.day, found.month);
|
|
||||||
description = `is on the <t:${unix}:d>\n<t:${unix}:R>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setThumbnail(target.displayAvatarURL())
|
|
||||||
.setTitle(`${target.globalName ?? target.username}'s Birthday...`)
|
|
||||||
.setDescription(description);
|
|
||||||
|
|
||||||
await interaction.reply({ embeds: [embed] });
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
data: new SlashCommandBuilder()
|
|
||||||
.setName('birthday')
|
|
||||||
.setDescription('manage birthdays')
|
|
||||||
.setDefaultMemberPermissions(PermissionFlagsBits.ManageRoles)
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s
|
|
||||||
.setName('set')
|
|
||||||
.setDescription('set date to birthday')
|
|
||||||
.addUserOption((option) =>
|
|
||||||
option
|
|
||||||
.setName('user')
|
|
||||||
.setDescription('user')
|
|
||||||
.setRequired(true))
|
|
||||||
.addNumberOption((option) =>
|
|
||||||
option
|
|
||||||
.setName('day')
|
|
||||||
.setDescription('day')
|
|
||||||
.setMinValue(1)
|
|
||||||
.setMaxValue(31)
|
|
||||||
.setRequired(true))
|
|
||||||
.addNumberOption((option) =>
|
|
||||||
option
|
|
||||||
.setName('month')
|
|
||||||
.setDescription('month')
|
|
||||||
.setMinValue(1)
|
|
||||||
.setMaxValue(12)
|
|
||||||
.setRequired(true))
|
|
||||||
)
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s
|
|
||||||
.setName('delete')
|
|
||||||
.setDescription('deletes a birthday')
|
|
||||||
.addUserOption((option) =>
|
|
||||||
option.setName('user').setDescription('user'))
|
|
||||||
.addStringOption((option) =>
|
|
||||||
option.setName('id').setDescription('ID')))
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s
|
|
||||||
.setName('get')
|
|
||||||
.setDescription('gets a birthday')
|
|
||||||
.addUserOption((option) =>
|
|
||||||
option.setName('user').setDescription('user').setRequired(true))),
|
|
||||||
async execute(interaction) {
|
|
||||||
switch (interaction.options._subcommand) {
|
|
||||||
case 'set':
|
|
||||||
birthdaySet(interaction)
|
|
||||||
break;
|
|
||||||
case 'delete':
|
|
||||||
birthdayDelete(interaction)
|
|
||||||
break;
|
|
||||||
case 'get':
|
|
||||||
birthdayGet(interaction)
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,172 +0,0 @@
|
|||||||
const { SlashCommandBuilder, Events, MessageFlags, PermissionFlagsBits } = require('discord.js')
|
|
||||||
const { mClient } = require('../../../index')
|
|
||||||
require('dotenv').config()
|
|
||||||
|
|
||||||
async function channelSet(interaction) {
|
|
||||||
const channel = interaction.options.getChannel('channel')
|
|
||||||
const purpose = interaction.options.getString('purpose')
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const channelColl = db.collection('config_channels')
|
|
||||||
|
|
||||||
await channelColl.findOneAndUpdate({
|
|
||||||
$and: [{ guildID: channel.guild.id }, { purpose: purpose }]
|
|
||||||
}, {
|
|
||||||
$set: {
|
|
||||||
guildID: channel.guild.id,
|
|
||||||
purpose: purpose,
|
|
||||||
channelID: channel.id
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
upsert: true
|
|
||||||
})
|
|
||||||
|
|
||||||
return await interaction.editReply({
|
|
||||||
content: `Set <#${channel.id}> as ${purpose} channel!`, flags: MessageFlags.Ephemeral
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async function channelSimulate(interaction) {
|
|
||||||
const purpose = interaction.options.getString('purpose')
|
|
||||||
switch (purpose) {
|
|
||||||
case 'birthday':
|
|
||||||
await interaction.client.emit('Birthday', interaction.member)
|
|
||||||
break;
|
|
||||||
case 'wge':
|
|
||||||
// For Future WGE Use
|
|
||||||
break;
|
|
||||||
case 'welcome':
|
|
||||||
await interaction.client.emit(Events.GuildMemberAdd, interaction.member)
|
|
||||||
break;
|
|
||||||
case 'logs':
|
|
||||||
// For Future Log Use
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return interaction.reply({ content: 'Done.', flags: MessageFlags.Ephemeral })
|
|
||||||
}
|
|
||||||
|
|
||||||
async function roleSet(interaction) {
|
|
||||||
const guild = interaction.guild
|
|
||||||
const purpose = interaction.options.getString('purpose')
|
|
||||||
const role = interaction.options.getRole('role')
|
|
||||||
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const roleColl = db.collection('config_roles')
|
|
||||||
|
|
||||||
switch (purpose) {
|
|
||||||
case 'birthday':
|
|
||||||
await roleColl.findOneAndUpdate({
|
|
||||||
$and: [{ guildID: guild.id }, { purpose: purpose }]
|
|
||||||
}, {
|
|
||||||
$set: {
|
|
||||||
guildID: guild.id,
|
|
||||||
purpose: purpose,
|
|
||||||
roleID: role.id
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
upsert: true
|
|
||||||
})
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return await interaction.editReply({
|
|
||||||
content: `Set ${role} as default role for ${purpose} in ${guild} `
|
|
||||||
})
|
|
||||||
}
|
|
||||||
module.exports = {
|
|
||||||
data: new SlashCommandBuilder()
|
|
||||||
.setName('config')
|
|
||||||
.setDescription('configurations for admins')
|
|
||||||
.setDefaultMemberPermissions(PermissionFlagsBits.ManageChannels)
|
|
||||||
.addSubcommandGroup(sg =>
|
|
||||||
sg
|
|
||||||
.setName('channels')
|
|
||||||
.setDescription('configure channels for certain events')
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s.setName('set')
|
|
||||||
.setDescription('sets channel')
|
|
||||||
.addStringOption(o =>
|
|
||||||
o.setName('purpose').setDescription('set the purpose').setRequired(true).addChoices({
|
|
||||||
name: 'birthday',
|
|
||||||
value: 'birthday'
|
|
||||||
}, {
|
|
||||||
name: 'welcome',
|
|
||||||
value: 'welcome'
|
|
||||||
}, {
|
|
||||||
name: 'logs',
|
|
||||||
value: 'logs'
|
|
||||||
}, {
|
|
||||||
name: 'wge',
|
|
||||||
value: 'wge'
|
|
||||||
}))
|
|
||||||
.addChannelOption(c =>
|
|
||||||
c.setName('channel').setDescription('choose a channel').setRequired(true)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s
|
|
||||||
.setName('simulate')
|
|
||||||
.setDescription('simulate a specific channel event')
|
|
||||||
.addStringOption(o =>
|
|
||||||
o.setName('purpose').setDescription('set the purpose').setRequired(true).addChoices({
|
|
||||||
name: 'birthday',
|
|
||||||
value: 'birthday'
|
|
||||||
}, {
|
|
||||||
name: 'welcome',
|
|
||||||
value: 'welcome'
|
|
||||||
}, {
|
|
||||||
name: 'logs',
|
|
||||||
value: 'logs'
|
|
||||||
}, {
|
|
||||||
name: 'wge',
|
|
||||||
value: 'wge'
|
|
||||||
}))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.addSubcommandGroup(sg =>
|
|
||||||
sg.setName('roles')
|
|
||||||
.setDescription('configure roles for certain events')
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s.setName('set')
|
|
||||||
.setDescription('sets roles')
|
|
||||||
.addStringOption(o =>
|
|
||||||
o.setName('purpose').setDescription('set the purpose').setRequired(true).addChoices({
|
|
||||||
name: 'birthday',
|
|
||||||
value: 'birthday'
|
|
||||||
}))
|
|
||||||
.addRoleOption(c =>
|
|
||||||
c.setName('role').setDescription('choose a role').setRequired(true)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
async execute(interaction) {
|
|
||||||
switch (interaction.options._group) {
|
|
||||||
case 'channels':
|
|
||||||
switch (interaction.options._subcommand) {
|
|
||||||
case 'set':
|
|
||||||
await interaction.deferReply()
|
|
||||||
channelSet(interaction)
|
|
||||||
break;
|
|
||||||
case 'simulate':
|
|
||||||
channelSimulate(interaction)
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'roles':
|
|
||||||
switch (interaction.options._subcommand) {
|
|
||||||
case 'set':
|
|
||||||
await interaction.deferReply()
|
|
||||||
roleSet(interaction)
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
const { SlashCommandBuilder } = require("discord.js");
|
|
||||||
const ping = require("../../../utils/ping");
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
data: new SlashCommandBuilder()
|
|
||||||
.setName('ping')
|
|
||||||
.setDescription('dev tool'),
|
|
||||||
async execute(interaction) {
|
|
||||||
return ping(interaction, null, 'slash')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,249 +0,0 @@
|
|||||||
const {
|
|
||||||
SlashCommandBuilder,
|
|
||||||
EmbedBuilder,
|
|
||||||
ActionRowBuilder,
|
|
||||||
ButtonBuilder,
|
|
||||||
ButtonStyle,
|
|
||||||
MessageFlags
|
|
||||||
} = require('discord.js');
|
|
||||||
const { mClient } = require('../../..');
|
|
||||||
require('dotenv').config()
|
|
||||||
|
|
||||||
const db = mClient.db(process.env.M_DB); // adjust if needed
|
|
||||||
const coll = db.collection('items_ezd');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
data: new SlashCommandBuilder()
|
|
||||||
.setName('ezd')
|
|
||||||
.setDescription('Ersti Zweiti Dritti')
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s
|
|
||||||
.setName('show')
|
|
||||||
.setDescription('Zeigt die täglichen Erster/Zweiter/Dritter Ergebnisse')
|
|
||||||
)
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s
|
|
||||||
.setName('leaderboard')
|
|
||||||
.setDescription('Zeigt die Rangliste der EZDler')
|
|
||||||
)
|
|
||||||
,
|
|
||||||
async execute(interaction, client) {
|
|
||||||
switch (interaction.options._subcommand) {
|
|
||||||
case 'show':
|
|
||||||
ezdShow(interaction)
|
|
||||||
break;
|
|
||||||
case 'leaderboard':
|
|
||||||
ezdLeaderboard(interaction)
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// helper: shift YYYY-MM-DD safely
|
|
||||||
function shiftDate(dateStr, offset) {
|
|
||||||
const d = new Date(dateStr);
|
|
||||||
d.setDate(d.getDate() + offset);
|
|
||||||
return d.toISOString().slice(0, 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function ezdShow(interaction) {
|
|
||||||
const today = new Date().toLocaleDateString("en-CA", {
|
|
||||||
timeZone: "Europe/Berlin"
|
|
||||||
});
|
|
||||||
|
|
||||||
let currentDate = today;
|
|
||||||
|
|
||||||
const sessionId = `${interaction.user.id}-${Date.now()}`;
|
|
||||||
|
|
||||||
const buildEmbed = (doc, date) => {
|
|
||||||
const p = doc?.positions || {};
|
|
||||||
|
|
||||||
const line = (emoji, label, key) => {
|
|
||||||
const v = p[key];
|
|
||||||
return `${emoji} **${label}:** ${v ? `<@${v.userId}>` : "—"}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
const germanDate = new Date(`${date}T00:00:00`).toLocaleDateString("de-DE", {
|
|
||||||
timeZone: "Europe/Berlin",
|
|
||||||
day: "2-digit",
|
|
||||||
month: "2-digit",
|
|
||||||
year: "numeric"
|
|
||||||
});
|
|
||||||
|
|
||||||
return new EmbedBuilder()
|
|
||||||
.setTitle(`📊 EZD Übersicht – ${germanDate}`)
|
|
||||||
.setColor(0x2b2d31)
|
|
||||||
.setDescription([
|
|
||||||
line("🥇", "Ersti", "Ersti"),
|
|
||||||
line("🥈", "Zweiti", "Zweiti"),
|
|
||||||
line("🥉", "Dritti", "Dritti")
|
|
||||||
].join("\n"));
|
|
||||||
};
|
|
||||||
|
|
||||||
const buildButtons = (date) => {
|
|
||||||
return new ActionRowBuilder().addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setCustomId(`ezd_prev`)
|
|
||||||
.setLabel("⬅️")
|
|
||||||
.setStyle(ButtonStyle.Secondary),
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setCustomId(`ezd_next`)
|
|
||||||
.setLabel("➡️")
|
|
||||||
.setStyle(ButtonStyle.Secondary)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const doc = await coll.findOne({ date: currentDate });
|
|
||||||
|
|
||||||
const msg = await interaction.reply({
|
|
||||||
embeds: [buildEmbed(doc, currentDate)],
|
|
||||||
components: [buildButtons(currentDate)]
|
|
||||||
});
|
|
||||||
|
|
||||||
const collector = msg.createMessageComponentCollector({
|
|
||||||
time: 1000 * 60 * 10 // 10 minutes
|
|
||||||
});
|
|
||||||
|
|
||||||
collector.on("collect", async (btn) => {
|
|
||||||
if (btn.user.id !== interaction.user.id) {
|
|
||||||
return btn.reply({
|
|
||||||
content: "❌ Diese Buttons gehören nicht dir.",
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (btn.customId === `ezd_prev`) {
|
|
||||||
currentDate = shiftDate(currentDate, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (btn.customId === `ezd_next`) {
|
|
||||||
currentDate = shiftDate(currentDate, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const newDoc = await coll.findOne({ date: currentDate });
|
|
||||||
|
|
||||||
await btn.update({
|
|
||||||
embeds: [buildEmbed(newDoc, currentDate)],
|
|
||||||
components: [buildButtons(currentDate)]
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function ezdLeaderboard(interaction) {
|
|
||||||
const docs = await coll.find({}).toArray();
|
|
||||||
|
|
||||||
const leaderboard = new Map();
|
|
||||||
|
|
||||||
const add = (entry, place) => {
|
|
||||||
if (!entry?.userId) return;
|
|
||||||
|
|
||||||
if (!leaderboard.has(entry.userId)) {
|
|
||||||
leaderboard.set(entry.userId, {
|
|
||||||
userId: entry.userId,
|
|
||||||
points: 0,
|
|
||||||
Ersti: 0,
|
|
||||||
Zweiti: 0,
|
|
||||||
Dritti: 0
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const user = leaderboard.get(entry.userId);
|
|
||||||
|
|
||||||
user[place]++;
|
|
||||||
|
|
||||||
if (place === "Ersti") user.points += 3;
|
|
||||||
if (place === "Zweiti") user.points += 2;
|
|
||||||
if (place === "Dritti") user.points += 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
for (const doc of docs) {
|
|
||||||
const p = doc.positions || {};
|
|
||||||
|
|
||||||
add(p.Ersti, "Ersti");
|
|
||||||
add(p.Zweiti, "Zweiti");
|
|
||||||
add(p.Dritti, "Dritti");
|
|
||||||
}
|
|
||||||
|
|
||||||
const users = [...leaderboard.values()].sort((a, b) => {
|
|
||||||
if (b.points !== a.points) return b.points - a.points;
|
|
||||||
if (b.Ersti !== a.Ersti) return b.Ersti - a.Ersti;
|
|
||||||
if (b.Zweiti !== a.Zweiti) return b.Zweiti - a.Zweiti;
|
|
||||||
return b.Dritti - a.Dritti;
|
|
||||||
});
|
|
||||||
|
|
||||||
const PAGE_SIZE = 5;
|
|
||||||
const pageCount = Math.max(1, Math.ceil(users.length / PAGE_SIZE));
|
|
||||||
let page = 0;
|
|
||||||
|
|
||||||
const buildEmbed = () => {
|
|
||||||
const slice = users.slice(
|
|
||||||
page * PAGE_SIZE,
|
|
||||||
page * PAGE_SIZE + PAGE_SIZE
|
|
||||||
);
|
|
||||||
|
|
||||||
const description = slice.length
|
|
||||||
? slice.map((u, i) => {
|
|
||||||
const rank = page * PAGE_SIZE + i + 1;
|
|
||||||
|
|
||||||
return `**#${rank}** <@${u.userId}> — **${u.points}**
|
|
||||||
🥇 ${u.Ersti} · 🥈 ${u.Zweiti} · 🥉 ${u.Dritti}`;
|
|
||||||
}).join("\n\n")
|
|
||||||
: "—";
|
|
||||||
|
|
||||||
return new EmbedBuilder()
|
|
||||||
.setTitle("🏆 EZD Rangliste")
|
|
||||||
.setColor(0x2b2d31)
|
|
||||||
.setDescription(description);
|
|
||||||
};
|
|
||||||
|
|
||||||
const buildButtons = () =>
|
|
||||||
new ActionRowBuilder().addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setCustomId("ezd_lb_prev")
|
|
||||||
.setLabel("⬅️")
|
|
||||||
.setStyle(ButtonStyle.Secondary),
|
|
||||||
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setCustomId("ezd_lb_page")
|
|
||||||
.setLabel(`${page + 1}/${pageCount}`)
|
|
||||||
.setStyle(ButtonStyle.Primary)
|
|
||||||
.setDisabled(true),
|
|
||||||
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setCustomId("ezd_lb_next")
|
|
||||||
.setLabel("➡️")
|
|
||||||
.setStyle(ButtonStyle.Secondary)
|
|
||||||
);
|
|
||||||
|
|
||||||
const msg = await interaction.reply({
|
|
||||||
embeds: [buildEmbed()],
|
|
||||||
components: [buildButtons()]
|
|
||||||
});
|
|
||||||
|
|
||||||
const collector = msg.createMessageComponentCollector({
|
|
||||||
time: 1000 * 60 * 10
|
|
||||||
});
|
|
||||||
|
|
||||||
collector.on("collect", async btn => {
|
|
||||||
if (btn.user.id !== interaction.user.id) {
|
|
||||||
return btn.reply({
|
|
||||||
content: "❌ Diese Buttons gehören nicht dir.",
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (btn.customId === "ezd_lb_prev")
|
|
||||||
page = (page - 1 + pageCount) % pageCount;
|
|
||||||
|
|
||||||
if (btn.customId === "ezd_lb_next")
|
|
||||||
page = (page + 1) % pageCount;
|
|
||||||
|
|
||||||
await btn.update({
|
|
||||||
embeds: [buildEmbed()],
|
|
||||||
components: [buildButtons()]
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,277 +0,0 @@
|
|||||||
const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, UserSelectMenuBuilder, MessageFlags } = require('discord.js')
|
|
||||||
const { mClient } = require('../../../index')
|
|
||||||
require('dotenv').config()
|
|
||||||
function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }
|
|
||||||
|
|
||||||
async function honorHoner(interaction) {
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const honorsColl = db.collection('items_honors')
|
|
||||||
|
|
||||||
const target = await interaction.options.getUser('target')
|
|
||||||
const reason = `[+] ${await interaction.options.getString('reason') ?? 'No reason provided'}`
|
|
||||||
|
|
||||||
const theirHonorLevel = await honorsColl.findOne({ userID: target.id })
|
|
||||||
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setTitle('- Honor Up! -')
|
|
||||||
.setDescription(`Willst du wirklich <@${target.id}> einen **Honor** geben?\r\n[Grund: ${reason}]`)
|
|
||||||
.addFields({
|
|
||||||
name: 'Current Honor Level', value: `${theirHonorLevel?.honors ?? 0} (**+1**)`
|
|
||||||
})
|
|
||||||
.setThumbnail(target.displayAvatarURL())
|
|
||||||
const row = new ActionRowBuilder()
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setLabel('✔')
|
|
||||||
.setCustomId('honor_multi_confirm')
|
|
||||||
.setStyle(ButtonStyle.Success)
|
|
||||||
)
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setLabel('✖')
|
|
||||||
.setCustomId('abort')
|
|
||||||
.setStyle(ButtonStyle.Danger)
|
|
||||||
)
|
|
||||||
await interaction.reply({
|
|
||||||
embeds: [embed],
|
|
||||||
components: [row],
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
})
|
|
||||||
}
|
|
||||||
async function honerDishonor(interaction) {
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const honorsColl = db.collection('items_honors')
|
|
||||||
|
|
||||||
const target = await interaction.options.getUser('target')
|
|
||||||
const reason = `[-] ${await interaction.options.getString('reason') ?? 'No reason provided'}`
|
|
||||||
const theirHonorLevel = await honorsColl.findOne({ userID: target.id })
|
|
||||||
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setTitle('- Honor Down! -')
|
|
||||||
.setDescription(`Willst du wirklich <@${target.id}> einen **Dishonor** geben?\r\n[Grund: ${reason}]`)
|
|
||||||
.addFields({
|
|
||||||
name: 'Current Honor Level', value: `${theirHonorLevel?.honors ?? 0} (**-1**)`
|
|
||||||
})
|
|
||||||
.setThumbnail(target.displayAvatarURL())
|
|
||||||
const row = new ActionRowBuilder()
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setLabel('✔')
|
|
||||||
.setCustomId('honor_multi_confirm')
|
|
||||||
.setStyle(ButtonStyle.Success)
|
|
||||||
)
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setLabel('✖')
|
|
||||||
.setCustomId('abort')
|
|
||||||
.setStyle(ButtonStyle.Danger)
|
|
||||||
)
|
|
||||||
await interaction.reply({
|
|
||||||
embeds: [embed],
|
|
||||||
components: [row],
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
})
|
|
||||||
}
|
|
||||||
async function honorLeaderboard(interaction) {
|
|
||||||
const row = new ActionRowBuilder()
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setLabel('◄')
|
|
||||||
.setStyle(ButtonStyle.Primary)
|
|
||||||
.setCustomId('honors_leaderboard_left')
|
|
||||||
)
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setLabel('🧑')
|
|
||||||
.setStyle(ButtonStyle.Primary)
|
|
||||||
.setCustomId('honors_leaderboard_self')
|
|
||||||
)
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setLabel('►')
|
|
||||||
.setStyle(ButtonStyle.Primary)
|
|
||||||
.setCustomId('honors_leaderboard_right')
|
|
||||||
)
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const honorsColl = db.collection('items_honors')
|
|
||||||
let skip = 0
|
|
||||||
const honorsData = await honorsColl.find({}).sort({ honors: -1 }).skip(skip).limit(5).toArray()
|
|
||||||
let fields
|
|
||||||
let placements = skip + 1
|
|
||||||
honorsData.forEach((data) => {
|
|
||||||
fields = (fields ? fields : '') + (`${placements}. <@${data.userID}> : ${data.honors} Honors\r\n`)
|
|
||||||
})
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setTitle('- Honors Leaderboard -')
|
|
||||||
.setThumbnail(interaction.guild.iconURL({ dynamic: true}))
|
|
||||||
.setDescription(fields.toString())
|
|
||||||
.setColor('#5865F2') // Discord's blurple color
|
|
||||||
.setFooter({ text: 'Use ◄ ► to navigate' });
|
|
||||||
await interaction.editReply({
|
|
||||||
embeds: [embed],
|
|
||||||
components: [row]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
async function honorHistory(interaction) {
|
|
||||||
var target = interaction.options.getUser('target')
|
|
||||||
if (!target) { target = interaction.user }
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const reasonsColl = db.collection('history_honors')
|
|
||||||
var history = await reasonsColl.findOne({ userID: target.id })
|
|
||||||
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setTitle('- Honor History -')
|
|
||||||
.setThumbnail(target.displayAvatarURL())
|
|
||||||
|
|
||||||
if (history) {
|
|
||||||
let temp = ''
|
|
||||||
history.reasons.forEach(reason => {
|
|
||||||
temp += reason + '\r\n'
|
|
||||||
})
|
|
||||||
embed.setDescription(temp)
|
|
||||||
}
|
|
||||||
await interaction.editReply({ embeds: [embed] })
|
|
||||||
}
|
|
||||||
async function honorCheck(interaction) {
|
|
||||||
var target = interaction.options.getUser('target')
|
|
||||||
if (!target) { target = interaction.user }
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const honorsColl = db.collection('items_honors')
|
|
||||||
var honors = await honorsColl.findOne({ userID: target.id })
|
|
||||||
honors = honors?.honors ?? 0
|
|
||||||
|
|
||||||
if (!honors) {
|
|
||||||
content = 'Choose a goddamn side!'
|
|
||||||
} else {
|
|
||||||
if (honors === -20) {
|
|
||||||
content = 'They are is at max Dishonor Level! <:lowhonor:748176295132790786> <:lowhonor:748176295132790786> <:lowhonor:748176295132790786>\n```' + `You don't get to live a bad life and have good things happen to you. - Arthur M.` + '```'
|
|
||||||
} else if (honors === 20) {
|
|
||||||
content = 'They are at max Honor Level! <:highhonor:748176295535443968> <:highhonor:748176295535443968> <:highhonor:748176295535443968>'
|
|
||||||
} else if (honors > 0) {
|
|
||||||
content = 'real good, boah, REAL GOOD! <:highhonor:748176295535443968>'
|
|
||||||
} else if (honors < 0) {
|
|
||||||
content = 'What happened to Loyalty?! <:lowhonor:748176295132790786>'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setTitle('- Honor Check -')
|
|
||||||
.setDescription(`${target} has an Honor Level of **${honors}**!`)
|
|
||||||
.setThumbnail(target.displayAvatarURL())
|
|
||||||
.addFields({ name: '\u200B', value: `*${content}*` })
|
|
||||||
|
|
||||||
await interaction.editReply({
|
|
||||||
embeds: [embed]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
async function honorMenu(interaction) {
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setTitle('- Honor Menu! -')
|
|
||||||
.setDescription('- Choose someone from the Select Menu below\r\n- Choose Honor Dishonor, or History\r\n- Confirm your Selection')
|
|
||||||
.setThumbnail(interaction.guild.iconURL())
|
|
||||||
const row = new ActionRowBuilder()
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setEmoji(`<:honorhigh:748176295535443968>`)
|
|
||||||
.setCustomId('honor_menu_honor')
|
|
||||||
.setStyle(ButtonStyle.Success)
|
|
||||||
)
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setEmoji(`<:honorlow:748176295132790786>`)
|
|
||||||
.setCustomId('honor_menu_dishonor')
|
|
||||||
.setStyle(ButtonStyle.Danger)
|
|
||||||
)
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setEmoji(`❌`)
|
|
||||||
.setCustomId('abort')
|
|
||||||
.setStyle(ButtonStyle.Secondary)
|
|
||||||
)
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setEmoji('📜')
|
|
||||||
.setCustomId('honor_menu_history')
|
|
||||||
.setStyle(ButtonStyle.Secondary)
|
|
||||||
)
|
|
||||||
const select = new ActionRowBuilder()
|
|
||||||
.addComponents(
|
|
||||||
new UserSelectMenuBuilder()
|
|
||||||
.setCustomId('honor_menu_mentionable')
|
|
||||||
.setPlaceholder('Select a User')
|
|
||||||
|
|
||||||
)
|
|
||||||
|
|
||||||
await interaction.reply({
|
|
||||||
embeds: [embed],
|
|
||||||
components: [select, row],
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
})
|
|
||||||
}
|
|
||||||
module.exports = {
|
|
||||||
data: new SlashCommandBuilder()
|
|
||||||
.setName('honors')
|
|
||||||
.setDescription('rund um den honor')
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s
|
|
||||||
.setName('honor')
|
|
||||||
.setDescription('honor someone')
|
|
||||||
.addUserOption(o => o.setName('target').setDescription('wer wird gehonored?').setRequired(true))
|
|
||||||
.addStringOption(o => o.setName('reason').setDescription('reason?'))
|
|
||||||
)
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s
|
|
||||||
.setName('dishonor')
|
|
||||||
.setDescription('dishonor someone')
|
|
||||||
.addUserOption(o => o.setName('target').setDescription('wer wird gehonored?').setRequired(true))
|
|
||||||
.addStringOption(o => o.setName('reason').setDescription('reason?'))
|
|
||||||
)
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s
|
|
||||||
.setName('check')
|
|
||||||
.setDescription("check someone's honor level")
|
|
||||||
.addUserOption(o => o.setName('target').setDescription('wer wird gehonored?'))
|
|
||||||
)
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s
|
|
||||||
.setName('history')
|
|
||||||
.setDescription("check someone's honor history")
|
|
||||||
.addUserOption(o => o.setName('target').setDescription('von wem?'))
|
|
||||||
)
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s
|
|
||||||
.setName('leaderboard')
|
|
||||||
.setDescription("check who's got the most honor")
|
|
||||||
)
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s
|
|
||||||
.setName('menu')
|
|
||||||
.setDescription('WIP universal honor menu'))
|
|
||||||
,
|
|
||||||
async execute(interaction) {
|
|
||||||
switch (interaction.options._subcommand) {
|
|
||||||
case 'honor':
|
|
||||||
honorHoner(interaction)
|
|
||||||
break;
|
|
||||||
case 'dishonor':
|
|
||||||
honerDishonor(interaction)
|
|
||||||
break;
|
|
||||||
case 'leaderboard':
|
|
||||||
await interaction.deferReply()
|
|
||||||
honorLeaderboard(interaction)
|
|
||||||
break;
|
|
||||||
case 'history':
|
|
||||||
await interaction.deferReply()
|
|
||||||
honorHistory(interaction)
|
|
||||||
break;
|
|
||||||
case 'check':
|
|
||||||
await interaction.deferReply()
|
|
||||||
honorCheck(interaction)
|
|
||||||
break;
|
|
||||||
case 'menu':
|
|
||||||
honorMenu(interaction)
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
// commands/applications/nutHub.js
|
|
||||||
|
|
||||||
const {
|
|
||||||
SlashCommandBuilder
|
|
||||||
} = require("discord.js");
|
|
||||||
|
|
||||||
const {
|
|
||||||
showNutHub
|
|
||||||
} = require(
|
|
||||||
"../../../utils/nutHub"
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
data:
|
|
||||||
new SlashCommandBuilder()
|
|
||||||
.setName(
|
|
||||||
"nuthub"
|
|
||||||
)
|
|
||||||
.setDescription(
|
|
||||||
"open the Nut Hub"
|
|
||||||
),
|
|
||||||
|
|
||||||
|
|
||||||
async execute(
|
|
||||||
interaction
|
|
||||||
) {
|
|
||||||
return showNutHub(
|
|
||||||
interaction
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,426 +0,0 @@
|
|||||||
/*
|
|
||||||
Random By Year?
|
|
||||||
Counter (Leaderboard)
|
|
||||||
*/
|
|
||||||
const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, UserSelectMenuBuilder, MessageFlags } = require('discord.js')
|
|
||||||
const { mClient, client } = require('../../../index')
|
|
||||||
|
|
||||||
require('dotenv').config()
|
|
||||||
function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }
|
|
||||||
|
|
||||||
async function quotesAdd(interaction) {
|
|
||||||
const messageLink = await interaction.options.getString('link')
|
|
||||||
//regex for message link
|
|
||||||
const regex = /^https:\/\/discord\.com\/channels\/\d+\/\d+\/\d+$/
|
|
||||||
|
|
||||||
if (!messageLink.match(regex)) {
|
|
||||||
return await interaction.editReply({
|
|
||||||
content: `Invalid URL`,
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
let temp = messageLink.split('/')
|
|
||||||
let messageID = temp[temp.length - 1]
|
|
||||||
let channelID = temp[temp.length - 2]
|
|
||||||
let guildID = temp[temp.length - 3]
|
|
||||||
|
|
||||||
const guild = await client.guilds.fetch(guildID)
|
|
||||||
const channel = await guild.channels.fetch(channelID)
|
|
||||||
const message = await channel.messages.fetch(messageID)
|
|
||||||
|
|
||||||
let refData = null
|
|
||||||
|
|
||||||
let msgData = {
|
|
||||||
content: message.content,
|
|
||||||
author: message.author,
|
|
||||||
reference: message.reference,
|
|
||||||
embed: message.embeds.length > 0 ? 'embed' : null
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msgData.reference) {
|
|
||||||
let refGuild = await client.guilds.fetch(msgData.reference.guildId)
|
|
||||||
let refChannel = await refGuild.channels.fetch(msgData.reference.channelId)
|
|
||||||
let refMessage = await refChannel.messages.fetch(msgData.reference.messageId)
|
|
||||||
|
|
||||||
|
|
||||||
refData = {
|
|
||||||
content: refMessage.content,
|
|
||||||
author: await refMessage.author,
|
|
||||||
embed: await refMessage.embeds.length > 0 ? 'embed' : null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const quotesColl = db.collection('items_quotes')
|
|
||||||
const found = await quotesColl.findOne({ messageID: messageID })
|
|
||||||
if (found) { return await interaction.editReply({ content: 'Quote Already in Database', flags: MessageFlags.Ephemeral }) }
|
|
||||||
await quotesColl.findOneAndUpdate({ messageID: messageID }, {
|
|
||||||
$set: {
|
|
||||||
messageID: messageID,
|
|
||||||
channelID: channelID,
|
|
||||||
guildID: guildID,
|
|
||||||
userID: msgData.author.id,
|
|
||||||
count: 0
|
|
||||||
}
|
|
||||||
}, { upsert: true })
|
|
||||||
|
|
||||||
var description = ''
|
|
||||||
if (refData) {
|
|
||||||
description += `> ${refData.author}`
|
|
||||||
if (refData.embed) {
|
|
||||||
description += '*an embed / a command* '
|
|
||||||
} else {
|
|
||||||
description += refData.content
|
|
||||||
}
|
|
||||||
description += `\r\n↳`
|
|
||||||
}
|
|
||||||
description += `${msgData.author} ${msgData.content}\r\n\r\n${messageLink}`
|
|
||||||
let timestamp = new Date(message.createdTimestamp)
|
|
||||||
let footer = timestamp.toDateString().toString()
|
|
||||||
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setThumbnail(msgData.author.displayAvatarURL())
|
|
||||||
.setURL(messageLink)
|
|
||||||
.setTitle(`- Quote Added! -`)
|
|
||||||
.setDescription(description)
|
|
||||||
.setFooter({ text: (footer + ' #' + messageID) })
|
|
||||||
await interaction.editReply({ embeds: [embed] })
|
|
||||||
}
|
|
||||||
async function quotesRemove(interaction) {
|
|
||||||
const id = await interaction.options.getString('id')
|
|
||||||
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const quotesColl = db.collection('items_quotes')
|
|
||||||
const found = await quotesColl.findOne({ messageID: id })
|
|
||||||
if (!found) { return await interaction.reply({ content: 'ID not found!', flags: MessageFlags.Ephemeral }) }
|
|
||||||
|
|
||||||
await quotesColl.deleteOne({ messageID: id })
|
|
||||||
|
|
||||||
return interaction.reply({ content: 'Quote successfully removed!', flags: MessageFlags.Ephemeral })
|
|
||||||
}
|
|
||||||
async function quotesSearch(interaction) {
|
|
||||||
const id = interaction.options.getString("id")
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const quotesColl = db.collection('items_quotes')
|
|
||||||
const found = await quotesColl.findOne({ messageID: id })
|
|
||||||
if (!found) { return await interaction.reply({ content: 'ID not found!', flags: MessageFlags.Ephemeral }) }
|
|
||||||
|
|
||||||
|
|
||||||
const guild = await client.guilds.fetch(found.guildID)
|
|
||||||
const channel = await guild.channels.fetch(found.channelID)
|
|
||||||
const message = await channel.messages.fetch(found.messageID)
|
|
||||||
|
|
||||||
let refData = null
|
|
||||||
|
|
||||||
let msgData = {
|
|
||||||
content: message.content,
|
|
||||||
author: message.author,
|
|
||||||
reference: message.reference,
|
|
||||||
embed: message.embeds.length > 0 ? 'embed' : null
|
|
||||||
}
|
|
||||||
|
|
||||||
quotesColl.findOneAndUpdate({
|
|
||||||
messageID: found.messageID
|
|
||||||
}, {
|
|
||||||
$inc: { count: 1 }
|
|
||||||
}, {
|
|
||||||
upsert: true
|
|
||||||
})
|
|
||||||
|
|
||||||
if (msgData.reference?.messageId) {
|
|
||||||
let refGuild = await client.guilds.fetch(msgData.reference.guildId)
|
|
||||||
let refChannel = await refGuild.channels.fetch(msgData.reference.channelId)
|
|
||||||
let refMessage = await refChannel.messages.fetch(msgData.reference.messageId)
|
|
||||||
|
|
||||||
refData = {
|
|
||||||
content: refMessage.content,
|
|
||||||
author: await refMessage.author,
|
|
||||||
embed: await refMessage.embeds.length > 0 ? 'embed' : null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var description = ''
|
|
||||||
if (refData) {
|
|
||||||
description += `> ${refData.author}`
|
|
||||||
if (refData.embed) {
|
|
||||||
description += '*an embed / a command* '
|
|
||||||
} else {
|
|
||||||
description += refData.content
|
|
||||||
}
|
|
||||||
description += `\r\n↳`
|
|
||||||
}
|
|
||||||
let messageLink = `https://discord.com/channels/${found.guildID}/${found.channelID}/${found.messageID}`
|
|
||||||
description += `${msgData.author} ${msgData.content}\r\n\r\n${messageLink}`
|
|
||||||
let timestamp = new Date(message.createdTimestamp)
|
|
||||||
let footer = timestamp.toDateString().toString()
|
|
||||||
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setThumbnail(msgData.author.displayAvatarURL())
|
|
||||||
.setURL(messageLink)
|
|
||||||
.setTitle(`- Quote Found! -`)
|
|
||||||
.setDescription(description)
|
|
||||||
.setFooter({ text: (footer + ' #' + found.messageID) })
|
|
||||||
await interaction.reply({ embeds: [embed] })
|
|
||||||
|
|
||||||
}
|
|
||||||
async function quotesRandom(interaction) {
|
|
||||||
var user = interaction.options.getUser("by")
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const quotesColl = db.collection('items_quotes')
|
|
||||||
var rdm
|
|
||||||
if (user) {
|
|
||||||
rdm = await quotesColl.aggregate([
|
|
||||||
{
|
|
||||||
$match: { userID: user.id },
|
|
||||||
}, {
|
|
||||||
$sample: { size: 1 }
|
|
||||||
}
|
|
||||||
]).toArray()
|
|
||||||
} else {
|
|
||||||
rdm = await quotesColl.aggregate([
|
|
||||||
{
|
|
||||||
$sample: { size: 1 }
|
|
||||||
}
|
|
||||||
]).toArray()
|
|
||||||
}
|
|
||||||
const found = rdm[0]
|
|
||||||
if (!found) { return await interaction.reply({ content: 'No Entry Found.', flags: MessageFlags.Ephemeral }) }
|
|
||||||
const guild = await client.guilds.fetch(found.guildID)
|
|
||||||
const channel = await guild.channels.fetch(found.channelID)
|
|
||||||
const message = await channel.messages.fetch(found.messageID)
|
|
||||||
|
|
||||||
let refData = null
|
|
||||||
|
|
||||||
let msgData = {
|
|
||||||
content: message.content,
|
|
||||||
author: message.author,
|
|
||||||
reference: message.reference,
|
|
||||||
embed: message.embeds.length > 0 ? 'embed' : null
|
|
||||||
}
|
|
||||||
|
|
||||||
quotesColl.findOneAndUpdate({
|
|
||||||
messageID: found.messageID
|
|
||||||
}, {
|
|
||||||
$inc: { count: 1 }
|
|
||||||
}, {
|
|
||||||
upsert: true
|
|
||||||
})
|
|
||||||
|
|
||||||
if (msgData.reference?.messageId) {
|
|
||||||
let refGuild = await client.guilds.fetch(msgData.reference.guildId)
|
|
||||||
let refChannel = await refGuild.channels.fetch(msgData.reference.channelId)
|
|
||||||
let refMessage = await refChannel.messages.fetch(msgData.reference.messageId)
|
|
||||||
refData = {
|
|
||||||
content: refMessage.content,
|
|
||||||
author: await refMessage.author,
|
|
||||||
embed: await refMessage.embeds.length > 0 ? 'embed' : null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var description = ''
|
|
||||||
if (refData) {
|
|
||||||
description += `> ${refData.author}`
|
|
||||||
if (refData.embed) {
|
|
||||||
description += '*an embed / a command* '
|
|
||||||
} else {
|
|
||||||
description += refData.content
|
|
||||||
}
|
|
||||||
description += `\r\n↳`
|
|
||||||
}
|
|
||||||
let messageLink = `https://discord.com/channels/${found.guildID}/${found.channelID}/${found.messageID}`
|
|
||||||
description += `${msgData.author} ${msgData.content}\r\n\r\n${messageLink}`
|
|
||||||
let timestamp = new Date(message.createdTimestamp)
|
|
||||||
let footer = timestamp.toDateString().toString()
|
|
||||||
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setThumbnail(msgData.author.displayAvatarURL())
|
|
||||||
.setURL(messageLink)
|
|
||||||
.setTitle(`- Quote Found! -`)
|
|
||||||
.setDescription(description)
|
|
||||||
.setFooter({ text: (footer + ' #' + found.messageID) })
|
|
||||||
await interaction.reply({ embeds: [embed] })
|
|
||||||
}
|
|
||||||
async function quotesList(interaction) {
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setTitle('- Quotes List! -')
|
|
||||||
.setDescription('- Choose someone below to filter by User')
|
|
||||||
.setThumbnail(interaction.guild.iconURL())
|
|
||||||
const row = new ActionRowBuilder()
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setEmoji(`◀`)
|
|
||||||
.setCustomId('quotes_list_left')
|
|
||||||
.setStyle(ButtonStyle.Primary)
|
|
||||||
)
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setEmoji(`❌`)
|
|
||||||
.setCustomId('abort')
|
|
||||||
.setStyle(ButtonStyle.Primary)
|
|
||||||
)
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setEmoji(`▶`)
|
|
||||||
.setCustomId('quotes_list_right')
|
|
||||||
.setStyle(ButtonStyle.Primary)
|
|
||||||
)
|
|
||||||
|
|
||||||
const select = new ActionRowBuilder()
|
|
||||||
.addComponents(
|
|
||||||
new UserSelectMenuBuilder()
|
|
||||||
.setCustomId('quotes_list_mentionable')
|
|
||||||
.setPlaceholder('Filter by User')
|
|
||||||
)
|
|
||||||
|
|
||||||
await interaction.reply({
|
|
||||||
embeds: [embed],
|
|
||||||
components: [select, row],
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
async function quotesLeaderboard(interaction, page = 1, limit = 5) {
|
|
||||||
const db = mClient.db(process.env.M_DB);
|
|
||||||
const quotesColl = db.collection('items_quotes');
|
|
||||||
|
|
||||||
// Total quotes in the guild
|
|
||||||
const totalQuotes = await quotesColl.countDocuments({ guildID: interaction.guild.id, count: { $gte: 0 } });
|
|
||||||
const totalPages = Math.ceil(totalQuotes / limit);
|
|
||||||
|
|
||||||
// Clamp page
|
|
||||||
if (page < 1) page = 1;
|
|
||||||
if (page > totalPages) page = totalPages;
|
|
||||||
|
|
||||||
const skip = (page - 1) * limit;
|
|
||||||
|
|
||||||
// Fetch quotes for this page
|
|
||||||
const quotesData = await quotesColl
|
|
||||||
.find({ guildID: interaction.guild.id, count: { $gte: 0 } })
|
|
||||||
.sort({ count: -1, messageID: -1 })
|
|
||||||
.skip(skip)
|
|
||||||
.limit(limit)
|
|
||||||
.toArray();
|
|
||||||
|
|
||||||
// Fallback if no quotes exist
|
|
||||||
if (!quotesData.length) {
|
|
||||||
return interaction.editReply({ content: 'No quotes found for this server yet!', components: [] });
|
|
||||||
}
|
|
||||||
|
|
||||||
const guild = await client.guilds.fetch(interaction.guild.id);
|
|
||||||
|
|
||||||
// Fetch all messages concurrently
|
|
||||||
const fields = await Promise.all(
|
|
||||||
quotesData.map(async (data, index) => {
|
|
||||||
try {
|
|
||||||
const channel = await guild.channels.fetch(data.channelID);
|
|
||||||
const message = await channel.messages.fetch(data.messageID);
|
|
||||||
const timestamp = new Date(message.createdTimestamp).toLocaleString('en-US', {
|
|
||||||
dateStyle: 'medium',
|
|
||||||
timeStyle: 'short'
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
name: `${skip + index + 1}.`,
|
|
||||||
value: `[#${data.messageID}](https://discord.com/channels/${data.guildID}/${data.channelID}/${data.messageID})\n**by** <@${data.userID}> • ⭐ ${data.count}\n_Posted on **${timestamp}**_\n${message.content}`
|
|
||||||
};
|
|
||||||
} catch {
|
|
||||||
return {
|
|
||||||
name: `${skip + index + 1}.`,
|
|
||||||
value: 'Message unavailable.'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
// Build embed
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setTitle('- Quotes Leaderboard -')
|
|
||||||
.setThumbnail(guild.iconURL({ dynamic: true }))
|
|
||||||
.setFields(fields)
|
|
||||||
.setColor('#5865F2')
|
|
||||||
.setFooter({ text: `Use ◄ ► to navigate • Page ${page} of ${totalPages}` });
|
|
||||||
|
|
||||||
// Build buttons
|
|
||||||
const row = new ActionRowBuilder()
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setLabel('◄')
|
|
||||||
.setStyle(ButtonStyle.Primary)
|
|
||||||
.setCustomId('quotes_leaderboard_left')
|
|
||||||
.setDisabled(page === 1),
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setLabel('X')
|
|
||||||
.setStyle(ButtonStyle.Danger)
|
|
||||||
.setCustomId('abort'),
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setLabel('►')
|
|
||||||
.setStyle(ButtonStyle.Primary)
|
|
||||||
.setCustomId('quotes_leaderboard_right')
|
|
||||||
.setDisabled(page === totalPages)
|
|
||||||
);
|
|
||||||
|
|
||||||
await interaction.editReply({ embeds: [embed], components: [row] });
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
data: new SlashCommandBuilder()
|
|
||||||
.setName('quotes')
|
|
||||||
.setDescription('quoten pfoten')
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s
|
|
||||||
.setName('add')
|
|
||||||
.setDescription('add a new quote either by replying to a message or inserting the message link')
|
|
||||||
.addStringOption(o => o.setName('link').setDescription('insert message link').setRequired(true)))
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s
|
|
||||||
.setName('remove')
|
|
||||||
.setDescription('remove a quote')
|
|
||||||
.addStringOption(o => o.setName('id').setDescription('insert message ID').setRequired(true)))
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s
|
|
||||||
.setName('search')
|
|
||||||
.setDescription('search by ID')
|
|
||||||
.addStringOption(o => o.setName('id').setDescription('insert message ID').setRequired(true)))
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s
|
|
||||||
.setName('random')
|
|
||||||
.setDescription('get a random quote')
|
|
||||||
.addUserOption(o => o.setName('by').setDescription('by user')))
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s
|
|
||||||
.setName('leaderboard')
|
|
||||||
.setDescription('see the most used quotes'))
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s
|
|
||||||
.setName('list')
|
|
||||||
.setDescription('[ADMIN] list all quotes')),
|
|
||||||
async execute(interaction) {
|
|
||||||
switch (interaction.options._subcommand) {
|
|
||||||
case 'add':
|
|
||||||
await interaction.deferReply()
|
|
||||||
await quotesAdd(interaction)
|
|
||||||
break;
|
|
||||||
case 'remove':
|
|
||||||
awaitquotesRemove(interaction)
|
|
||||||
break;
|
|
||||||
case 'search':
|
|
||||||
awaitquotesSearch(interaction)
|
|
||||||
break;
|
|
||||||
case 'random':
|
|
||||||
awaitquotesRandom(interaction)
|
|
||||||
break;
|
|
||||||
case 'leaderboard':
|
|
||||||
await interaction.deferReply()
|
|
||||||
awaitquotesLeaderboard(interaction)
|
|
||||||
break;
|
|
||||||
case 'list':
|
|
||||||
await quotesList(interaction)
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
module.exports.quotesLeaderboard = quotesLeaderboard
|
|
||||||
@@ -1,576 +0,0 @@
|
|||||||
const { ModalBuilder, UserSelectMenuBuilder, TextInputBuilder, EmbedBuilder, TimestampStyles, time, StringSelectMenuBuilder, messageLink } = require("@discordjs/builders");
|
|
||||||
const { ActionRowBuilder, ButtonBuilder, ButtonStyle, ComponentType } = require('discord.js')
|
|
||||||
const { SlashCommandBuilder, LabelBuilder, TextInputStyle, MessageFlags } = require("discord.js");
|
|
||||||
const { mClient } = require("../../..");
|
|
||||||
const db = mClient.db('neo-db')
|
|
||||||
require('dotenv').config()
|
|
||||||
|
|
||||||
function getRemaining(timer) {
|
|
||||||
if (timer.state !== 'running') {
|
|
||||||
return timer.timeRemaining;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Math.max(
|
|
||||||
0,
|
|
||||||
timer.timeRemaining - (Date.now() - timer.startedAt)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function ordinal(n) {
|
|
||||||
const s = ["th", "st", "nd", "rd"];
|
|
||||||
const v = n % 100;
|
|
||||||
|
|
||||||
return n + (s[(v - 20) % 10] || s[v] || s[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function wgeStatus(interaction) {
|
|
||||||
|
|
||||||
const wgeColl = db.collection('timer_wge')
|
|
||||||
const historyColl = db.collection('history_wge');
|
|
||||||
|
|
||||||
const results = await wgeColl.findOne({
|
|
||||||
$and: [
|
|
||||||
{ debug: false },
|
|
||||||
{ state: 'running' }
|
|
||||||
]
|
|
||||||
})
|
|
||||||
if (!results) {
|
|
||||||
return interaction.editReply({
|
|
||||||
content: 'No WGE Session currently running!',
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const historyCount = await historyColl.countDocuments();
|
|
||||||
const iteration = historyCount + 1;
|
|
||||||
|
|
||||||
const createdAt = new Date(results.createdAt)
|
|
||||||
const expiresAt = new Date(createdAt.getTime() + Number(results.timeRemaining))
|
|
||||||
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setTitle(`✨ [${ordinal(iteration)}] World's Greatest Expert ✨`)
|
|
||||||
.setDescription(
|
|
||||||
`<@${results.assignedUser}> is currently the **World's Greatest Expert** in **${results.topic}**.\n\n` +
|
|
||||||
`They must submit their entry <t:${Math.floor(expiresAt.getTime() / 1000)}:R>.\n\n` +
|
|
||||||
`Thank you, <@${results.assigningUser}>, for the nomination!`
|
|
||||||
)
|
|
||||||
|
|
||||||
return interaction.editReply({
|
|
||||||
embeds: [embed]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async function wgeStart(interaction) {
|
|
||||||
const defaultUsers = []
|
|
||||||
defaultUsers.push(process.env.D_ID)
|
|
||||||
|
|
||||||
|
|
||||||
const participantColl = db.collection('items_wge')
|
|
||||||
const participants = await participantColl.find({
|
|
||||||
status: true
|
|
||||||
}).toArray()
|
|
||||||
|
|
||||||
|
|
||||||
const wgeBaseModal = new ModalBuilder()
|
|
||||||
.setCustomId('wgeBaseModal')
|
|
||||||
.setTitle("World's Greatest Expert")
|
|
||||||
|
|
||||||
const options = [
|
|
||||||
{
|
|
||||||
label: 'RANDOM',
|
|
||||||
value: process.env.D_ID
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const participantOptions = await Promise.all(
|
|
||||||
participants.map(async (participant) => {
|
|
||||||
try {
|
|
||||||
const member = await interaction.guild.members.fetch(participant.userID);
|
|
||||||
return {
|
|
||||||
label: `${member.displayName} (${member.user.username})`,
|
|
||||||
value: participant.userID
|
|
||||||
};
|
|
||||||
} catch {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
options.push(
|
|
||||||
...participantOptions.filter(option => option !== null)
|
|
||||||
);
|
|
||||||
|
|
||||||
// Using StringSelectMenuBuilder because UserSelectMenuBuilder cannot be filtered for now
|
|
||||||
const wgeUserCustInput = new StringSelectMenuBuilder()
|
|
||||||
.setCustomId('wgeCustUserInput')
|
|
||||||
.setMaxValues(1)
|
|
||||||
.setMinValues(1)
|
|
||||||
.setRequired(true)
|
|
||||||
.addOptions(options)
|
|
||||||
|
|
||||||
const wgeTopicInput = new TextInputBuilder()
|
|
||||||
.setCustomId('wgeTopicInput')
|
|
||||||
.setStyle(TextInputStyle.Short)
|
|
||||||
.setRequired(true)
|
|
||||||
|
|
||||||
const wgeTopicLabel = new LabelBuilder()
|
|
||||||
.setLabel("And WHAT are they an expert in?")
|
|
||||||
.setDescription('Tell me!')
|
|
||||||
.setTextInputComponent(wgeTopicInput)
|
|
||||||
|
|
||||||
const wgeCustUserLabel = new LabelBuilder()
|
|
||||||
.setLabel('WHO is your greatest expert?')
|
|
||||||
.setDescription('Select them')
|
|
||||||
.setStringSelectMenuComponent(wgeUserCustInput)
|
|
||||||
|
|
||||||
wgeBaseModal
|
|
||||||
.addLabelComponents(wgeCustUserLabel, wgeTopicLabel)
|
|
||||||
|
|
||||||
await interaction.showModal(wgeBaseModal)
|
|
||||||
}
|
|
||||||
|
|
||||||
async function wgeStop(interaction) {
|
|
||||||
;
|
|
||||||
const wgeColl = db.collection('timer_wge');
|
|
||||||
|
|
||||||
const timer = await wgeColl.findOne({
|
|
||||||
debug: false
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!timer) {
|
|
||||||
return interaction.reply({
|
|
||||||
content: 'Timer not found.',
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// freeze remaining time
|
|
||||||
const remaining = getRemaining(timer);
|
|
||||||
|
|
||||||
await wgeColl.updateOne(
|
|
||||||
{ _id: timer._id },
|
|
||||||
{
|
|
||||||
$set: {
|
|
||||||
timeRemaining: remaining,
|
|
||||||
startedAt: null,
|
|
||||||
state: 'stopped'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
await interaction.reply({
|
|
||||||
content: `🛑 Timer stopped for **${timer.topic}**`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function wgeResume(interaction) {
|
|
||||||
;
|
|
||||||
const wgeColl = db.collection('timer_wge');
|
|
||||||
|
|
||||||
const timer = await wgeColl.findOne({
|
|
||||||
debug: false
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!timer) {
|
|
||||||
return interaction.reply({
|
|
||||||
content: 'Timer not found.',
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// freeze remaining time
|
|
||||||
const remaining = getRemaining(timer);
|
|
||||||
|
|
||||||
await wgeColl.updateOne(
|
|
||||||
{ _id: timer._id },
|
|
||||||
{
|
|
||||||
$set: {
|
|
||||||
timeRemaining: remaining,
|
|
||||||
startedAt: Date.now(),
|
|
||||||
state: 'running'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
await interaction.reply({
|
|
||||||
content: `🟢 Timer resumed for **${timer.topic}**`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function wgeForfeit(interaction) {
|
|
||||||
;
|
|
||||||
const wgeColl = db.collection('timer_wge');
|
|
||||||
const participateColl = db.collection('items_wge');
|
|
||||||
|
|
||||||
// Get active WGE
|
|
||||||
const wge = await wgeColl.findOne({
|
|
||||||
debug: false,
|
|
||||||
state: 'running'
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!wge) {
|
|
||||||
return interaction.reply({
|
|
||||||
content: 'No active WGE is currently running.',
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sanity check: only assigned user can forfeit
|
|
||||||
if (wge.assignedUser !== interaction.user.id) {
|
|
||||||
return interaction.reply({
|
|
||||||
content: `Only <@${wge.assignedUser}> can forfeit the current WGE.`,
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pick a new participant, excluding current assignee
|
|
||||||
const [randomParticipant] = await participateColl.aggregate([
|
|
||||||
{
|
|
||||||
$match: {
|
|
||||||
status: true,
|
|
||||||
userID: { $ne: interaction.user.id }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ $sample: { size: 1 } }
|
|
||||||
]).toArray();
|
|
||||||
|
|
||||||
if (!randomParticipant) {
|
|
||||||
return interaction.reply({
|
|
||||||
content: 'No one else is participating!',
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const member = await interaction.guild.members.fetch(
|
|
||||||
randomParticipant.userID
|
|
||||||
);
|
|
||||||
|
|
||||||
const nextUser = member.user;
|
|
||||||
|
|
||||||
const WGE_DURATION = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
||||||
|
|
||||||
await wgeColl.deleteOne({ _id: wge._id });
|
|
||||||
|
|
||||||
await wgeColl.insertOne({
|
|
||||||
assignedUser: nextUser.id,
|
|
||||||
assigningUser: wge.assigningUser,
|
|
||||||
|
|
||||||
startedAt: Date.now(),
|
|
||||||
timeRemaining: WGE_DURATION,
|
|
||||||
|
|
||||||
state: 'running',
|
|
||||||
|
|
||||||
notifications: {
|
|
||||||
half: false,
|
|
||||||
day24: false,
|
|
||||||
complete: false
|
|
||||||
},
|
|
||||||
|
|
||||||
topic: wge.topic,
|
|
||||||
debug: false,
|
|
||||||
|
|
||||||
createdAt: new Date()
|
|
||||||
});
|
|
||||||
|
|
||||||
return interaction.reply({
|
|
||||||
content: `${interaction.user} has forfeited! <@${nextUser.id}> is the next expert! Their topic is **${wge.topic}**`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function wgeParticipate(interaction) {
|
|
||||||
const status = interaction.options.getBoolean('status')
|
|
||||||
const user = interaction.user
|
|
||||||
|
|
||||||
const coll = db.collection('items_wge')
|
|
||||||
|
|
||||||
// Choice was false, ergo not participating
|
|
||||||
await coll.findOneAndUpdate({
|
|
||||||
userID: user.id
|
|
||||||
}, {
|
|
||||||
$set: {
|
|
||||||
userID: user.id,
|
|
||||||
status: status
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
upsert: true
|
|
||||||
})
|
|
||||||
|
|
||||||
interaction.reply({
|
|
||||||
content: `You are ${status ? '' : 'no longer '}participating!`,
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async function listParticipants(interaction) {
|
|
||||||
;
|
|
||||||
const participantColl = db.collection('items_wge');
|
|
||||||
const participants = await participantColl.find({}).toArray();
|
|
||||||
|
|
||||||
const participating = participants
|
|
||||||
.filter(p => p.status)
|
|
||||||
.map(p => `<@${p.userID}>`);
|
|
||||||
|
|
||||||
const notParticipating = participants
|
|
||||||
.filter(p => !p.status)
|
|
||||||
.map(p => `<@${p.userID}>`);
|
|
||||||
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setTitle('WGE Participation')
|
|
||||||
.setColor(0x5865F2)
|
|
||||||
.addFields(
|
|
||||||
{
|
|
||||||
name: `Participating (${participating.length})`,
|
|
||||||
value: participating.join('\n') || 'No participants found.',
|
|
||||||
inline: true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: `Not Participating (${notParticipating.length})`,
|
|
||||||
value: notParticipating.join('\n') || 'No entries found.',
|
|
||||||
inline: true
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.setFooter({
|
|
||||||
text: `Total entries: ${participants.length}`
|
|
||||||
})
|
|
||||||
|
|
||||||
await interaction.reply({
|
|
||||||
embeds: [embed],
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatDuration(ms) {
|
|
||||||
if (ms == null) return "unknown"
|
|
||||||
|
|
||||||
const totalSeconds = Math.floor(ms / 1000)
|
|
||||||
const days = Math.floor(totalSeconds / 86400)
|
|
||||||
const hours = Math.floor((totalSeconds % 86400) / 3600)
|
|
||||||
const minutes = Math.floor((totalSeconds % 3600) / 60)
|
|
||||||
const seconds = totalSeconds % 60
|
|
||||||
|
|
||||||
const parts = []
|
|
||||||
|
|
||||||
if (days) parts.push(`${days}d`)
|
|
||||||
if (hours) parts.push(`${hours}h`)
|
|
||||||
if (minutes) parts.push(`${minutes}m`)
|
|
||||||
if (seconds && !days) parts.push(`${seconds}s`) // only show seconds for short durations
|
|
||||||
|
|
||||||
return parts.length ? parts.join(" ") : "0s"
|
|
||||||
}
|
|
||||||
|
|
||||||
async function listHistory(interaction) {
|
|
||||||
const historyColl = db.collection('history_wge')
|
|
||||||
|
|
||||||
const wgeHistory = await historyColl
|
|
||||||
.find({ debug: false })
|
|
||||||
.sort({ createdAt: -1 })
|
|
||||||
.toArray()
|
|
||||||
|
|
||||||
if (!wgeHistory.length) {
|
|
||||||
return interaction.reply({
|
|
||||||
content: "No WGE history found.",
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const buildEmbed = (entry, index) => {
|
|
||||||
const createdTs = entry.createdAt
|
|
||||||
? Math.floor(new Date(entry.createdAt).getTime() / 1000)
|
|
||||||
: null
|
|
||||||
|
|
||||||
return new EmbedBuilder()
|
|
||||||
.setTitle(`WGE History (${index + 1}/${wgeHistory.length})`)
|
|
||||||
.setDescription(
|
|
||||||
`<@${entry.assignedUser}> was the **World's Greatest Expert** of...\n\n` +
|
|
||||||
`**${entry.topic}**\n\n` +
|
|
||||||
|
|
||||||
`Assigned by: <@${entry.assigningUser}>\n` +
|
|
||||||
(createdTs ? `Created: <t:${createdTs}:R>` : "")
|
|
||||||
)
|
|
||||||
.setColor(0x2b2d31)
|
|
||||||
}
|
|
||||||
|
|
||||||
let page = 0
|
|
||||||
|
|
||||||
const row = new ActionRowBuilder().addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setCustomId('prev')
|
|
||||||
.setLabel('◀')
|
|
||||||
.setStyle(ButtonStyle.Secondary)
|
|
||||||
.setDisabled(true),
|
|
||||||
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setCustomId('next')
|
|
||||||
.setLabel('▶')
|
|
||||||
.setStyle(ButtonStyle.Secondary)
|
|
||||||
.setDisabled(wgeHistory.length <= 1)
|
|
||||||
)
|
|
||||||
|
|
||||||
const msg = await interaction.reply({
|
|
||||||
embeds: [buildEmbed(wgeHistory[page], page)],
|
|
||||||
components: [row],
|
|
||||||
fetchReply: true
|
|
||||||
})
|
|
||||||
|
|
||||||
const collector = msg.createMessageComponentCollector({
|
|
||||||
componentType: ComponentType.Button,
|
|
||||||
time: 120000
|
|
||||||
})
|
|
||||||
|
|
||||||
collector.on('collect', async i => {
|
|
||||||
if (i.user.id !== interaction.user.id) {
|
|
||||||
return i.reply({
|
|
||||||
content: "You can't control this pagination.",
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i.customId === 'prev') {
|
|
||||||
page--
|
|
||||||
} else if (i.customId === 'next') {
|
|
||||||
page++
|
|
||||||
}
|
|
||||||
|
|
||||||
page = Math.max(0, Math.min(page, wgeHistory.length - 1))
|
|
||||||
|
|
||||||
row.components[0].setDisabled(page === 0)
|
|
||||||
row.components[1].setDisabled(page === wgeHistory.length - 1)
|
|
||||||
|
|
||||||
await i.update({
|
|
||||||
embeds: [buildEmbed(wgeHistory[page], page)],
|
|
||||||
components: [row]
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
collector.on('end', async () => {
|
|
||||||
const disabledRow = new ActionRowBuilder().addComponents(
|
|
||||||
row.components.map(btn => ButtonBuilder.from(btn).setDisabled(true))
|
|
||||||
)
|
|
||||||
|
|
||||||
await msg.edit({ components: [disabledRow] }).catch(() => { })
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async function wgeList(interaction) {
|
|
||||||
const thing = interaction.options.getString('thing');
|
|
||||||
|
|
||||||
switch (thing) {
|
|
||||||
case 'participants': {
|
|
||||||
listParticipants(interaction)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'history':
|
|
||||||
listHistory(interaction)
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
data: new SlashCommandBuilder()
|
|
||||||
.setName('wge')
|
|
||||||
.setDescription('welcome to worlds greatest experts')
|
|
||||||
// Show Status of Current Running WGE Session
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s
|
|
||||||
.setName('status')
|
|
||||||
.setDescription('display current wge session')
|
|
||||||
)
|
|
||||||
|
|
||||||
// Assign Someone to be the next Expert
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s
|
|
||||||
.setName('start')
|
|
||||||
.setDescription('start a new wge session')
|
|
||||||
)
|
|
||||||
|
|
||||||
// Stop the current Session Timer
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s
|
|
||||||
.setName('stop')
|
|
||||||
.setDescription('stop the current wge session')
|
|
||||||
)
|
|
||||||
|
|
||||||
// Resume the current Session Timer
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s
|
|
||||||
.setName('resume')
|
|
||||||
.setDescription('resume the current wge session timer')
|
|
||||||
)
|
|
||||||
|
|
||||||
// Forfeit your current expert topic and assign someone else
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s
|
|
||||||
.setName('forfeit')
|
|
||||||
.setDescription('forfeit your current topic')
|
|
||||||
)
|
|
||||||
|
|
||||||
// List the previous WGE Sessions
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s
|
|
||||||
.setName('history')
|
|
||||||
.setDescription('display the previous wge sessions')
|
|
||||||
)
|
|
||||||
|
|
||||||
// List the previous WGE Sessions
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s
|
|
||||||
.setName('participate')
|
|
||||||
.setDescription('do you want to play a game?')
|
|
||||||
.addBooleanOption(o =>
|
|
||||||
o.setName('status')
|
|
||||||
.setDescription('choose')
|
|
||||||
.setRequired(true)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
// List the previous WGE Sessions
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s
|
|
||||||
.setName('list')
|
|
||||||
.setDescription('list things')
|
|
||||||
.addStringOption(o =>
|
|
||||||
o.setName('thing')
|
|
||||||
.setDescription('what would you like to be listed')
|
|
||||||
.addChoices(
|
|
||||||
{ name: 'participants', value: 'participants' },
|
|
||||||
{ name: 'history', value: 'history' }
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
,
|
|
||||||
async execute(interaction) {
|
|
||||||
switch (interaction.options._subcommand) {
|
|
||||||
case 'status':
|
|
||||||
await interaction.deferReply()
|
|
||||||
wgeStatus(interaction)
|
|
||||||
break;
|
|
||||||
case 'start':
|
|
||||||
wgeStart(interaction)
|
|
||||||
break;
|
|
||||||
case 'stop':
|
|
||||||
wgeStop(interaction)
|
|
||||||
break;
|
|
||||||
case 'pause':
|
|
||||||
wgePause(interaction)
|
|
||||||
break;
|
|
||||||
case 'resume':
|
|
||||||
wgeResume(interaction)
|
|
||||||
break;
|
|
||||||
case 'forfeit':
|
|
||||||
wgeForfeit(interaction)
|
|
||||||
break;
|
|
||||||
case 'history':
|
|
||||||
wgeHistory(interaction)
|
|
||||||
break;
|
|
||||||
case 'participate':
|
|
||||||
wgeParticipate(interaction)
|
|
||||||
break;
|
|
||||||
case 'list':
|
|
||||||
wgeList(interaction)
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
const { SlashCommandBuilder } = require("discord.js");
|
|
||||||
|
|
||||||
function askMyBalls() {
|
|
||||||
var answers = [
|
|
||||||
'Absolut, so wie die Authorität unserer Göttin!',
|
|
||||||
'Unterschätze es nicht, genauso wie Roberts sexual frustration',
|
|
||||||
'Ich zedaz so',
|
|
||||||
'Ohne Zweifel',
|
|
||||||
'Definitiv, Alter',
|
|
||||||
'Microsoft Outlook gut',
|
|
||||||
'Das Sternzeichen von Yeesh leuchtet heute stark dafür',
|
|
||||||
'Mit "Support-Desk am Freitagabend" - Wahrscheinlichkeit',
|
|
||||||
'Ist die Nase von Julius wunderschön und lang?',
|
|
||||||
'So wahr wie Laviis Zeichnkünste',
|
|
||||||
'nein...ja... vielleicht?',
|
|
||||||
'Frag mich nachher nochmal',
|
|
||||||
'Die Kalkulationen sind leicht off, ich aber nicht ;)',
|
|
||||||
'Ich sag es dir ein ander Mal',
|
|
||||||
'Ohne schwere Zeiten, würden wir die guten Zeiten nie schätzen',
|
|
||||||
'Genauso schlecht wie eine Ketzerei gegen den Olymp',
|
|
||||||
'Hat der Fuchs uns jemals verraten?...**hust**',
|
|
||||||
'Mein Outlook ist abgeschmiert, mist',
|
|
||||||
'Ich bezweifle es. A propos, zweifel nicht an den Götter und ihren Priester!',
|
|
||||||
'Meine Quellen sagen.... WARNUNG! Artikel 17: Die betroffene Person hat das Recht, von dem Verantwortlichen zu verlangen, dass sie betreffende personenbezogene Daten unverzüglich gelöscht werden, und der Verantwortliche ist verpflichtet, personenbezogene Daten unverzüglich zu löschen, sofern einer der folgenden Gründe zutrifft **ERROR ERROR ERROR**?'
|
|
||||||
]
|
|
||||||
const r = Math.floor(Math.random() * answers.length)
|
|
||||||
|
|
||||||
return answers[r]
|
|
||||||
}
|
|
||||||
|
|
||||||
function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
data: new SlashCommandBuilder()
|
|
||||||
.setName('8ball')
|
|
||||||
.setDescription('dont ask me anything')
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s.setName('ask')
|
|
||||||
.setDescription('what do you want to know?')
|
|
||||||
.addStringOption(
|
|
||||||
o => o.setName('question').setDescription('ask away!').setRequired(true))
|
|
||||||
),
|
|
||||||
async execute(interaction) {
|
|
||||||
await interaction.deferReply()
|
|
||||||
await delay(2000)
|
|
||||||
await interaction.editReply(askMyBalls())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
const { SlashCommandBuilder, EmbedBuilder, AttachmentBuilder } = require("discord.js");
|
|
||||||
|
|
||||||
async function doggoPet(interaction) {
|
|
||||||
|
|
||||||
const responses = [
|
|
||||||
'*loving growl*',
|
|
||||||
'Danke, das habe ich gebraucht.',
|
|
||||||
'Ein bisschen tiefer.',
|
|
||||||
'Ja, genau dort!'
|
|
||||||
]
|
|
||||||
var r = Math.floor(Math.random() * responses.length)
|
|
||||||
|
|
||||||
const filePath = `assets/Command_Doggo/doggo.jpg`;
|
|
||||||
|
|
||||||
const attachment = new AttachmentBuilder(filePath);
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setDescription(responses[r])
|
|
||||||
.setColor(0x51267)
|
|
||||||
.setTimestamp()
|
|
||||||
.setImage(`attachment://doggo.jpg`);
|
|
||||||
|
|
||||||
await interaction.editReply({
|
|
||||||
embeds: [embed],
|
|
||||||
files: [attachment]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
async function doggoFeed(interaction) {
|
|
||||||
await interaction.editReply({
|
|
||||||
content: 'WIP placeholder'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
async function doggoWalk(interaction) {
|
|
||||||
await interaction.editReply({
|
|
||||||
content: 'WIP placeholder'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
async function doggoPlay(interaction) {
|
|
||||||
await interaction.editReply({
|
|
||||||
content: 'WIP placeholder'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
data: new SlashCommandBuilder()
|
|
||||||
.setName('doggo')
|
|
||||||
.setDescription('who is a good boi?')
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s.setName('pet')
|
|
||||||
.setDescription('beeg scratch')
|
|
||||||
)
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s.setName('feed')
|
|
||||||
.setDescription('tastge')
|
|
||||||
)
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s.setName('walk')
|
|
||||||
.setDescription('walkies')
|
|
||||||
)
|
|
||||||
.addSubcommand(s =>
|
|
||||||
s.setName('play')
|
|
||||||
.setDescription('fun time')
|
|
||||||
),
|
|
||||||
async execute(interaction) {
|
|
||||||
await interaction.deferReply()
|
|
||||||
switch (interaction.options._subcommand) {
|
|
||||||
case 'pet':
|
|
||||||
doggoPet(interaction)
|
|
||||||
break;
|
|
||||||
case 'feed':
|
|
||||||
doggoFeed(interaction)
|
|
||||||
break;
|
|
||||||
case 'walk':
|
|
||||||
doggoWalk(interaction)
|
|
||||||
break;
|
|
||||||
case 'play':
|
|
||||||
doggoPlay(interaction)
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
const { SlashCommandBuilder, AttachmentBuilder, EmbedBuilder } = require('discord.js');
|
|
||||||
const fs = require('fs/promises');
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
async function makeDay() {
|
|
||||||
const date = new Date();
|
|
||||||
|
|
||||||
const tage = [
|
|
||||||
'sonntag',
|
|
||||||
'montag',
|
|
||||||
'dienstag',
|
|
||||||
'mittwoch',
|
|
||||||
'donnerstag',
|
|
||||||
'freitag',
|
|
||||||
'samstag'
|
|
||||||
];
|
|
||||||
|
|
||||||
const text = {
|
|
||||||
montag: 'Es ist Montag meine Münmler!',
|
|
||||||
mittwoch: 'Es ist Mittwoch meine Kerle!',
|
|
||||||
donnerstag: 'Es ist nicht mehr Mittwoch meine Kerle!',
|
|
||||||
freitag: 'Es ist Freitag meine Kerl*innen!',
|
|
||||||
default: 'Es ist nicht Mittwoch, meine Kerle...'
|
|
||||||
};
|
|
||||||
|
|
||||||
const today = tage[date.getDay()];
|
|
||||||
|
|
||||||
let files;
|
|
||||||
try {
|
|
||||||
files = await fs.readdir('assets/Command_Mittwoch');
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
return { filename: 'nicht_mittwoch', content: text.default };
|
|
||||||
}
|
|
||||||
|
|
||||||
const available = files.map(f => path.parse(f).name);
|
|
||||||
|
|
||||||
if (available.includes(today)) {
|
|
||||||
return {
|
|
||||||
filename: today,
|
|
||||||
content: text[today] || text.default
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
filename: 'nicht_mittwoch',
|
|
||||||
content: text.default
|
|
||||||
};
|
|
||||||
}
|
|
||||||
module.exports = {
|
|
||||||
data: new SlashCommandBuilder()
|
|
||||||
.setName('mittwoch')
|
|
||||||
.setDescription('mittwoch vibes'),
|
|
||||||
|
|
||||||
async execute(interaction) {
|
|
||||||
const { filename, content } = await makeDay();
|
|
||||||
|
|
||||||
const filePath = `assets/Command_Mittwoch/${filename}.jpg`;
|
|
||||||
|
|
||||||
const attachment = new AttachmentBuilder(filePath);
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setTitle(content)
|
|
||||||
.setColor(0x51267)
|
|
||||||
.setTimestamp()
|
|
||||||
.setImage(`attachment://${filename}.jpg`);
|
|
||||||
|
|
||||||
await interaction.reply({
|
|
||||||
embeds: [embed],
|
|
||||||
files: [attachment]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
const { createCanvas, loadImage } = require('canvas');
|
|
||||||
const path = require('node:path');
|
|
||||||
const { mClient } = require('..');
|
|
||||||
require('dotenv').configDotenv();
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: "Birthday",
|
|
||||||
once: false,
|
|
||||||
async execute(member, client) {
|
|
||||||
console.log(`${member.user.username} hat Geburtstag!`)
|
|
||||||
let found = null
|
|
||||||
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const channelsColl = db.collection('config_channels')
|
|
||||||
found = await channelsColl.find(
|
|
||||||
{
|
|
||||||
$and: [
|
|
||||||
{ guildID: member.guild.id },
|
|
||||||
{ purpose: 'birthday' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
).toArray()
|
|
||||||
|
|
||||||
if (!found) {
|
|
||||||
return console.log('Channel not yet set for birthday!')
|
|
||||||
}
|
|
||||||
|
|
||||||
const guild = client.guilds.cache.get(found[0].guildID);
|
|
||||||
const channel = guild.channels.cache.get(found[0].channelID);
|
|
||||||
const roleColl = db.collection('config_roles')
|
|
||||||
|
|
||||||
// Bot Role MUST BE above birthday Role, Birthday Role MUST BE above user roles
|
|
||||||
found = await roleColl.findOne({guildID: member.guild.id})
|
|
||||||
const role = guild.roles.cache.get(found.roleID)
|
|
||||||
|
|
||||||
try {
|
|
||||||
await member.roles.add(role)
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
}
|
|
||||||
// Create Canvas
|
|
||||||
let canvasWidth = 600;
|
|
||||||
let canvasHeight = 250;
|
|
||||||
const canvas = new createCanvas(canvasWidth, canvasHeight);
|
|
||||||
const ctx = canvas.getContext('2d');
|
|
||||||
|
|
||||||
// Draw Initial Image
|
|
||||||
const background = await loadImage(
|
|
||||||
path.join(__dirname, '../assets/Event_Birthday/bdbanner.png')
|
|
||||||
);
|
|
||||||
let x = 0;
|
|
||||||
let y = 0;
|
|
||||||
ctx.drawImage(background, x, y);
|
|
||||||
|
|
||||||
// Create Profile Picture
|
|
||||||
const pfp = await loadImage(
|
|
||||||
member.user.displayAvatarURL({
|
|
||||||
extension: 'jpg',
|
|
||||||
size: 64,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
// Draw Profile Picture on Top of Background
|
|
||||||
x = canvas.width / 2 - pfp.width / 2;
|
|
||||||
y = 20;
|
|
||||||
ctx.drawImage(pfp, x, y);
|
|
||||||
|
|
||||||
// Set styles for text
|
|
||||||
ctx.font = '35px sans-serif';
|
|
||||||
ctx.fillStyle = '#FFC0CB'; // Pink text
|
|
||||||
ctx.strokeStyle = '#000000'; // Black outline
|
|
||||||
ctx.lineWidth = 3; // Thickness of the outline
|
|
||||||
|
|
||||||
let text = `Alles Gute zum Geburtstag! `;
|
|
||||||
let textWidth = ctx.measureText(text).width;
|
|
||||||
let textX = canvas.width / 2 - textWidth / 2;
|
|
||||||
let textHeight = 35; // Approximate height of the text
|
|
||||||
|
|
||||||
// Draw the text with black outline
|
|
||||||
ctx.strokeText(text, textX, 60 + pfp.height);
|
|
||||||
ctx.fillText(text, textX, 60 + pfp.height);
|
|
||||||
|
|
||||||
// requires apt-get install ttf-ancient-fonts
|
|
||||||
ctx.font = '30px "Noto Emoji", "Segoe UI Emoji", "Apple Color Emoji", sans-serif';
|
|
||||||
text = `🎉 ${member.user.globalName ? member.user.globalName : member.user.username} 🎉`;
|
|
||||||
textWidth = ctx.measureText(text).width;
|
|
||||||
textX = canvas.width / 2 - textWidth / 2;
|
|
||||||
textHeight = 30; // Approximate height of the text
|
|
||||||
|
|
||||||
// Draw the second line of text with black outline
|
|
||||||
ctx.strokeText(text, textX, 100 + pfp.height);
|
|
||||||
ctx.fillText(text, textX, 100 + pfp.height);
|
|
||||||
|
|
||||||
const banner = canvas.toBuffer();
|
|
||||||
|
|
||||||
channel.send({
|
|
||||||
content: `@here`,
|
|
||||||
files: [{
|
|
||||||
attachment: banner,
|
|
||||||
name: 'banner.png',
|
|
||||||
description: 'a birthday banner'
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
|
|
||||||
// mark as notified
|
|
||||||
|
|
||||||
const bdayColl = db.collection('items_birthdays')
|
|
||||||
await bdayColl.findOneAndUpdate({
|
|
||||||
userID: member.user.id
|
|
||||||
}, {
|
|
||||||
$set: {
|
|
||||||
notified: true
|
|
||||||
}
|
|
||||||
},{
|
|
||||||
upsert: true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
const { Events, ActivityType } = require('discord.js');
|
|
||||||
const { mClient } = require('..');
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: Events.ClientReady,
|
|
||||||
once: true,
|
|
||||||
async execute(client) {
|
|
||||||
console.log(`Ready! Logged in as ${client.user.tag}`);
|
|
||||||
|
|
||||||
// Set presence
|
|
||||||
client.user.setPresence({
|
|
||||||
activities: [{
|
|
||||||
name: 'Red Dead Depression',
|
|
||||||
type: ActivityType.Streaming,
|
|
||||||
url: 'https://twitch.tv/desq_blocki'
|
|
||||||
}],
|
|
||||||
status: 'online'
|
|
||||||
});
|
|
||||||
|
|
||||||
// Check if a date matches today
|
|
||||||
const isToday = (day, month) => {
|
|
||||||
const today = new Date();
|
|
||||||
return today.getDate() === day && today.getMonth() === month - 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Handle birthdays
|
|
||||||
const handleBirthdays = async () => {
|
|
||||||
const guild = await client.guilds.fetch(process.env.D_GuildID);
|
|
||||||
const db = mClient.db(process.env.M_DB);
|
|
||||||
|
|
||||||
const bdayColl = db.collection('items_birthdays');
|
|
||||||
const allBirthdays = await bdayColl.find().toArray();
|
|
||||||
const bdayMap = new Map(allBirthdays.map(b => [b.userID, b]));
|
|
||||||
|
|
||||||
// Fetch birthday role
|
|
||||||
const bdayRoleColl = db.collection('config_roles');
|
|
||||||
const bdayRoleEntry = await bdayRoleColl.findOne({ guildID: guild.id });
|
|
||||||
const birthdayRoleID = bdayRoleEntry?.roleID;
|
|
||||||
|
|
||||||
if (!birthdayRoleID) {
|
|
||||||
console.warn("No birthday role configured in DB");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch all guild members
|
|
||||||
const members = await guild.members.fetch();
|
|
||||||
|
|
||||||
for (const member of members.values()) {
|
|
||||||
const dbEntry = bdayMap.get(member.id);
|
|
||||||
|
|
||||||
if (!dbEntry) continue;
|
|
||||||
|
|
||||||
// Reset notification once the birthday has passed
|
|
||||||
if (!isToday(dbEntry.day, dbEntry.month) && dbEntry.notified) {
|
|
||||||
await bdayColl.updateOne(
|
|
||||||
{ userID: member.id },
|
|
||||||
{ $set: { notified: false } }
|
|
||||||
);
|
|
||||||
|
|
||||||
dbEntry.notified = false; // keep local copy in sync
|
|
||||||
console.log(`Removed notified flag for ${member.user.tag}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip if already handled today
|
|
||||||
if (dbEntry.notified && isToday(dbEntry.day, dbEntry.month)) {
|
|
||||||
console.log(`${member.user.username} was already notified today, skipping...`);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isToday(dbEntry.day, dbEntry.month)) {
|
|
||||||
await member.roles.add(birthdayRoleID).catch(err =>
|
|
||||||
console.error(`Failed to add birthday role to ${member.user.tag}:`, err)
|
|
||||||
);
|
|
||||||
|
|
||||||
console.log(`Added birthday role to ${member.user.tag}`);
|
|
||||||
client.emit('Birthday', member);
|
|
||||||
|
|
||||||
// mark as notified
|
|
||||||
await bdayColl.updateOne(
|
|
||||||
{ userID: member.id },
|
|
||||||
{ $set: { notified: true } }
|
|
||||||
);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (member.roles.cache.has(birthdayRoleID)) {
|
|
||||||
await member.roles.remove(birthdayRoleID).catch(err =>
|
|
||||||
console.error(`Failed to remove birthday role from ${member.user.tag}:`, err)
|
|
||||||
);
|
|
||||||
|
|
||||||
console.log(`Removed birthday role from ${member.user.tag}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
await handleBirthdays();
|
|
||||||
|
|
||||||
// First check after restart
|
|
||||||
client.emit('timerCheck');
|
|
||||||
|
|
||||||
// Check every minute
|
|
||||||
setInterval(() => {
|
|
||||||
client.emit('timerCheck');
|
|
||||||
}, 60_000);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
const { Events } = require('discord.js');
|
|
||||||
const { createCanvas, loadImage } = require('canvas');
|
|
||||||
const path = require('node:path');
|
|
||||||
const { mClient } = require('..');
|
|
||||||
require('dotenv').configDotenv();
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: Events.GuildMemberAdd,
|
|
||||||
once: false,
|
|
||||||
async execute(member, client) {
|
|
||||||
console.log(`${member.user.username} joined the Server`);
|
|
||||||
const db = mClient.db(process.env.M_DB)
|
|
||||||
const channelsColl = db.collection('config_channels')
|
|
||||||
const found = await channelsColl.find(
|
|
||||||
{
|
|
||||||
$and: [
|
|
||||||
{ guildID: member.guild.id },
|
|
||||||
{ purpose: 'welcome' }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
).toArray()
|
|
||||||
|
|
||||||
if (!found) {
|
|
||||||
return console.log('Channel not yet set for welcome!')
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const guild = client.guilds.cache.get(found[0].guildID);
|
|
||||||
const channel = guild.channels.cache.get(found[0].channelID);
|
|
||||||
|
|
||||||
// Create Canvas
|
|
||||||
let canvasWidth = 600;
|
|
||||||
let canvasHeight = 250;
|
|
||||||
const canvas = new createCanvas(canvasWidth, canvasHeight);
|
|
||||||
const ctx = canvas.getContext('2d');
|
|
||||||
|
|
||||||
// Draw Initial Image
|
|
||||||
const background = await loadImage(
|
|
||||||
path.join(__dirname, '../assets/Event_MemberJoin/background.png')
|
|
||||||
);
|
|
||||||
let x = 0;
|
|
||||||
let y = 0;
|
|
||||||
ctx.drawImage(background, x, y);
|
|
||||||
|
|
||||||
// Create Profile Picture
|
|
||||||
const pfp = await loadImage(
|
|
||||||
member.user.displayAvatarURL({
|
|
||||||
extension: 'jpg',
|
|
||||||
size: 64,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
// Draw Profile Picture on Top of Background
|
|
||||||
x = canvas.width / 2 - pfp.width / 2;
|
|
||||||
y = 20;
|
|
||||||
ctx.drawImage(pfp, x, y);
|
|
||||||
|
|
||||||
// Set styles for text
|
|
||||||
ctx.font = '35px sans-serif';
|
|
||||||
ctx.fillStyle = '#ffffff'; // White text
|
|
||||||
ctx.strokeStyle = '#000000'; // Black outline
|
|
||||||
ctx.lineWidth = 3; // Thickness of the outline
|
|
||||||
|
|
||||||
let text = `Willkommen, ${member.user.globalName?member.user.globalName:member.user.username}!`;
|
|
||||||
let textWidth = ctx.measureText(text).width;
|
|
||||||
let textX = canvas.width / 2 - textWidth / 2;
|
|
||||||
let textHeight = 35; // Approximate height of the text
|
|
||||||
|
|
||||||
// Draw the text with black outline
|
|
||||||
ctx.strokeText(text, textX, 60 + pfp.height);
|
|
||||||
ctx.fillText(text, textX, 60 + pfp.height);
|
|
||||||
|
|
||||||
ctx.font = '30px sans-serif';
|
|
||||||
text = `auf dem ✨Olymp✨`;
|
|
||||||
textWidth = ctx.measureText(text).width;
|
|
||||||
textX = canvas.width / 2 - textWidth / 2;
|
|
||||||
textHeight = 30; // Approximate height of the text
|
|
||||||
|
|
||||||
// Draw the second line of text with black outline
|
|
||||||
ctx.strokeText(text, textX, 100 + pfp.height);
|
|
||||||
ctx.fillText(text, textX, 100 + pfp.height);
|
|
||||||
const banner = canvas.toBuffer();
|
|
||||||
|
|
||||||
channel.send({
|
|
||||||
content: `Bitte guck einmal in die <#455023824791011338> ${member}`,
|
|
||||||
files: [{
|
|
||||||
attachment: banner,
|
|
||||||
name: 'banner.png',
|
|
||||||
description: 'a welcome banner'
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,316 +0,0 @@
|
|||||||
const { Events, MessageFlags, Message } = require('discord.js')
|
|
||||||
const { mClient } = require('../index')
|
|
||||||
require('dotenv').config()
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: Events.InteractionCreate,
|
|
||||||
once: false,
|
|
||||||
async execute(interaction) {
|
|
||||||
if (interaction.isChatInputCommand()) { commandHandler(interaction) }
|
|
||||||
if (interaction.isButton()) { buttonHandler(interaction) }
|
|
||||||
if (interaction.isMentionableSelectMenu()) { selectMenuHandler(interaction) }
|
|
||||||
if (interaction.isUserSelectMenu()) { selectMenuHandler(interaction) }
|
|
||||||
if (interaction.isModalSubmit()) { modalSubmitHandler(interaction) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function commandHandler(interaction) {
|
|
||||||
const command = interaction.client.commands.get(interaction.commandName);
|
|
||||||
|
|
||||||
if (!command) {
|
|
||||||
console.error(`No command matching ${interaction.commandName} was found.`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
await command.execute(interaction);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
if (interaction.replied || interaction.deferred) {
|
|
||||||
await interaction.followUp({ content: 'There was an error while executing this command!', flags: MessageFlags.Ephemeral });
|
|
||||||
} else {
|
|
||||||
await interaction.reply({ content: 'There was an error while executing this command!', flags: MessageFlags.Ephemeral });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function buttonHandler(interaction) {
|
|
||||||
const button = interaction.client.buttons.get(interaction.customId)
|
|
||||||
if (!button) { return }// console.error(`No button registered matching ${interaction.customId}.`) }
|
|
||||||
try {
|
|
||||||
await button.execute(interaction);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
if (interaction.replied || interaction.deferred) {
|
|
||||||
await interaction.followUp({ content: 'There was an error while executing this command!', flags: MessageFlags.Ephemeral });
|
|
||||||
} else {
|
|
||||||
await interaction.reply({ content: 'There was an error while executing this command!', flags: MessageFlags.Ephemeral });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async function selectMenuHandler(interaction) {
|
|
||||||
const selectMenu = interaction.client.selectMenus.get(interaction.customId)
|
|
||||||
if (!selectMenu) { return console.error(`No Select Menu registered matching ${interaction.customId}.`) }
|
|
||||||
try {
|
|
||||||
await selectMenu.execute(interaction);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
if (interaction.replied || interaction.deferred) {
|
|
||||||
await interaction.followUp({ content: 'There was an error while executing this command!', flags: MessageFlags.Ephemeral });
|
|
||||||
} else {
|
|
||||||
await interaction.reply({ content: 'There was an error while executing this command!', flags: MessageFlags.Ephemeral });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getParticipantWeight(participant, now = Date.now()) {
|
|
||||||
// Never selected before -> strongly favor them
|
|
||||||
if (!participant.lastExpertAt) {
|
|
||||||
return 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
const lastExpertAt = new Date(participant.lastExpertAt).getTime();
|
|
||||||
|
|
||||||
// Invalid date safety
|
|
||||||
if (Number.isNaN(lastExpertAt)) {
|
|
||||||
return 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
const daysSinceExpert = Math.max(
|
|
||||||
0,
|
|
||||||
(now - lastExpertAt) / (24 * 60 * 60 * 1000)
|
|
||||||
);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Square-root weighting prevents very old participants
|
|
||||||
* from completely dominating the random selection.
|
|
||||||
*
|
|
||||||
* Examples:
|
|
||||||
* 1 day -> ~1.41
|
|
||||||
* 7 days -> ~2.83
|
|
||||||
* 30 days -> ~5.57
|
|
||||||
*/
|
|
||||||
return Math.sqrt(daysSinceExpert + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function weightedRandom(participants) {
|
|
||||||
if (!participants.length) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const weightedParticipants = participants.map(participant => ({
|
|
||||||
participant,
|
|
||||||
weight: getParticipantWeight(participant)
|
|
||||||
}));
|
|
||||||
|
|
||||||
const totalWeight = weightedParticipants.reduce(
|
|
||||||
(total, item) => total + item.weight,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
|
|
||||||
let random = Math.random() * totalWeight;
|
|
||||||
|
|
||||||
for (const item of weightedParticipants) {
|
|
||||||
random -= item.weight;
|
|
||||||
|
|
||||||
if (random <= 0) {
|
|
||||||
return item.participant;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Floating-point safety fallback
|
|
||||||
return weightedParticipants[weightedParticipants.length - 1].participant;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function selectWgeParticipant(
|
|
||||||
participateColl,
|
|
||||||
{ excludeUserId = null } = {}
|
|
||||||
) {
|
|
||||||
const filter = {
|
|
||||||
status: true
|
|
||||||
};
|
|
||||||
|
|
||||||
if (excludeUserId) {
|
|
||||||
filter.userID = {
|
|
||||||
$ne: excludeUserId
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const participants = await participateColl
|
|
||||||
.find(filter)
|
|
||||||
.toArray();
|
|
||||||
|
|
||||||
return weightedRandom(participants);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function modalSubmitHandler(interaction) {
|
|
||||||
if (interaction.customId !== 'wgeBaseModal') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const db = mClient.db('neo-db');
|
|
||||||
|
|
||||||
const wgeColl = db.collection('timer_wge');
|
|
||||||
const participateColl = db.collection('items_wge');
|
|
||||||
const historyWgeColl = db.collection('history_wge');
|
|
||||||
|
|
||||||
const assigningUser = interaction.user;
|
|
||||||
|
|
||||||
const selectedUserId =
|
|
||||||
interaction.components[0].component.values[0];
|
|
||||||
|
|
||||||
const topic = interaction.fields.getTextInputValue(
|
|
||||||
'wgeTopicInput'
|
|
||||||
);
|
|
||||||
|
|
||||||
const defaultAssignedTime =
|
|
||||||
7 * 24 * 60 * 60 * 1000;
|
|
||||||
|
|
||||||
// Get current running WGE so the previous expert
|
|
||||||
// cannot immediately be selected again.
|
|
||||||
const prevWge = await wgeColl.findOne({
|
|
||||||
debug: false,
|
|
||||||
state: 'running'
|
|
||||||
});
|
|
||||||
|
|
||||||
let assignedUser;
|
|
||||||
let selectedParticipant;
|
|
||||||
|
|
||||||
// ---------------------------------
|
|
||||||
// RANDOM / WEIGHTED ASSIGNMENT
|
|
||||||
// ---------------------------------
|
|
||||||
if (selectedUserId === process.env.D_ID) {
|
|
||||||
selectedParticipant = await selectWgeParticipant(
|
|
||||||
participateColl,
|
|
||||||
{
|
|
||||||
excludeUserId: prevWge?.assignedUser
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!selectedParticipant) {
|
|
||||||
return interaction.reply({
|
|
||||||
content:
|
|
||||||
'There are no eligible participants available.',
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const member = await interaction.guild.members
|
|
||||||
.fetch(selectedParticipant.userID)
|
|
||||||
.catch(() => null);
|
|
||||||
|
|
||||||
if (!member) {
|
|
||||||
return interaction.reply({
|
|
||||||
content:
|
|
||||||
'The selected participant could not be found in the server.',
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
assignedUser = member.user;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------
|
|
||||||
// MANUAL ASSIGNMENT
|
|
||||||
// ---------------------------------
|
|
||||||
else {
|
|
||||||
selectedParticipant = await participateColl.findOne({
|
|
||||||
userID: selectedUserId,
|
|
||||||
status: true
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!selectedParticipant) {
|
|
||||||
return interaction.reply({
|
|
||||||
content:
|
|
||||||
`<@${selectedUserId}> is not participating!`,
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
prevWge &&
|
|
||||||
selectedUserId === prevWge.assignedUser
|
|
||||||
) {
|
|
||||||
return interaction.reply({
|
|
||||||
content:
|
|
||||||
`<@${selectedUserId}> was the previous expert and cannot be selected again this round.`,
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
assignedUser = {
|
|
||||||
id: selectedUserId
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------
|
|
||||||
// ARCHIVE PREVIOUS WGE
|
|
||||||
// ---------------------------------
|
|
||||||
if (prevWge) {
|
|
||||||
await historyWgeColl.insertOne({
|
|
||||||
assignedUser: prevWge.assignedUser,
|
|
||||||
assigningUser: prevWge.assigningUser,
|
|
||||||
|
|
||||||
timeRemaining: prevWge.timeRemaining,
|
|
||||||
|
|
||||||
topic: prevWge.topic,
|
|
||||||
debug: prevWge.debug,
|
|
||||||
|
|
||||||
createdAt: prevWge.createdAt
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log({
|
|
||||||
message: 'Saved previous WGE to history_wge',
|
|
||||||
data: prevWge
|
|
||||||
});
|
|
||||||
|
|
||||||
await wgeColl.deleteOne({
|
|
||||||
_id: prevWge._id
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const assignedAt = new Date();
|
|
||||||
|
|
||||||
// ---------------------------------
|
|
||||||
// UPDATE PARTICIPANT STATISTICS
|
|
||||||
// ---------------------------------
|
|
||||||
await participateColl.updateOne(
|
|
||||||
{
|
|
||||||
_id: selectedParticipant._id
|
|
||||||
},
|
|
||||||
{
|
|
||||||
$set: {
|
|
||||||
lastExpertAt: assignedAt
|
|
||||||
},
|
|
||||||
$inc: {
|
|
||||||
expertCount: 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// ---------------------------------
|
|
||||||
// CREATE NEW WGE
|
|
||||||
// ---------------------------------
|
|
||||||
await wgeColl.insertOne({
|
|
||||||
assignedUser: assignedUser.id,
|
|
||||||
assigningUser: assigningUser.id,
|
|
||||||
|
|
||||||
startedAt: Date.now(),
|
|
||||||
timeRemaining: defaultAssignedTime,
|
|
||||||
|
|
||||||
state: 'running',
|
|
||||||
|
|
||||||
notifications: {
|
|
||||||
half: false,
|
|
||||||
day24: false,
|
|
||||||
complete: false
|
|
||||||
},
|
|
||||||
|
|
||||||
topic,
|
|
||||||
debug: false,
|
|
||||||
|
|
||||||
createdAt: assignedAt
|
|
||||||
});
|
|
||||||
|
|
||||||
return interaction.reply({
|
|
||||||
content:
|
|
||||||
`<@${assignedUser.id}> is the next expert! Their topic is **${topic}**`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
const { Events, MessageFlags } = require("discord.js");
|
|
||||||
require("dotenv").config();
|
|
||||||
|
|
||||||
const { client, mClient } = require("../index");
|
|
||||||
|
|
||||||
const prefix = process.env.D_Prefix;
|
|
||||||
const db = mClient.db(process.env.M_DB);
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: Events.MessageCreate,
|
|
||||||
once: false,
|
|
||||||
|
|
||||||
async execute(message) {
|
|
||||||
if (message.author.bot) return;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Daily number handler
|
|
||||||
* Only does something if Ersti/Zweiti/Dritti is detected.
|
|
||||||
*/
|
|
||||||
if (message.channelId === "353902391021535244") {
|
|
||||||
const numbered = {
|
|
||||||
Erst: "Ersti",
|
|
||||||
Zweit: "Zweiti",
|
|
||||||
Dritt: "Dritti"
|
|
||||||
};
|
|
||||||
|
|
||||||
const found = Object.entries(numbered).find(([stem]) =>
|
|
||||||
new RegExp(`\\b\\w*${stem}\\w*\\b`, "i").test(message.content)
|
|
||||||
)?.[1];
|
|
||||||
|
|
||||||
if (found) {
|
|
||||||
const numberedColl = db.collection("items_ezd");
|
|
||||||
|
|
||||||
const today = new Date().toLocaleDateString("en-CA", {
|
|
||||||
timeZone: "Europe/Berlin"
|
|
||||||
});
|
|
||||||
|
|
||||||
await numberedColl.findOneAndUpdate(
|
|
||||||
{ date: today },
|
|
||||||
{
|
|
||||||
$setOnInsert: {
|
|
||||||
date: today,
|
|
||||||
positions: {
|
|
||||||
Ersti: null,
|
|
||||||
Zweiti: null,
|
|
||||||
Dritti: null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ upsert: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
const result = await numberedColl.findOneAndUpdate(
|
|
||||||
{
|
|
||||||
date: today,
|
|
||||||
[`positions.${found}`]: null,
|
|
||||||
"positions.Ersti.userId": { $ne: message.author.id },
|
|
||||||
"positions.Zweiti.userId": { $ne: message.author.id },
|
|
||||||
"positions.Dritti.userId": { $ne: message.author.id }
|
|
||||||
},
|
|
||||||
{
|
|
||||||
$set: {
|
|
||||||
[`positions.${found}`]: {
|
|
||||||
userId: message.author.id,
|
|
||||||
timestamp: new Date()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
returnDocument: "after"
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!result) {
|
|
||||||
await message.reply({
|
|
||||||
content:
|
|
||||||
"❌ Du kannst pro Tag nur eine Position beanspruchen, und sie muss noch frei sein.",
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
await message.reply({
|
|
||||||
content: `✅ Du bist ${found}! :point_right: :point_left: <@${message.author.id}>`,
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only stop here if this was actually a number claim.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Command handler
|
|
||||||
*/
|
|
||||||
if (!message.content.startsWith(prefix)) return;
|
|
||||||
|
|
||||||
const args = message.content
|
|
||||||
.slice(prefix.length)
|
|
||||||
.trim()
|
|
||||||
.split(/ +/);
|
|
||||||
|
|
||||||
const cmd = args.shift().toLowerCase();
|
|
||||||
|
|
||||||
let command = client.legacyCommands.get(cmd);
|
|
||||||
|
|
||||||
if (!command) {
|
|
||||||
command = client.aliases.get(cmd)
|
|
||||||
? client.legacyCommands.get(client.aliases.get(cmd))
|
|
||||||
: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!command) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await command.execute(message, args);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
// const { Events, ClientVoiceManager } = require("discord.js");
|
|
||||||
// const { getVoiceConnection } = require('@discordjs/voice')
|
|
||||||
// require('dotenv').config()
|
|
||||||
// const { client } = require('../index');
|
|
||||||
// const users_in_afk = new Set();
|
|
||||||
// const delay = ms => new Promise(res => setTimeout(res, ms));
|
|
||||||
// var connected = false;
|
|
||||||
// const url = `https://www.youtube.com/watch?v=Y4ySxP_IptE`
|
|
||||||
|
|
||||||
// module.exports = {
|
|
||||||
// name: Events.VoiceStateUpdate,
|
|
||||||
// once: false,
|
|
||||||
// async execute(oldState, newState) {
|
|
||||||
// const guild = client.guilds.cache.get(process.env.D_GuildID)
|
|
||||||
// const afk_channel = await guild.channels.fetch(guild.afkChannelId)
|
|
||||||
// const real_afk_channel = await guild.channels.fetch(process.env.D_RealTartarosID)
|
|
||||||
// const user = await guild.members.fetch(newState.id)
|
|
||||||
|
|
||||||
// if(user.id === process.env.D_ID) return;
|
|
||||||
|
|
||||||
// // if someone enters the official AFK channel, move them to one where we can play music
|
|
||||||
// if (newState.channelId === afk_channel.id) {
|
|
||||||
// await delay(1000)
|
|
||||||
|
|
||||||
// await user.voice.setChannel(real_afk_channel)
|
|
||||||
|
|
||||||
// users_in_afk.add(newState.id)
|
|
||||||
// console.log(`${users_in_afk.size} User(s) in Channel`)
|
|
||||||
|
|
||||||
// if (!connected) {
|
|
||||||
// connected = true;
|
|
||||||
// await client.distube.voices.join(real_afk_channel)
|
|
||||||
// await user.voice.setSuppressed(true) // mute user?
|
|
||||||
// await guild.members.me.voice.setSuppressed(false); //unmute self
|
|
||||||
// await client.distube.play(real_afk_channel, url, {
|
|
||||||
// member: newState.member,
|
|
||||||
// })
|
|
||||||
// //const queue = client.distube.getQueue(guild)
|
|
||||||
// //await queue.setRepeatMode(2)
|
|
||||||
// //await queue.setVolume(40)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // if someone leaves the real AFK channel, remove them from cache but wait for rejoiners, then leave if none are here
|
|
||||||
// if (oldState.channelId === real_afk_channel.id && oldState.channelId != newState.channelId) {
|
|
||||||
// users_in_afk.delete(oldState.id)
|
|
||||||
// const user = await guild.members.fetch(oldState.id)
|
|
||||||
// //await user.voice.setMute(false) //kann nicht unmuten wenn disconnected ist
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (users_in_afk.size === 0) {
|
|
||||||
// //leave if empty
|
|
||||||
// await client.distube.voices.leave(real_afk_channel)
|
|
||||||
// connected = false;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
async function getMember(client, userId) {
|
|
||||||
const guild = client.guilds.cache.get(process.env.D_GuildID);
|
|
||||||
if (!guild) return null;
|
|
||||||
|
|
||||||
// cache first (fast path)
|
|
||||||
let member = guild.members.cache.get(userId);
|
|
||||||
|
|
||||||
// fallback (safe path)
|
|
||||||
if (!member) {
|
|
||||||
member = await guild.members.fetch(userId).catch(() => null);
|
|
||||||
}
|
|
||||||
|
|
||||||
return member;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'timer24h',
|
|
||||||
|
|
||||||
async execute(timer, client) {
|
|
||||||
const member = await getMember(client, timer.assignedUser);
|
|
||||||
if (!member) return;
|
|
||||||
|
|
||||||
console.log(`⚠️ Less than 24 hours remaining for ${member.user.username}, notifying...`)
|
|
||||||
|
|
||||||
try {
|
|
||||||
await member.send(
|
|
||||||
`⚠️ Less than 24 hours remaining for: **${timer.topic}**`
|
|
||||||
)
|
|
||||||
console.log('notified successfully!')
|
|
||||||
} catch (e) {
|
|
||||||
console.error(`notification failed, errorr ${e}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
const { mClient } = require('../index');
|
|
||||||
function getRemaining(timer) {
|
|
||||||
if (timer.state !== 'running') {
|
|
||||||
return timer.timeRemaining;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Math.max(
|
|
||||||
0,
|
|
||||||
timer.timeRemaining - (Date.now() - timer.startedAt)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'timerCheck',
|
|
||||||
|
|
||||||
async execute(client) {
|
|
||||||
const db = mClient.db('neo-db');
|
|
||||||
const wgeColl = db.collection('timer_wge');
|
|
||||||
|
|
||||||
const timers = await wgeColl.find({
|
|
||||||
state: { $ne: 'stopped' }
|
|
||||||
}).toArray();
|
|
||||||
|
|
||||||
const now = Date.now();
|
|
||||||
|
|
||||||
for (const timer of timers) {
|
|
||||||
|
|
||||||
const remaining = getRemaining(timer);
|
|
||||||
|
|
||||||
// -------------------------
|
|
||||||
// HALF TIME (3.5 days left)
|
|
||||||
// -------------------------
|
|
||||||
if (
|
|
||||||
!timer.notifications?.half &&
|
|
||||||
remaining <= 3.5 * 24 * 60 * 60 * 1000
|
|
||||||
) {
|
|
||||||
await wgeColl.updateOne(
|
|
||||||
{ _id: timer._id },
|
|
||||||
{ $set: { "notifications.half": true } }
|
|
||||||
);
|
|
||||||
|
|
||||||
client.emit('timerHalf', timer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------
|
|
||||||
// 24H WARNING
|
|
||||||
// -------------------------
|
|
||||||
if (
|
|
||||||
!timer.notifications?.day24 &&
|
|
||||||
remaining <= 24 * 60 * 60 * 1000
|
|
||||||
) {
|
|
||||||
await wgeColl.updateOne(
|
|
||||||
{ _id: timer._id },
|
|
||||||
{ $set: { "notifications.day24": true } }
|
|
||||||
);
|
|
||||||
|
|
||||||
client.emit('timer24h', timer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// -------------------------
|
|
||||||
// COMPLETION
|
|
||||||
// -------------------------
|
|
||||||
if (
|
|
||||||
!timer.notifications?.complete &&
|
|
||||||
remaining <= 0
|
|
||||||
) {
|
|
||||||
await wgeColl.updateOne(
|
|
||||||
{ _id: timer._id },
|
|
||||||
{ $set: { "notifications.complete": true } }
|
|
||||||
);
|
|
||||||
|
|
||||||
client.emit('timerComplete', timer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,245 +0,0 @@
|
|||||||
const { mClient } = require('..');
|
|
||||||
|
|
||||||
async function getMember(client, userId) {
|
|
||||||
const guild = client.guilds.cache.get(process.env.D_GuildID);
|
|
||||||
|
|
||||||
if (!guild) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
guild.members.cache.get(userId) ||
|
|
||||||
await guild.members.fetch(userId).catch(() => null)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
function getParticipantWeight(participant, now = Date.now()) {
|
|
||||||
// Never selected before -> strongly favor them
|
|
||||||
if (!participant.lastExpertAt) {
|
|
||||||
return 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
const lastExpertAt = new Date(participant.lastExpertAt).getTime();
|
|
||||||
|
|
||||||
// Invalid date safety
|
|
||||||
if (Number.isNaN(lastExpertAt)) {
|
|
||||||
return 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
const daysSinceExpert = Math.max(
|
|
||||||
0,
|
|
||||||
(now - lastExpertAt) / (24 * 60 * 60 * 1000)
|
|
||||||
);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Square-root weighting prevents very old participants
|
|
||||||
* from completely dominating the random selection.
|
|
||||||
*
|
|
||||||
* Examples:
|
|
||||||
* 1 day -> ~1.41
|
|
||||||
* 7 days -> ~2.83
|
|
||||||
* 30 days -> ~5.57
|
|
||||||
*/
|
|
||||||
return Math.sqrt(daysSinceExpert + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
function weightedRandom(participants) {
|
|
||||||
if (!participants.length) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const weightedParticipants = participants.map(participant => ({
|
|
||||||
participant,
|
|
||||||
weight: getParticipantWeight(participant)
|
|
||||||
}));
|
|
||||||
|
|
||||||
const totalWeight = weightedParticipants.reduce(
|
|
||||||
(total, item) => total + item.weight,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
|
|
||||||
let random = Math.random() * totalWeight;
|
|
||||||
|
|
||||||
for (const item of weightedParticipants) {
|
|
||||||
random -= item.weight;
|
|
||||||
|
|
||||||
if (random <= 0) {
|
|
||||||
return item.participant;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Floating-point safety fallback
|
|
||||||
return weightedParticipants[weightedParticipants.length - 1].participant;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function selectWgeParticipant(
|
|
||||||
participateColl,
|
|
||||||
{ excludeUserId = null } = {}
|
|
||||||
) {
|
|
||||||
const filter = {
|
|
||||||
status: true
|
|
||||||
};
|
|
||||||
|
|
||||||
if (excludeUserId) {
|
|
||||||
filter.userID = {
|
|
||||||
$ne: excludeUserId
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const participants = await participateColl
|
|
||||||
.find(filter)
|
|
||||||
.toArray();
|
|
||||||
|
|
||||||
return weightedRandom(participants);
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'timerComplete',
|
|
||||||
|
|
||||||
async execute(timer, client) {
|
|
||||||
const db = mClient.db('neo-db');
|
|
||||||
|
|
||||||
const wgeColl = db.collection('timer_wge');
|
|
||||||
const participateColl = db.collection('items_wge');
|
|
||||||
const channelColl = db.collection('config_channels');
|
|
||||||
|
|
||||||
const guild = client.guilds.cache.get(process.env.D_GuildID);
|
|
||||||
|
|
||||||
if (!guild) {
|
|
||||||
console.error('timerComplete: Guild not found.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notify previous expert
|
|
||||||
const previousMember = await getMember(
|
|
||||||
client,
|
|
||||||
timer.assignedUser
|
|
||||||
);
|
|
||||||
|
|
||||||
if (previousMember) {
|
|
||||||
await previousMember.send(
|
|
||||||
`❌ Timer ran out: **${timer.topic}** ...Re-assigning randomly...`
|
|
||||||
).catch(error => {
|
|
||||||
console.error(
|
|
||||||
`timerComplete: Failed to DM ${timer.assignedUser}:`,
|
|
||||||
error
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get configured WGE channel
|
|
||||||
const wgeChannelConfig = await channelColl.findOne({
|
|
||||||
purpose: 'wge',
|
|
||||||
guildID: process.env.D_GuildID
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!wgeChannelConfig) {
|
|
||||||
console.error(
|
|
||||||
'timerComplete: WGE channel configuration not found.'
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const channel = client.channels.cache.get(
|
|
||||||
wgeChannelConfig.channelID
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!channel) {
|
|
||||||
console.error('timerComplete: WGE channel not found.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Weighted random selection.
|
|
||||||
// Previous expert is explicitly excluded.
|
|
||||||
const selectedParticipant = await selectWgeParticipant(
|
|
||||||
participateColl,
|
|
||||||
{
|
|
||||||
excludeUserId: timer.assignedUser
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!selectedParticipant) {
|
|
||||||
await channel.send({
|
|
||||||
content:
|
|
||||||
`The timer for <@${timer.assignedUser}> has run out, ` +
|
|
||||||
`but there are currently no other participating users available for reassignment.`
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const newMember = await guild.members
|
|
||||||
.fetch(selectedParticipant.userID)
|
|
||||||
.catch(() => null);
|
|
||||||
|
|
||||||
if (!newMember) {
|
|
||||||
console.error(
|
|
||||||
`timerComplete: Could not fetch selected user ${selectedParticipant.userID}.`
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const newAssignedUser = newMember.user;
|
|
||||||
|
|
||||||
const wgeDefaultAssignedTime =
|
|
||||||
7 * 24 * 60 * 60 * 1000;
|
|
||||||
|
|
||||||
const assignedAt = new Date();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Update participant statistics.
|
|
||||||
*
|
|
||||||
* $inc automatically creates expertCount with value 1
|
|
||||||
* if the field does not exist yet.
|
|
||||||
*/
|
|
||||||
await participateColl.updateOne(
|
|
||||||
{
|
|
||||||
_id: selectedParticipant._id
|
|
||||||
},
|
|
||||||
{
|
|
||||||
$set: {
|
|
||||||
lastExpertAt: assignedAt
|
|
||||||
},
|
|
||||||
$inc: {
|
|
||||||
expertCount: 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// Remove the expired timer
|
|
||||||
await wgeColl.deleteOne({
|
|
||||||
_id: timer._id
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create new timer
|
|
||||||
await wgeColl.insertOne({
|
|
||||||
assignedUser: newAssignedUser.id,
|
|
||||||
assigningUser: timer.assigningUser,
|
|
||||||
|
|
||||||
startedAt: Date.now(),
|
|
||||||
timeRemaining: wgeDefaultAssignedTime,
|
|
||||||
|
|
||||||
state: 'running',
|
|
||||||
|
|
||||||
notifications: {
|
|
||||||
half: false,
|
|
||||||
day24: false,
|
|
||||||
complete: false
|
|
||||||
},
|
|
||||||
|
|
||||||
topic: timer.topic,
|
|
||||||
debug: false,
|
|
||||||
|
|
||||||
createdAt: assignedAt
|
|
||||||
});
|
|
||||||
|
|
||||||
await channel.send({
|
|
||||||
content:
|
|
||||||
`The timer for <@${timer.assignedUser}> has run out! Assigning randomly...\n` +
|
|
||||||
`<@${newAssignedUser.id}> is the next expert! Their topic is still **${timer.topic}**`
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(
|
|
||||||
`timerComplete: Reassigned WGE from ${timer.assignedUser} to ${newAssignedUser.id}.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
async function getMember(client, userId) {
|
|
||||||
const guild = client.guilds.cache.get(process.env.D_GuildID);
|
|
||||||
if (!guild) return null;
|
|
||||||
|
|
||||||
// cache first (fast path)
|
|
||||||
let member = guild.members.cache.get(userId);
|
|
||||||
|
|
||||||
// fallback (safe path)
|
|
||||||
if (!member) {
|
|
||||||
member = await guild.members.fetch(userId).catch(() => null);
|
|
||||||
}
|
|
||||||
|
|
||||||
return member;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
name: 'timerHalf',
|
|
||||||
|
|
||||||
async execute(timer, client) {
|
|
||||||
const member = await getMember(client, timer.assignedUser);
|
|
||||||
if (!member) return;
|
|
||||||
|
|
||||||
console.log(`⏳ Half time reached for: ${member.user.username}, notifying...`)
|
|
||||||
try {
|
|
||||||
await member.send(
|
|
||||||
`⏳ Half time reached for: **${timer.topic}**`
|
|
||||||
)
|
|
||||||
console.log('notified successfully!')
|
|
||||||
} catch (e) {
|
|
||||||
console.error(`notification failed, errorr ${e}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
const fs = require('node:fs')
|
|
||||||
const path = require('node:path')
|
|
||||||
module.exports = (client) => {
|
|
||||||
const buttonsFoldersPath = path.join(__dirname, '../buttons');
|
|
||||||
const buttonsFolders = fs.readdirSync(buttonsFoldersPath);
|
|
||||||
let buttonCount = 0
|
|
||||||
for (const folder of buttonsFolders) {
|
|
||||||
const buttonsPath = path.join(buttonsFoldersPath, folder);
|
|
||||||
const buttonsFiles = fs.readdirSync(buttonsPath).filter(file => file.endsWith('.js'));
|
|
||||||
for (const file of buttonsFiles) {
|
|
||||||
buttonCount++
|
|
||||||
const filePath = path.join(buttonsPath, file);
|
|
||||||
const button = require(filePath);
|
|
||||||
if ('execute' in button) {
|
|
||||||
client.buttons.set(button.name, button);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
console.log(`[${buttonCount}] Button(s) initialized`)
|
|
||||||
}
|
|
||||||