nodbot/functions.js
Skylar Grant 46e5079eaf
All checks were successful
NodBot PE Dockerization / build (push) Successful in 19s
Add client to sendAlert
2026-10-01 15:28:03 -04:00

937 lines
34 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* eslint-disable comma-dangle */
// dotenv for handling environment variables
const dotenv = require('dotenv').config();
// Assignment of environment variables for database access
const dbHost = process.env.dbHost;
const dbUser = process.env.dbUser;
const dbName = process.env.dbName;
const dbPass = process.env.dbPass;
const dbPort = process.env.dbPort;
const isDev = process.env.isDev;
const ownerId = process.env.ownerId;
const statusChannelId = process.env.statusChannelId;
// filesystem
const fs = require('fs');
const zlib = require('zlib');
// Discord.js
const Discord = require('discord.js');
// Fuzzy text matching for db lookups
const FuzzySearch = require('fuzzy-search');
// Axios for APIs
const axios = require('axios');
// Various imports from other files
const config = require('./config.json');
const strings = require('./strings.json');
const appVersion = require('./package.json').version;
const slashCommandFiles = fs.readdirSync('./slash-commands/').filter(file => file.endsWith('.js'));
const dotCommandFiles = fs.readdirSync('./dot-commands/').filter(file => file.endsWith('.js'));
const customEmbeds = require('./CustomModules/Embeds.js');
// MySQL database connection
const mysql = require('mysql');
const { GifData, PastaData } = require('./CustomModules/NodBot');
const db = new mysql.createPool({
connectionLimit: 10,
host: dbHost,
user: dbUser,
password: dbPass,
database: dbName,
port: dbPort,
});
const functions = {
// Functions for managing and creating Collections
collections: {
interactionStorage(client) {
if (!client.iStorage) client.iStorage = new Discord.Collection();
client.iStorage.clear();
if (isDev) console.log('Interaction Storage Collection Built');
},
// Create the collection of slash commands
slashCommands(client) {
if (!client.slashCommands) client.slashCommands = new Discord.Collection();
client.slashCommands.clear();
for (const file of slashCommandFiles) {
const slashCommand = require(`./slash-commands/${file}`);
if (slashCommand.data != undefined) {
client.slashCommands.set(slashCommand.data.name, slashCommand);
}
}
if (isDev) console.log('Slash Commands Collection Built');
},
setvalidCommands(client) {
for (const entry of client.dotCommands.map(command => command)) {
config.validCommands.push(entry.name);
if (Array.isArray(entry.alias)) {
entry.alias.forEach(element => {
config.validCommands.push(element);
});
} else if (entry.alias != undefined) {
config.validCommands.push(entry.alias);
}
}
if (isDev) console.log(`Valid Commands Added to Config\n${config.validCommands}`);
},
dotCommands(client) {
if (!client.dotCommands) client.dotCommands = new Discord.Collection();
client.dotCommands.clear();
for (const file of dotCommandFiles) {
const dotCommand = require(`./dot-commands/${file}`);
client.dotCommands.set(dotCommand.name, dotCommand);
// if (Array.isArray(dotCommand.alias)) {
// dotCommand.alias.forEach(element => {
// client.dotCommands.set(element, dotCommand);
// });
// } else if (dotCommand.alias != undefined) {
// client.dotCommands.set(dotCommand.alias, dotCommand);
// }
}
if (isDev) console.log('Dot Commands Collection Built');
},
gifs(rows, client) {
if (!client.gifs) client.gifs = new Discord.Collection();
client.gifs.clear();
for (const row of rows) {
// const gif = {
// id: row.id,
// name: row.name,
// embed_url: row.embed_url
// };
const gifData = new GifData().setInfo(row.name, row.embed_url);
client.gifs.set(gifData.name, gifData);
}
if (isDev) console.log('GIFs Collection Built');
},
joints(rows, client) {
if (!client.joints) client.joints = new Discord.Collection();
client.joints.clear();
for (const row of rows) {
const joint = {
id: row.id,
content: row.content
};
client.joints.set(joint.id, joint);
}
if (isDev) console.log('Joints Collection Built');
},
pastas(rows, client) {
if (!client.pastas) client.pastas = new Discord.Collection();
client.pastas.clear();
for (const row of rows) {
const pastaData = new PastaData().setInfo(row.name, row.content, row.iconurl, row.id);
client.pastas.set(pastaData.name, pastaData);
}
if (isDev) console.log('Pastas Collection Built');
},
requests(rows, client) {
if (!client.requests) client.requests = new Discord.Collection();
client.requests.clear();
for (const row of rows) {
const request = {
id: row.id,
author: row.author,
request: row.request,
};
client.requests.set(request.id, request);
}
if (isDev) console.log('Requests Collection Built');
},
strains(rows, client) {
if (!client.strains) client.strains = new Discord.Collection();
client.strains.clear();
for (const row of rows) {
const strain = {
id: row.id,
name: row.strain,
};
client.strains.set(strain.name, strain);
// if (isDev) console.log(strain)
}
if (isDev) console.log('Strains Collection Built');
},
medicalAdvice(rows, client) {
if (!client.medicalAdviceColl) client.medicalAdviceColl = new Discord.Collection();
client.medicalAdviceColl.clear();
for (const row of rows) {
const medicalAdvice = {
id: row.id,
content: row.content
};
client.medicalAdviceColl.set(medicalAdvice.id, medicalAdvice);
}
if (isDev) console.log('Medical Advice Collection Built');
},
roaches(client) {
if (!client.roaches) client.roaches = new Discord.Collection();
client.roaches.clear();
if (isDev) console.log('Medical Advice Collection Built');
},
memberships(client) {
if (!client.memberships) client.memberships = new Discord.Collection();
client.memberships.clear();
client.memberships.set("481933290912350209", "vfsh");
if (isDev) console.log('Memberships Collection Built');
}
},
embeds: {
help(interaction) {
// Construct the Help Embed
const helpEmbed = new Discord.MessageEmbed()
.setColor('BLUE')
.setAuthor({name: 'Help Page'})
.setThumbnail(strings.urls.avatar)
.setFooter(`v${appVersion}`);
// Construct the Slash Commands help
let slashCommandsFields = [];
let slashSeenNames = new Array();
const slashCommandsMap = interaction.client.slashCommands.map(e => {
if (!slashSeenNames.includes(e.data.name)) {
slashSeenNames.push(e.data.name);
const command = {
name: e.data.name,
description: e.data.description
};
return command;
} else {
return null;
}
});
for (const e of slashCommandsMap) {
slashCommandsFields.push(`- \`/${e.name}\` - ${e.description}`);
}
console.log(slashCommandsFields);
// Construct the Dot Commands Help
let dotCommandsFields = new Array();
let dotSeenNames = new Array();
const dotCommandsMap = interaction.client.dotCommands.map(e => {
if (!dotSeenNames.includes(e.name)) {
dotSeenNames.push(e.name);
let command = {
name: e.name,
description: e.description,
usage: e.usage
};
command.aliasString = new String();
if (e.alias != undefined && typeof e.alias === 'object') {
for (const a of e.alias) {
command.aliasString += `\`.${a}\`, `;
}
} else if (e.alias != undefined && typeof e.alias === 'string') {
command.aliasString += `\`.${e.alias}\``;
} else {
command.aliasString = 'None';
}
return command;
} else {
return null;
}
});
for (const e of dotCommandsMap) {
if (e != null) {
dotCommandsFields.push(`- \`.${e.name}\` - ${e.description}\n\tUsage: ${e.usage}\n\tAliases: ${e.aliasString}`);
}
}
console.log(dotCommandsFields);
// Construct the Description Fields
const descriptionFields = [
`${strings.help.description}\n`,
`**Slash Commands**\n${strings.help.slash}\n`,
`${slashCommandsFields.join('\n')}\n`,
`**Dot Commands**\n${strings.help.dot}\n`,
`${dotCommandsFields.join('\n')}`
];
// Set the description
helpEmbed.setDescription(descriptionFields.join('\n'));
return { embeds: [
helpEmbed
], ephemeral: true };
},
gif(commandData) {
return { embeds: [new Discord.MessageEmbed()
.setAuthor({name: `${commandData.args}.${commandData.command}`})
.setImage(commandData.embed_url)
.setTimestamp()
.setFooter({text: commandData.author})]};
},
pasta(commandData, pastaData) {
return { embeds: [ new Discord.MessageEmbed()
.setAuthor({name: `${commandData.args}.${commandData.command}`})
.setDescription(pastaData.content)
.setThumbnail("https://assets.vfsh.dev/shednod.png")
.setTimestamp()
.setFooter({text: commandData.author})]};
},
pastas(commandData, indexedPastas) {
const pastasEmbed = new Discord.MessageEmbed()
.setAuthor({name: commandData.command})
.setTimestamp()
.setFooter({text: `Page: ${indexedPastas.pagesString}`})
.setDescription(indexedPastas.pastasString);
const pastasPageAR = customEmbeds.actionRows.pastasPageAR(indexedPastas.state);
return { embeds: [pastasEmbed], components: [pastasPageAR], ephemeral: true };
},
gifs(commandData, indexedGifs) {
const gifsEmbed = new Discord.MessageEmbed()
.setAuthor({name: commandData.command})
.setTimestamp()
.setFooter({text: `Page: ${indexedGifs.pagesString}`})
.setDescription(indexedGifs.gifsString);
const gifsPageAR = customEmbeds.actionRows.gifsPageAR(indexedGifs.state);
return { embeds: [gifsEmbed], components: [gifsPageAR], ephemeral: true };
},
joints(commandData, indexedJoints) {
const jointsEmbed = new Discord.MessageEmbed()
.setAuthor({name: commandData.command})
.setTimestamp()
.setFooter({text: `Page: ${indexedJoints.pagesString}`})
.setDescription(indexedJoints.jointsString);
const jointsPageAR = customEmbeds.actionRows.jointsPageAR(indexedJoints.state);
return { embeds: [jointsEmbed], components: [jointsPageAR], ephemeral: true };
},
text(commandData) {
const textEmbed = new Discord.MessageEmbed()
.setAuthor({ name: commandData.command })
.setDescription(commandData.content)
.setTimestamp()
.setFooter({text: commandData.author});
return textEmbed;
},
requests(commandData, indexedRequests) {
const requestsEmbed = new Discord.MessageEmbed()
.setAuthor({name: commandData.command})
.setTimestamp()
.setFooter({text: `Page: ${indexedRequests.pagesString}`})
.setDescription(indexedRequests.requestsString);
const requestsPageAR = customEmbeds.actionRows.requestsPageAR(indexedRequests.state);
return { embeds: [requestsEmbed], components: [requestsPageAR], ephemeral: true };
},
strain(strainInfo, interaction) {
const strainEmbed = new Discord.MessageEmbed()
.setTimestamp();
strainEmbed.addFields([
{
name: 'Strain Name',
value: `${strainInfo.strain}`,
inline: true,
},
{
name: 'Type',
value: `${strainInfo.type}`,
inline: true,
},
{
name: 'Effects',
value: `${strainInfo.effects}`,
inline: true,
},
{
name: 'Flavor',
value: `${strainInfo.flavor}`,
inline: true,
},
{
name: 'Rating',
value: `⭐️${strainInfo.rating}`,
inline: true,
},
{
name: 'Description',
value: `${strainInfo.description}`,
inline: false,
},
]);
interaction.reply({ embeds: [ strainEmbed ]});
},
dalle(prompt, imageUrl, size) {
const dalleEmbed = new Discord.MessageEmbed()
.setAuthor({ name: "NodBot powered by DALL-E", iconURL: "https://assets.vfsh.dev/openai-logos/PNGs/openai-logomark.png" })
.addFields(
{ name: "Prompt", value: prompt }
)
.setImage(imageUrl)
.setFooter({ text: `This ${size} image cost ${strings.costs.dalle[size]}¢ to generate.` })
return { embeds: [dalleEmbed] };
},
gpt(prompt, response, usage) {
const gptEmbed = new Discord.MessageEmbed()
.setAuthor({ name: "NodBot powered by GPT-3.5", iconURL: "https://assets.vfsh.dev/openai-logos/PNGs/openai-logomark.png" })
.setDescription(`**Prompt**\n${prompt}\n\n**Response**\n${response}`)
.setFooter({ text: `This prompt used ${usage.tokens} tokens for a cost of ${usage.usdc}¢. Generated using ${strings.ai.chatModel}` })
return { embeds: [gptEmbed] };
},
generatingResponse() {
const embed = new Discord.MessageEmbed()
.setAuthor({ name: "NodBot powered by OpenAI", iconURL: "https://assets.vfsh.dev/openai-logos/PNGs/openai-logomark.png" })
.setImage("https://media.tenor.com/aHMHzNGCb4kAAAAC/sucks.gif")
.setDescription("Generating a response, please stand by.")
.setFooter({ text: "Ligma balls" });
return { embeds: [embed] };
},
avWx: {
metar(metarData) {
const wgst = metarData.wgst ? `G${metarData.wgst}` : '';
const clouds = [];
const interAltim = Math.round((metarData.altim * 0.2952998057228486) * 10)
const altim = interAltim / 100;
metarData.clouds.forEach(cloudLayer => {
if (cloudLayer.base !== null) {
clouds.push(`${cloudLayer.cover} @ ${cloudLayer.base}'`);
} else {
clouds.push(`${cloudLayer.cover}`);
}
});
const embed = new Discord.MessageEmbed()
.setAuthor({ name: `${metarData.name} [${metarData.icaoId}] METAR`, iconURL: "https://aviationweather.gov/img/icons/awc-logo-180.png"})
// .setImage("https://media.discordapp.net/stickers/1175134632845516821.webp")
.setDescription(`**Do not use for real world flight planning or navigation.**`)
.setFooter({ text: "METAR by AviationWeather.gov for CumbHub LLC" })
.addFields(
{ name: 'Observation Time', value: `${metarData.reportTime}Z`, inline: true },
{ name: 'Temperature', value: `${metarData.temp}ºC/${metarData.dewp}ºC`, inline: true },
{ name: 'Winds', value: `${metarData.wdir.toString().padStart(3, '0')}º@${metarData.wspd}${wgst} kts`, inline: true },
{ name: 'Visibility', value: `${metarData.visib} SM`, inline: true },
{ name: 'Clouds', value: clouds.join('\n'), inline: true },
{ name: 'Altimeter', value: `${altim} inHg`, inline: true }
)
return { content: metarData.rawOb, embeds: [embed] };
},
datis(datisData) {
const messageEmbed = new Discord.MessageEmbed()
.setAuthor({ name: `${datisData[0].airport} Digital ATIS` })
// .setImage('https://media.discordapp.net/stickers/1175134632845516821.webp')
.setDescription(`**Do not use for real world flight planning or navigation.**`)
.setFooter({ text: 'D-ATIS by Clowd.io for CumbHub LLC' })
if (datisData.length > 1) {
datisData.forEach(data => {
if (data.type === 'dep') messageEmbed.addFields({ name: 'Departure Digital ATIS', value: data.datis, inline: false });
if (data.type === 'arr') messageEmbed.addFields({ name: 'Arrival Digital ATIS', value: data.datis, inline: false });
messageEmbed.addFields({ name: 'Information', value: data.code, inline: true });
})
messageEmbed.addFields(
{ name: 'Retreival Time', value: `${new Date().toISOString()}`, inline: true }
);
} else {
messageEmbed.addFields(
{ name: 'Digital ATIS', value: datisData[0].datis, inline: false },
{ name: 'Information', value: `${datisData[0].code}`, inline: true },
{ name: 'Retreival Time', value: `${new Date().toISOString()}`, inline: true }
)
}
const messagePayload = { embeds: [ messageEmbed ] };
return messagePayload;
}
},
noMembership() {
const embed = new Discord.MessageEmbed()
.setAuthor({ name: 'NodBot, powered by Enshittification'})
.setTitle('🚨 Subscription Required 🚨')
.setDescription('You have attempted to access NodBot\’s premium services without an active subscription. Please refer to our updated Terms of Service and pay the necessary fees to continue. [PayPal link](https://paypal.me/v0idf1sh)')
.setFooter({ text: "Ligma balls" });
return { embeds: [embed] };
},
membershipAnnouncement() {
const announcement = '# 🚨 Attention, peasants 🚨\n\nBig changes are here! As of today, NodBot is no longer a free service. Due to rising operational costs, we’re moving to a subscription-based model.\n\nEffective immediately, non-paying users (freeloaders) will have all commands rejected. To regain access, kindly submit a donation of your hard-earned monies, I\'ll spend it better than you anyways.\n\n## 💰 New Pricing Structure\nNodBot\'s subscription is a pay-what-you-want model with a minimum monthly donation valued at $10 USD.\n\nThank you for your continued (and now mandatory) support!\n\n— NodBot, your favorite paywalled AI overlord';
const embed1 = new Discord.MessageEmbed()
.setAuthor({ name: 'Terms of Use' })
.setDescription('By continuing to exist within the same digital space as NodBot, you automatically agree to the following terms:\n* Subscription Fees – Access to NodBot is now a privilege, not a right. Users must pay the required fees or suffer the consequences (i.e., total rejection and public shaming).\n* Payment Processing Period – Due to fraud prevention measures, payments must be verified before access to the bot is restored. Please allow 2-4 hours for access to be restored.\n* Non-Refundable Payments – If you thought there were refunds, think again moron. No take-backs.\n* Service Interruptions – NodBot may go offline at any time due to totally legitimate server issues. No compensation will be provided.\n* Arbitrary Rule Enforcement – Rules are subject to change at my whim, and compliance is mandatory.');
const embed2 = new Discord.MessageEmbed()
.setAuthor({ name: 'Privacy Policy' })
.setDescription('* Data Collection – NodBot does collect personal data, including but not limited to: location, IP address, MAC address, physical address, mother\'s maiden name, social security number, credit card numbers, phone fingerprints, physical fingerprints, penis length and girth, first pet\'s name, city where you met your spouse, and city where your parents met.\n* Payment Info – All payments are processed through a sketchy-looking PayPal link. NodBot and voidf1sh take no responsibility if your bank, CPA, lawyer, or local PD calls you afterward.\n* Chat Logs – NodBot may or may not remember every dumbass thing you’ve ever typed. Just assume it does.\n* Third-Party Sharing – Your usage data may be shared with savage\'s mom\n* Right to Be Forgotten – You can request NodBot forget your existence, but that requires a one-time processing fee of $50.');
return { content: announcement, embeds: [ embed1, embed2 ] };
},
error(errorText) {
const errorEmbed = new Discord.MessageEmbed()
.setAuthor({ name: "Error!" })
.setDescription(errorText)
.setFooter({ text: appVersion });
return errorEmbed;
}
},
collect: {
gifName(interaction) {
const gifNameFilter = m => m.author.id == strings.temp.gifUserId;
return interaction.channel.createMessageCollector({ filter: gifNameFilter, time: 30000 });
},
},
upload: {
request(requester, requestText, messageUrl, client) {
const query = `INSERT INTO requests (author, request, status, url) VALUES (${db.escape(requester)},${db.escape(requestText)},'Active',${db.escape(messageUrl)})`;
db.query(query, (err, rows, fields) => {
if (err) throw err;
functions.download.requests(client);
});
},
async pasta(pastaData, client) {
const query = `INSERT INTO pastas (name, content) VALUES (${db.escape(pastaData.name)},${db.escape(pastaData.content)}) ON DUPLICATE KEY UPDATE content=${db.escape(pastaData.content)}`;
await db.query(query, (err, rows, fields) => {
if (err) throw err;
functions.download.pastas(client);
});
return;
},
joint(content, client) {
const query = `INSERT INTO joints (content) VALUES (${db.escape(content)})`;
db.query(query, (err, rows, fields) => {
if (err) throw err;
functions.download.joints(client);
});
},
async gif(gifData, client) {
const query = `INSERT INTO gifs (name, embed_url) VALUES (${db.escape(gifData.name)}, ${db.escape(gifData.url)}) ON DUPLICATE KEY UPDATE embed_url=${db.escape(gifData.url)}`;
await db.query(query, (err, rows, fields) => {
if (err) throw err;
functions.download.gifs(client);
});
},
setup(interaction) {
/* Tables:
* - gifs
* - joints
* - pastas
* - requests
* - strains */
const gifsQuery = "CREATE TABLE 'gifs' (id int(11), name varchar(100), embed_url varchar(1000), PRIMARY KEY(id))";
const jointsQuery = "CREATE TABLE 'joints' (id int(11), content varchar(1000), PRIMARY KEY(id))";
const pastasQuery = "CREATE TABLE 'pastas' (id int(11), name varchar(100), content varchar(1900), iconurl varchar(200) DEFAULT 'https://cdn.discordapp.com/avatars/513184762073055252/12227aa23a06d5178853e59b72c7487b.webp?size=128', PRIMARY KEY(id))";
const requestsQuery = "CREATE TABLE 'requests' (id int(11), author varchar(100), request varchar(1000), status varchar(10) DEFAULT 'Active', PRIMARY KEY(id))";
const strainsQuery = "CREATE TABLE 'strains' (id smallint(6), name varchar(60), type varchar(10), effects varchat(80), ailment varchar(70), flavor varchar(30), PRIMARY KEY(id))";
// Check for owner
if (interaction.user.id == ownerId) {
db.query(gifsQuery, (err, rows, fields) => {
if (err) throw err;
});
db.query(jointsQuery, (err, rows, fields) => {
if (err) throw err;
});
db.query(pastasQuery, (err, rows, fields) => {
if (err) throw err;
});
db.query(requestsQuery, (err, rows, fields) => {
if (err) throw err;
});
db.query(strainsQuery, (err, rows, fields) => {
if (err) throw err;
});
return 'I\'ve created the required tables. Please check your database to validate this.';
} else {
return 'Sorry, you don\'t have permission to do that.';
}
},
medicalAdvice(content, client) {
const query = `INSERT INTO medical_advice (content) VALUES (${db.escape(content)})`;
db.query(query, (err, rows, fields) => {
if (err) throw err;
functions.download.medicalAdvice(client);
});
},
strain(interaction) {
const strain = db.escape(interaction.options.getString('name'));
const type = db.escape(interaction.options.getString('type'));
const effects = db.escape(( interaction.options.getString('effects') || 'Unkown' ));
const description = db.escape(( interaction.options.getString('description') || 'Unknown' ));
const flavor = db.escape(( interaction.options.getString('flavor') || 'Unknown' ));
const rating = db.escape(( interaction.options.getString('rating') || '3' ));
const strainQuery = `INSERT INTO strains (strain, type, effects, description, flavor, rating) VALUES (${strain}, ${type}, ${effects}, ${description}, ${flavor}, ${rating}) ON DUPLICATE KEY UPDATE strain=${db.escape(strain)}, type=${db.escape(type)}, effects=${db.escape(effects)}, description=${db.escape(description)}, flavor=${db.escape(flavor)}, rating=${db.escape(rating)}`;
console.log(strainQuery);
return new Promise((resolve, reject) => {
db.query(strainQuery, (err, rows, fields) => {
if (err) reject(err);
functions.download.strains(interaction.client);
resolve();
});
})
},
openai(user, prompt, engine, tokens, usdc) {
const query = `INSERT INTO openai (user, prompt, engine, tokens, usdc) VALUES (${db.escape(user)}, ${db.escape(prompt)}, ${db.escape(engine)}, ${db.escape(tokens)}, ${db.escape(usdc)})`;
db.query(query, (err) => {
if (err) throw err;
});
}
},
download: {
async requests(client) {
const query = 'SELECT * FROM requests WHERE status = \'Active\' ORDER BY id DESC';
await db.query(query, (err, rows, fields) => {
if (err) throw err;
functions.collections.requests(rows, client);
});
},
async pastas(client) {
const query = 'SELECT * FROM pastas ORDER BY id ASC';
await db.query(query, (err, rows, fields) => {
if (err) throw err;
functions.collections.pastas(rows, client);
});
},
async gifs(client) {
const query = 'SELECT * FROM gifs ORDER BY id ASC';
await db.query(query, (err, rows, fields) => {
if (err) throw err;
functions.collections.gifs(rows, client);
});
},
async joints(client) {
const query = 'SELECT * FROM joints ORDER BY id ASC';
await db.query(query, (err, rows, fields) => {
if (err) throw err;
functions.collections.joints(rows, client);
});
},
async strain(strainName, interaction) {
const query = `SELECT id, strain, type, effects, description, flavor, rating FROM strains WHERE strain = ${db.escape(strainName)}`;
await db.query(query, (err, rows, fields) => {
if (rows != undefined) {
const strainInfo = {
id: `${rows[0].id}`,
strain: `${rows[0].strain}`,
type: `${rows[0].type}`,
effects: `${rows[0].effects}`,
description: `${rows[0].description}`,
flavor: `${rows[0].flavor}`,
rating: `${rows[0].rating}`,
};
functions.embeds.strain(strainInfo, interaction);
}
});
},
async strains(client) {
const query = 'SELECT id, strain FROM strains';
await db.query(query, (err, rows, fields) => {
if (err) throw err;
functions.collections.strains(rows, client);
});
},
async medicalAdvice(client) {
const query = 'SELECT * FROM medical_advice ORDER BY id ASC';
await db.query(query, (err, rows, fields) => {
if (err) throw err;
functions.collections.medicalAdvice(rows, client);
});
}
},
weed: {
strain: {
lookup(strainName, client) {
const strainSearcher = new FuzzySearch(client.strains.map(e => e.name));
return strainSearcher.search(strainName).slice(0,25);
},
submit(strainName) {
const query = ``
return strainName;
}
}
},
search: {
gifs(query, client) {
const gifSearcher = new FuzzySearch(client.gifs.map(element => element.name));
return gifSearcher.search(query).slice(0,25);
},
pastas(query, client) {
const pastaSearcher = new FuzzySearch(client.pastas.map(element => element.name));
return pastaSearcher.search(query).slice(0,25);
}
},
// Parent-Level functions (miscellaneuous)
closeRequest(requestId, interaction) {
if (interaction.user.id == ownerId) {
const { client } = interaction;
const query = `UPDATE requests SET status = 'Closed' WHERE id = ${db.escape(requestId)}`;
db.query(query, (err, rows, fields) => {
if (err) throw err;
functions.download.requests(client);
});
interaction.reply({ content: `Request #${requestId} has been closed.`, ephemeral: true });
} else {
interaction.reply({ content: 'You do not have permission to do that.', ephemeral: true });
}
if (isDev) {
console.log(requestId, interaction, ownerId);
}
},
spongebob(commandData) {
let newText = '';
let lastIsUpper = 0;
for (const letter of commandData.args) {
if (letter == ' ') {
newText += letter;
continue;
}
if (letter == 'i' || letter == 'I') {
newText += 'i';
lastIsUpper = 0;
continue;
}
if (letter == 'l' || letter == 'L') {
newText += 'L';
lastIsUpper = 1;
continue;
}
if (lastIsUpper === 0) {
newText += letter.toUpperCase();
lastIsUpper = 1;
} else {
newText += letter.toLowerCase();
lastIsUpper = 0;
}
}
return newText + ' <:spongebob:1053398825965985822>';
},
setNick(user, nickname) {
return new Promise((resolve, reject) => {
user.setNickname(nickname).then(() => {
resolve('Nickname set.');
}).catch(err => {
reject(err);
});
});
},
checkBannedServers(client, statusChannel) {
if ( !config.bannedServers || !statusChannel ) return;
const guildChecks = [];
console.log('Guild Check:');
client.guilds.cache.forEach((guild) => {
const p = new Promise((resolve, reject) => {
console.log(` - ${guild.name} (${guild.id})`);
if (config.bannedServers.includes(guild.id)) {
console.log(` Leaving banned server: ${guild.name}`);
statusChannel.send(`<@${process.env.ownerId}> Leaving banned server: ${guild.name}`);
guild.leave().then(resolve).catch(reject);
} else {
resolve();
}
});
guildChecks.push(p);
});
Promise.all(guildChecks).then(() => {
console.log('All guilds checked.');
}).catch((err) => {
console.error(err);
});
},
checkMembership(client, userId) {
if (!client.memberships) throw new Error("Membership Collection Not Exist");
if (client.memberships.has(userId)) {
return true;
} else {
return false;
}
},
addMember(client, userId, username) {
if (!client.memberships) throw new Error("Memberships Collection Not Exist");
client.memberships.set(userId, username);
return;
},
removeMember(client, userId) {
if (!client.memberships) throw new Error("Memberships Collection Not Exist");
if (client.memberships.has(userId)) {
client.memberships.delete(userId);
return;
} else {
return;
}
},
autoresponses: { // Specific responses for certain keywords in sent messages
checkForAll(messageContent) {
let responses = [];
if (this.bigDoinks(messageContent)) responses.push("bigDoinks");
if (this.ligma(messageContent)) responses.push("ligma");
if (this.ong(messageContent)) responses.push("ong");
if (this.fuckYou(messageContent)) responses.push("fuckYou");
return responses;
},
bigDoinks(messageContent) {
let count = 0;
const { keywords } = strings.autoresponses.bigDoinks;
keywords.forEach(e => {
if (messageContent.includes(e)) count++;
});
if (count === keywords.length) {
return true;
}
},
ligma(messageContent) {
let count = 0;
const { keywords } = strings.autoresponses.ligma;
keywords.forEach(e => {
if (messageContent.includes(e)) count++;
});
if (count > 0) {
return true;
}
},
ong(messageContent) {
let count = 0;
const { keywords } = strings.autoresponses.ong;
keywords.forEach(e => {
if (messageContent.includes(e)) count++;
});
if (count > 0) {
return true;
}
},
fuckYou(messageContent) {
let count = 0;
const { keywords } = strings.autoresponses.fuckYou;
keywords.forEach(e => {
if (messageContent.includes(e)) count++;
});
if (count === keywords.length) {
return true;
}
},
send(message, responseType) {
const { responses } = strings.autoresponses[responseType];
const randomIndex = Math.floor(Math.random() * responses.length);
const response = responses[randomIndex];
try {
message.reply(response);
} catch(e) {
console.log(new Error(e));
}
}
},
avWx: {
parseICAOs(commandData) {
let input = commandData.args.toUpperCase();
// Replace newlines and different delimiters with a comma
let standardizedInput = input.replace(/[\s,;]+/g, ',');
// Split the string by commas
let icaoArray = standardizedInput.split(',');
// Trim each element to remove extra whitespace
icaoArray = icaoArray.map(icao => icao.trim()).filter(icao => icao.length > 0);
icaoArray.forEach(icao => {
if (!(config.icaoIds.includes(icao))) throw new Error(`Invalid ICAO ID Detected: ${icao}`);
});
// Join the array into a comma-separated string
return icaoArray.join(',');
},
metar: {
async getAllICAOs() {
const reqUrl = `https://aviationweather.gov/data/cache/stations.cache.json.gz`
try {
// Step 1: Download the GZipped file
const response = await axios({
url: reqUrl,
method: 'GET',
responseType: 'arraybuffer', // Ensure we get the raw binary data
headers: {
'Accept-Encoding': 'gzip' // Ensure the server sends gzipped content
}
});
// Step 2: Decompress the GZipped content
const buffer = Buffer.from(response.data);
zlib.gunzip(buffer, (err, decompressedBuffer) => {
if (err) {
console.error('An error occurred during decompression:', err);
return;
}
// Step 3: Parse the decompressed JSON
const jsonString = decompressedBuffer.toString('utf-8');
try {
const jsonData = JSON.parse(jsonString);
// console.log('Parsed JSON data:', jsonData);
jsonData.forEach(airport => {
config.icaoIds.push(airport.icaoId);
});
// console.log(`ICAO IDs: ${config.icaoIds.length}\n\n${config.icaoIds}`)
} catch (jsonError) {
console.error('An error occurred while parsing JSON:', jsonError);
}
});
} catch (error) {
console.error('An error occurred during the HTTP request:', error);
}
},
async getData(icaoList) {
const reqUrl = `https://aviationweather.gov/api/data/metar?ids=${icaoList}&format=json`;
const response = await axios.get(reqUrl);
return response.data;
},
parseData(metarData) {
let messages = [];
metarData.forEach(metar => {
messages.push(functions.embeds.avWx.metar(metar));
})
return messages;
}
},
datis: {
async getAllICAOs() {
const reqUrl = 'https://datis.clowd.io/api/stations';
const response = await axios.get(reqUrl);
response.data.forEach(icaoId => {
config.datisICAOs.push(icaoId);
});
},
validate(icaoId) {
return config.datisICAOs.includes(icaoId);
},
async getData(icaoId) {
const reqUrl = `https://datis.clowd.io/api/${icaoId}`;
const response = await axios.get(reqUrl);
if (response.error !== undefined) throw new Error('The D-ATIS API returned an error:\n' + response.error);
return response.data;
},
parseData(datisData) {
return functions.embeds.avWx.datis(datisData);
}
}
},
generateErrorId() {
const digitCount = 10;
const digits = [];
for (let i = 0; i < digitCount; i++) {
const randBase = Math.random();
const randNumRaw = randBase * 10;
const randNumRound = Math.floor(randNumRaw);
digits.push(randNumRound);
}
const errorId = digits.join("");
return errorId;
},
async sendAlert(embed, client) {
const statusChannel = await client.channels.fetch(statusChannelId)
.catch(err => {
console.error(err);
});
await statusChannel.send({ embeds: [ embed ] })
.catch(err => {
console.error(err);
});
}
};
module.exports = functions;