diff --git a/To-Do.md b/To-Do.md new file mode 100644 index 0000000..5c3d072 --- /dev/null +++ b/To-Do.md @@ -0,0 +1,9 @@ +- quotes leaderboard (count) +- quotes filter by channel +- event creation + reminder 1h before +- birthday role +- 8ball (neue Antworten) +- avatar +- mittwoch +- wetter +- WGE (help) diff --git a/buttons/honor/honors_leaderboard_left.js b/buttons/honor/honors_leaderboard_left.js index a6c0d89..9480798 100644 --- a/buttons/honor/honors_leaderboard_left.js +++ b/buttons/honor/honors_leaderboard_left.js @@ -24,7 +24,9 @@ module.exports = { const embed = new EmbedBuilder() .setTitle('Honors Leaderboard') .setThumbnail('https://cdn.discordapp.com/attachments/1152723542836772914/1152940755539722240/pngwing.com.png') - .setDescription(fields.toString()); + .setDescription(fields.toString()) + .setColor('#5865F2') // Discord's blurple color + .setFooter({ text: 'Use ◄ ► to navigate' }); await interaction.update({ embeds: [embed], components: [interaction.message.components[0]] diff --git a/buttons/honor/honors_leaderboard_right.js b/buttons/honor/honors_leaderboard_right.js index 94679db..5cfe146 100644 --- a/buttons/honor/honors_leaderboard_right.js +++ b/buttons/honor/honors_leaderboard_right.js @@ -22,7 +22,9 @@ module.exports = { const embed = new EmbedBuilder() .setTitle('Honors Leaderboard') .setThumbnail('https://cdn.discordapp.com/attachments/1152723542836772914/1152940755539722240/pngwing.com.png') - .setDescription(fields.toString()); + .setDescription(fields.toString()) + .setColor('#5865F2') // Discord's blurple color + .setFooter({ text: 'Use ◄ ► to navigate' }); await interaction.update({ embeds: [embed], components: [interaction.message.components[0]] diff --git a/buttons/honor/honors_leaderboard_self.js b/buttons/honor/honors_leaderboard_self.js index b60c33d..8149056 100644 --- a/buttons/honor/honors_leaderboard_self.js +++ b/buttons/honor/honors_leaderboard_self.js @@ -32,7 +32,10 @@ module.exports = { const embed = new EmbedBuilder() .setTitle('Honors Leaderboard') .setThumbnail('https://cdn.discordapp.com/attachments/1152723542836772914/1152940755539722240/pngwing.com.png') - .setDescription(fields.toString()); + .setDescription(fields.toString()) + .setColor('#5865F2') // Discord's blurple color + .setFooter({ text: 'Use ◄ ► to navigate' }); + await interaction.update({ embeds: [embed], components: [interaction.message.components[0]] diff --git a/buttons/nuts/nuts_leaderboard_left.js b/buttons/nuts/nuts_leaderboard_left.js index 4c08bc3..9b4fee8 100644 --- a/buttons/nuts/nuts_leaderboard_left.js +++ b/buttons/nuts/nuts_leaderboard_left.js @@ -24,7 +24,9 @@ module.exports = { const embed = new EmbedBuilder() .setTitle('Nuts Leaderboard') .setThumbnail('https://cdn.discordapp.com/attachments/1152723542836772914/1152940755539722240/pngwing.com.png') - .setDescription(fields.toString()); + .setDescription(fields.toString()) + .setColor('#5865F2') // Discord's blurple color + .setFooter({ text: 'Use ◄ ► to navigate' }); await interaction.update({ embeds: [embed], components: [interaction.message.components[0]] diff --git a/buttons/nuts/nuts_leaderboard_right.js b/buttons/nuts/nuts_leaderboard_right.js index 77eb2ff..f8225d4 100644 --- a/buttons/nuts/nuts_leaderboard_right.js +++ b/buttons/nuts/nuts_leaderboard_right.js @@ -22,7 +22,9 @@ module.exports = { const embed = new EmbedBuilder() .setTitle('Nuts Leaderboard') .setThumbnail('https://cdn.discordapp.com/attachments/1152723542836772914/1152940755539722240/pngwing.com.png') - .setDescription(fields.toString()); + .setDescription(fields.toString()) + .setColor('#5865F2') // Discord's blurple color + .setFooter({ text: 'Use ◄ ► to navigate' }); await interaction.update({ embeds: [embed], components: [interaction.message.components[0]] diff --git a/buttons/nuts/nuts_leaderboard_self.js b/buttons/nuts/nuts_leaderboard_self.js index e1960dc..d295c9b 100644 --- a/buttons/nuts/nuts_leaderboard_self.js +++ b/buttons/nuts/nuts_leaderboard_self.js @@ -32,7 +32,9 @@ module.exports = { const embed = new EmbedBuilder() .setTitle('Nuts Leaderboard') .setThumbnail('https://cdn.discordapp.com/attachments/1152723542836772914/1152940755539722240/pngwing.com.png') - .setDescription(fields.toString()); + .setDescription(fields.toString()) + .setColor('#5865F2') // Discord's blurple color + .setFooter({ text: 'Use ◄ ► to navigate' }); await interaction.update({ embeds: [embed], components: [interaction.message.components[0]] diff --git a/buttons/quotes/quotes_leaderboard_left.js b/buttons/quotes/quotes_leaderboard_left.js new file mode 100644 index 0000000..4e2224b --- /dev/null +++ b/buttons/quotes/quotes_leaderboard_left.js @@ -0,0 +1,70 @@ +const { EmbedBuilder, ButtonBuilder, ButtonStyle, ActionRowBuilder } = require('discord.js'); +const { mClient } = require('../..'); // Adjust the path as needed +function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } + +module.exports = { + name: 'quotes_leaderboard_right', + description: 'Navigate right through the quotes leaderboard', + async execute(interaction) { + await interaction.deferReply() + const db = mClient.db(process.env.M_DB) + const quotesColl = db.collection('quotes') + const maxValue = await quotesColl.countDocuments({ $and: [{ guildID: interaction.guild.id }, { count: { $gt: 0 } }] }) + + let skip = interaction.message.embeds[0].data.fields[0].value.split('.') + skip = Number(skip[0]) - 6 + if (skip >= (maxValue - (maxValue % 5))) { + skip = maxValue - (maxValue % 5) + } + + const quotesData = await quotesColl.find({ count: { $gt: 0 } }).sort({ count: -1, messageID: -1 }).skip(skip).limit(5).toArray() + const fields = [] + + const guild = await interaction.client.guilds.fetch(interaction.guild.id) + quotesData.forEach(async (data, index) => { + + let channel = await guild.channels.fetch(data.channelID) + let message = await channel.messages.fetch(data.messageID) + await delay(500) + fields.push({ + name: `\u200b`, + value: `${skip + index + 1}. [#${data.messageID}](https://discord.com/channels/${data.guildID}/${data.channelID}/${data.messageID})\r\n**by** <@${data.by}> • ⭐ ${data.count}\r\n${message.content}` + }) + }) + + await delay(5000) + console.log(fields) + const embed = new EmbedBuilder() + .setTitle('- Quotes Leaderboard -') + .setThumbnail('https://cdn.discordapp.com/attachments/1152723542836772914/1152940755539722240/pngwing.com.png') + .setFields(fields) + .setColor('#5865F2') // Discord's blurple color + .setFooter({ text: 'Use ◄ ► to navigate' }); + + const row = new ActionRowBuilder() + .addComponents( + new ButtonBuilder() + .setLabel('◄') + .setStyle(ButtonStyle.Primary) + .setCustomId('quotes_leaderboard_left') + .setDisabled(skip - 6 < 0) + ) + .addComponents( + new ButtonBuilder() + .setLabel('X') + .setStyle(ButtonStyle.Danger) + .setCustomId('abort') + ) + .addComponents( + new ButtonBuilder() + .setLabel('►') + .setStyle(ButtonStyle.Primary) + .setCustomId('quotes_leaderboard_right') + .setDisabled(skip + 4 > maxValue) + ) + await interaction.editReply({ + embeds: [embed], + components: [row] + }) + } +}; diff --git a/buttons/quotes/quotes_leaderboard_right.js b/buttons/quotes/quotes_leaderboard_right.js new file mode 100644 index 0000000..5b69312 --- /dev/null +++ b/buttons/quotes/quotes_leaderboard_right.js @@ -0,0 +1,70 @@ +const { EmbedBuilder, ButtonBuilder, ButtonStyle, ActionRowBuilder } = require('discord.js'); +const { mClient } = require('../..'); // Adjust the path as needed +function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } + +module.exports = { + name: 'quotes_leaderboard_right', + description: 'Navigate right through the quotes leaderboard', + async execute(interaction) { + await interaction.deferReply() + const db = mClient.db(process.env.M_DB) + const quotesColl = db.collection('quotes') + const maxValue = await quotesColl.countDocuments({ $and: [{ guildID: interaction.guild.id }, { count: { $gt: 0 } }] }) + + let skip = interaction.message.embeds[0].data.fields[0].value.split('.') + skip = Number(skip[0]) +4 + if (skip >= (maxValue - (maxValue % 5))) { + skip = maxValue - (maxValue % 5) + } + + const quotesData = await quotesColl.find({ count: { $gt: 0 } }).sort({ count: -1, messageID: -1 }).skip(skip).limit(5).toArray() + const fields = [] + + const guild = await interaction.client.guilds.fetch(interaction.guild.id) + quotesData.forEach(async (data, index) => { + + let channel = await guild.channels.fetch(data.channelID) + let message = await channel.messages.fetch(data.messageID) + await delay(500) + fields.push({ + name: `\u200b`, + value: `${skip + index + 1}. [#${data.messageID}](https://discord.com/channels/${data.guildID}/${data.channelID}/${data.messageID})\r\n**by** <@${data.by}> • ⭐ ${data.count}\r\n${message.content}` + }) + }) + + await delay(5000) + console.log(fields) + const embed = new EmbedBuilder() + .setTitle('- Quotes Leaderboard -') + .setThumbnail('https://cdn.discordapp.com/attachments/1152723542836772914/1152940755539722240/pngwing.com.png') + .setFields(fields) + .setColor('#5865F2') // Discord's blurple color + .setFooter({ text: 'Use ◄ ► to navigate' }); + + const row = new ActionRowBuilder() + .addComponents( + new ButtonBuilder() + .setLabel('◄') + .setStyle(ButtonStyle.Primary) + .setCustomId('quotes_leaderboard_left') + .setDisabled(skip - 6 < 0) + ) + .addComponents( + new ButtonBuilder() + .setLabel('X') + .setStyle(ButtonStyle.Danger) + .setCustomId('abort') + ) + .addComponents( + new ButtonBuilder() + .setLabel('►') + .setStyle(ButtonStyle.Primary) + .setCustomId('quotes_leaderboard_right') + .setDisabled(skip + 4 > maxValue) + ) + await interaction.editReply({ + embeds: [embed], + components: [row] + }) + } +}; diff --git a/commands/channels/channels.js b/commands/channels/channels.js new file mode 100644 index 0000000..9b5ab16 --- /dev/null +++ b/commands/channels/channels.js @@ -0,0 +1,106 @@ +const { SlashCommandBuilder, Events } = require('discord.js') +const { mClient } = require('../..') +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.DB) + const channelColl = db.collection('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!`, ephemeral: true + }) +} +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.', ephemeral: true }) +} +module.exports = { + data: new SlashCommandBuilder() + .setName('channels') + .setDescription('rund um den honor') + .addSubcommand(s => + s + .setName('set') + .setDescription('set a channel for a specific purpose') + .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' + })) + ) + , + async execute(interaction) { + switch (interaction.options._subcommand) { + case 'set': + await interaction.deferReply() + channelSet(interaction) + break; + case 'simulate': + channelSimulate(interaction) + break; + default: + break; + } + } +} \ No newline at end of file diff --git a/commands/honors/honors.js b/commands/honors/honors.js index 7ac7933..7000810 100644 --- a/commands/honors/honors.js +++ b/commands/honors/honors.js @@ -104,7 +104,9 @@ async function honorLeaderboard(interaction) { const embed = new EmbedBuilder() .setTitle('- Honors Leaderboard -') .setThumbnail('https://cdn.discordapp.com/attachments/1152723542836772914/1152940755539722240/pngwing.com.png') - .setDescription(fields.toString()); + .setDescription(fields.toString()) + .setColor('#5865F2') // Discord's blurple color + .setFooter({ text: 'Use ◄ ► to navigate' }); await interaction.editReply({ embeds: [embed], components: [row] diff --git a/commands/nuts/nuts.js b/commands/nuts/nuts.js index 17bd342..139dd16 100644 --- a/commands/nuts/nuts.js +++ b/commands/nuts/nuts.js @@ -129,7 +129,9 @@ async function nutsLeaderboard(interaction) { const embed = new EmbedBuilder() .setTitle('Nuts Leaderboard') .setThumbnail('https://cdn.discordapp.com/attachments/1152723542836772914/1152940755539722240/pngwing.com.png') - .setDescription(fields.toString()); + .setDescription(fields.toString()) + .setColor('#5865F2') // Discord's blurple color + .setFooter({ text: 'Use ◄ ► to navigate' }); await interaction.editReply({ embeds: [embed], components: [row] @@ -192,7 +194,9 @@ async function nutsCooldown(interaction) { let content = `Du kannst wieder nussen! :)` let thumbnail = 'https://cdn-icons-png.flaticon.com/512/7451/7451659.png' let title = 'Go Nuts!' - if (cooldown) { + + let date = (Date.now() / 1000) + if (cooldown.cooldown > date) { content = ` 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...' @@ -213,6 +217,8 @@ async function nutsNut(interaction) { const cdColl = db.collection('cooldown') const cdData = await cdColl.findOne({ userID: interaction.user.id }) + const embed = new EmbedBuilder() + .setThumbnail('https://cdn.discordapp.com/attachments/1152723542836772914/1152991361113538621/png-transparent-subscription-box-label-bag-mysterious-miscellaneous-purple-blue-thumbnail-PhotoRoom.png-PhotoRoom.png') let content const images = { @@ -259,11 +265,14 @@ async function nutsNut(interaction) { } else { content = `Du kannst erst wieder nussen :(` image = images["onCD"] + await delay(1000) + embed.setDescription(content) + embed.setThumbnail(image) + return await interaction.editReply({ + embeds: [embed] + }) } - const embed = new EmbedBuilder() - .setThumbnail('https://cdn.discordapp.com/attachments/1152723542836772914/1152991361113538621/png-transparent-subscription-box-label-bag-mysterious-miscellaneous-purple-blue-thumbnail-PhotoRoom.png-PhotoRoom.png') - await interaction.editReply({ embeds: [embed] }) diff --git a/commands/quotes/quotes.js b/commands/quotes/quotes.js index 32bcdc2..32559aa 100644 --- a/commands/quotes/quotes.js +++ b/commands/quotes/quotes.js @@ -1,17 +1,11 @@ /* -Add -Delete -Random -Random By Person -Direct Search by ID - Random By Year? -List? -Counter (Leaderboard?) +Counter (Leaderboard) */ const { SlashCommandBuilder, EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle, UserSelectMenuBuilder } = require('discord.js') const { mClient } = require('../..') require('dotenv').config() +function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } async function quotesAdd(interaction) { const messageLink = await interaction.options.getString('link') @@ -108,7 +102,7 @@ async function quotesSearch(interaction) { const found = await quotesColl.findOne({ messageID: id }) if (!found) { return await interaction.reply({ content: 'ID not found!', ephemeral: true }) } - + 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) @@ -122,9 +116,9 @@ async function quotesSearch(interaction) { quotesColl.findOneAndUpdate({ messageID: found.messageID - },{ - $inc: { count: 1} - },{ + }, { + $inc: { count: 1 } + }, { upsert: true }) @@ -166,18 +160,18 @@ async function quotesRandom(interaction) { const db = mClient.db(process.env.M_DB) const quotesColl = db.collection('quotes') var rdm - if(user){ + if (user) { rdm = await quotesColl.aggregate([ - { - $match: { by: user.id}, - },{ - $sample: { size: 1 } + { + $match: { by: user.id }, + }, { + $sample: { size: 1 } } ]).toArray() } else { rdm = await quotesColl.aggregate([ - { - $sample: { size: 1 } + { + $sample: { size: 1 } } ]).toArray() } @@ -196,9 +190,9 @@ async function quotesRandom(interaction) { quotesColl.findOneAndUpdate({ messageID: found.messageID - },{ - $inc: { count: 1} - },{ + }, { + $inc: { count: 1 } + }, { upsert: true }) @@ -258,7 +252,7 @@ async function quotesList(interaction) { .setCustomId('quotes_list_right') .setStyle(ButtonStyle.Primary) ) - + const select = new ActionRowBuilder() .addComponents( new UserSelectMenuBuilder() @@ -272,12 +266,74 @@ async function quotesList(interaction) { ephemeral: true }) - - } async function quotesLeaderboard(interaction) { - // need to add count to quotes + const db = mClient.db(process.env.M_DB) + const quotesColl = db.collection('quotes') + let skip = 0 + const minValue = 0 + const maxValue = await quotesColl.countDocuments({ $and: [{ guildID: interaction.guild.id }, { count: { $gt: 0 } }] }) + + const quotesData = await quotesColl.find({}).sort({ count: -1, messageID: -1 }).skip(skip).limit(5).toArray() + const fields = [] + + const guild = await interaction.client.guilds.fetch(interaction.guild.id) + quotesData.forEach(async (data, index) => { + + let channel = await guild.channels.fetch(data.channelID) + let message = await channel.messages.fetch(data.messageID) + + await delay(500) + let timestamp = new Date(message.createdTimestamp) + fields.push({ + name: `${index + 1}.`,//`\u200b` , + value: `[#${data.messageID}](https://discord.com/channels/${data.guildID}/${data.channelID}/${data.messageID})\r\n**by** <@${data.by}> • ⭐ ${data.count}\r\n_Posted on **${timestamp}**_\r\n${message.content}` + }) + + }) + + + await delay(5000) + console.log(fields) + quotesData.sort((a,b) => { + const numA = parseInt(a.name); + const numB = parseInt(b.name); + return numA - numB; + }) + console.log(fields) + + const embed = new EmbedBuilder() + .setTitle('- Quotes Leaderboard -') + .setThumbnail('https://cdn.discordapp.com/attachments/1152723542836772914/1152940755539722240/pngwing.com.png') + .setFields(fields) + .setColor('#5865F2') // Discord's blurple color + .setFooter({ text: `Use ◄ ► to navigate\r\n${skip}` }); + + const row = new ActionRowBuilder() + .addComponents( + new ButtonBuilder() + .setLabel('◄') + .setStyle(ButtonStyle.Primary) + .setCustomId('quotes_leaderboard_left') + ) + .addComponents( + new ButtonBuilder() + .setLabel('X') + .setStyle(ButtonStyle.Danger) + .setCustomId('abort') + ) + .addComponents( + new ButtonBuilder() + .setLabel('►') + .setStyle(ButtonStyle.Primary) + .setCustomId('quotes_leaderboard_right') + ) + await interaction.editReply({ + embeds: [embed], + components: [row] + }) } + module.exports = { data: new SlashCommandBuilder() .setName('quotes') @@ -326,6 +382,7 @@ module.exports = { quotesRandom(interaction) break; case 'leaderboard': + await interaction.deferReply() quotesLeaderboard(interaction) break; case 'list': diff --git a/commands/social/birthday.js b/commands/social/birthday.js new file mode 100644 index 0000000..47c7d3e --- /dev/null +++ b/commands/social/birthday.js @@ -0,0 +1,259 @@ +const { SlashCommandBuilder, EmbedBuilder } = require('discord.js') +const { mClient } = require('../..') +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 (ignore leap years) + 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; +} + +async function birthdayAdd(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", ephemeral: true }) + } + + const db = mClient.db(process.env.M_DB) + const bdayColl = db.collection('birthdays') + + const found = await bdayColl.findOne({ userID: target.id }) + if (found) { + return interaction.reply({ content: "Already in Database", ephemeral: true }) + } + + 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('birthdays') + + const found = await bdayColl.findOne({ userID: target.id }) + if (!found) { + return interaction.reply({ content: "Not yet in Database", ephemeral: true }) + } + + 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 birthdayEdit(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", ephemeral: true }) + } + + const db = mClient.db(process.env.M_DB) + const bdayColl = db.collection('birthdays') + + const found = await bdayColl.findOne({ userID: target.id }) + if (!found) { + return interaction.reply({ content: "Not yet in Database", ephemeral: true }) + } + + const data = { + guildID: interaction.guild.id, + userID: target.id, + day: day, + month: month + } + + const res = await bdayColl.findOneAndUpdate({ userID: target.id }, { $set: data }, { upsert: true }) + return interaction.reply({ content: "Birthday edited successfully!" }) +} +async function isDateInPast(day, month) { + const currentYear = new Date().getFullYear(); + const inputDate = new Date(currentYear, month - 1, day); + const now = new Date(); + return inputDate < now; +} +async function makeTimestamp(day, month, year) { + const date = new Date(year, month - 1, day); + const unixTimestamp = Math.floor(date.getTime() / 1000); + return unixTimestamp +} +function isToday(day, month) { + const currentYear = new Date().getFullYear(); + const inputDate = new Date(currentYear, month - 1, day); + const today = new Date(); + return ( + inputDate.getDate() === today.getDate() && + inputDate.getMonth() === today.getMonth() && + inputDate.getFullYear() === today.getFullYear() + ); +} +async function birthdayGet(interaction) { + let target = await interaction.options.getUser('user') + const db = mClient.db(process.env.M_DB) + const bdayColl = db.collection('birthdays') + + const found = await bdayColl.findOne({ userID: target.id }) + if (!found) { + return interaction.reply({ content: "Not in Database!", ephemeral: true }) + } + let unix + if(isDateInPast(found.day,found.month)){ + let nextYear = new Date().getFullYear() + 1 + unix = await makeTimestamp(found.day,found.month, nextYear) + } else { + let thisYear = new Date().getFullYear() + unix = await makeTimestamp(found.day,found.month, thisYear) + } + let description = `is on the \r\n` + if(isToday(found.day, found.month)){ + description = `IS TODAY!🥳🎉` + } + const embed = new EmbedBuilder() + .setThumbnail(target.displayAvatarURL()) + .setTitle(`${target.globalName ? target.globalName: target.username}'s Birthday!`) + .setDescription(description) + await interaction.reply({ embeds: [embed] }) +} + +module.exports = { + data: new SlashCommandBuilder() + .setName('birthday') + .setDescription('manage birthdays') + .addSubcommand(s => + s + .setName('add') + .setDescription('adds a 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('edit') + .setDescription('edits a birthday') + .addUserOption((option) => + option.setName('user').setDescription('user').setRequired(true)) + .addNumberOption((option) => + option.setName('day').setDescription('day').setRequired(true)) + .addNumberOption((option) => + option.setName('month').setDescription('month').setRequired(true))) + .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 'add': + if (!interaction.member.permissions.has("ADMINISTRATOR")) { + return await interaction.reply({ + content: "Unprivileged Access!", + ephemeral: true + }) + } + birthdayAdd(interaction) + break; + case 'delete': + if (!interaction.member.permissions.has("ADMINISTRATOR")) { + return await interaction.reply({ + content: "Unprivileged Access!", + ephemeral: true + }) + } + birthdayDelete(interaction) + break; + case 'edit': + if (!interaction.member.permissions.has("ADMINISTRATOR")) { + return await interaction.reply({ + content: "Unprivileged Access!", + ephemeral: true + }) + } + birthdayEdit(interaction) + break; + case 'get': + birthdayGet(interaction) + break; + default: + break; + } + } +} \ No newline at end of file diff --git a/commands/testStuff/simjoin.js b/commands/testStuff/simjoin.js deleted file mode 100644 index 834b34f..0000000 --- a/commands/testStuff/simjoin.js +++ /dev/null @@ -1,39 +0,0 @@ -const { SlashCommandBuilder, Events } = require('discord.js') -module.exports = { - data: new SlashCommandBuilder() - .setName('simjoin') - .setDescription('simulates a join event') - .addMentionableOption((option) => - option.setName('target').setDescription('user')), - async execute(interaction) { - - if(!interaction.member.permissions.has("ADMINISTRATOR")){ - return await interaction.reply({ - content: "Unprivileged Access!", - ephemeral: true - }) - } - - let target = interaction.options.getMentionable('target') - if(!target){ - target = interaction.member - } - try { - if(target.user.username){ - interaction.client.emit(Events.GuildMemberAdd, target) - await interaction.reply({ - content: "Done!", - ephemeral: true - }) - } - } catch (error) { - await interaction.reply({ - content: "Invalid Mentionable!", - ephemeral: true - }) - } - - - - } -} \ No newline at end of file diff --git a/events/Birthday.js b/events/Birthday.js new file mode 100644 index 0000000..d2b4237 --- /dev/null +++ b/events/Birthday.js @@ -0,0 +1,103 @@ +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!`) + + + const db = mClient.db(process.env.DB) + const channelsColl = db.collection('channels') + const 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 roleID = '702877228857557002' + const role = guild.roles.cache.get(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/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); + + ctx.font = '30px 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' + }] + }); + } +}; diff --git a/events/ClientReady.js b/events/ClientReady.js index 5f08030..e2926a2 100644 --- a/events/ClientReady.js +++ b/events/ClientReady.js @@ -1,4 +1,5 @@ -const { Events, ActivityType } = require('discord.js') +const { Events, ActivityType } = require('discord.js'); +const { mClient } = require('..'); module.exports = { name: Events.ClientReady, @@ -13,5 +14,39 @@ module.exports = { }], status: 'online' }) + + // if today is birthday + function isToday(day, month) { + const currentYear = new Date().getFullYear(); + const inputDate = new Date(currentYear, month - 1, day); + const today = new Date(); + return ( + inputDate.getDate() === today.getDate() && + inputDate.getMonth() === today.getMonth() && + inputDate.getFullYear() === today.getFullYear() + ); + } + async function isBirthday() { + const db = mClient.db(process.env.M_DB) + const bdayColl = db.collection('birthdays') + const allBirthdays = await bdayColl.find().toArray() + for (let index = 0; index < allBirthdays.length; index++) { + if (isToday(allBirthdays[index].day, allBirthdays[index].month)) { + let guild = client.guilds.cache.get(process.env.D_GuildID) + let member = guild.members.cache.get(allBirthdays[index].userID) + client.emit('Birthday', member) + } else { + // remove any residual birthday roles + try { + let guild = client.guilds.cache.get(process.env.D_GuildID) + let member = guild.members.cache.get(allBirthdays[index].userID) + await member.roles.remove('702877228857557002') + } catch (error) { + console.error('Could not remove role', error) + } + } + } + } + isBirthday() } } diff --git a/events/GuildMemberAdd.js b/events/GuildMemberAdd.js index 87bb65a..4d1bef3 100644 --- a/events/GuildMemberAdd.js +++ b/events/GuildMemberAdd.js @@ -1,15 +1,32 @@ 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) { - const guild = client.guilds.cache.get(process.env.D_GuildID); - const channel = guild.channels.cache.get(process.env.D_WelcomeID); console.log(`${member.user.username} joined the Server`); + const db = mClient.db(process.env.DB) + const channelsColl = db.collection('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; @@ -44,7 +61,7 @@ module.exports = { ctx.strokeStyle = '#000000'; // Black outline ctx.lineWidth = 3; // Thickness of the outline - let text = `Willkommen, ${member.user.username}!`; + 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 @@ -63,10 +80,8 @@ module.exports = { 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 <#850491176540700703> ${member}`, + content: `Bitte guck einmal in die <#455023824791011338> ${member}`, files: [{ attachment: banner, name: 'banner.png', diff --git a/index.js b/index.js index aa6d6c8..58b9571 100644 --- a/index.js +++ b/index.js @@ -9,14 +9,14 @@ const client = new Client({ intents: [ GatewayIntentBits.Guilds, GatewayIntentBits.GuildMembers, - GatewayIntentBits.GuildMessages, - GatewayIntentBits.GuildPresences, + GatewayIntentBits.GuildMessages, + GatewayIntentBits.GuildPresences, GatewayIntentBits.GuildMessageReactions, - GatewayIntentBits.GuildVoiceStates, + GatewayIntentBits.GuildVoiceStates, GatewayIntentBits.DirectMessages, - GatewayIntentBits.MessageContent - ], - partials: [Partials.Channel, Partials.Message, Partials.User, Partials.GuildMember, Partials.Reaction] + GatewayIntentBits.MessageContent, + ], + partials: [Partials.Channel, Partials.Message, Partials.User, Partials.GuildMember, Partials.Reaction] }); exports.client = client @@ -28,6 +28,6 @@ client.selectMenus = new Collection() // list of selectMenus fs.readdirSync('./handlers').forEach((handler) => { require(`./handlers/${handler}`)(client) - }); +}); - client.login(process.env.D_Token) \ No newline at end of file +client.login(process.env.D_Token) \ No newline at end of file diff --git a/legacyCommands/nuts/nutsLeaderboard.js b/legacyCommands/nuts/nutsLeaderboard.js index dca79fb..2761040 100644 --- a/legacyCommands/nuts/nutsLeaderboard.js +++ b/legacyCommands/nuts/nutsLeaderboard.js @@ -38,7 +38,9 @@ module.exports = { const embed = new EmbedBuilder() .setTitle('Nuts Leaderboard') .setThumbnail('https://cdn.discordapp.com/attachments/1152723542836772914/1152940755539722240/pngwing.com.png') - .setDescription(fields.toString()); + .setDescription(fields.toString()) + .setColor('#5865F2') // Discord's blurple color + .setFooter({ text: 'Use ◄ ► to navigate' }); await message.reply({ embeds: [embed], components: [row]