how to reference a currency collection from within a module in nodejs - javascript

I'm attempting to make an economy discord bot using node.js and I'm trying to move the commands into modules so that I can have a generic/dynamic command handler. How do I reference the currency collection and the models that I created within the main file within the command modules?
index.js file:
const currency = new Discord.Collection();
//defining methods for the currency collection
Reflect.defineProperty(currency, 'add', {
/* eslint-disable-next-line func-name-matching */
value: async function add(id, amount) {
const user = currency.get(id);
if (user) {
user.balance += Number(amount);
return user.save();
}
const newUser = await Users.create({ user_id: id, balance: amount });
currency.set(id, newUser);
return newUser;
},
});
Reflect.defineProperty(currency, 'getBalance', {
/* eslint-disable-next-line func-name-matching */
value: function getBalance(id) {
const user = currency.get(id);
return user ? user.balance : 0;
},
});
(In a subfolder) balance.js:
module.exports = {
name: 'balance',
description: 'get balance',
execute(message, args) {
const target = message.mentions.users.first() || message.author;
return message.channel.send(`${target.tag} has ${currency.getBalance(target.id)}🍉`);
},
};
Which currently throws an error on currency, since it's not defined. However, I don't know how to reference the currency collection I made in index.js, which also has methods created for it.
Thank you in advance.

To do this you could attach the Collection to your Client. Something like
Client.currency = new Discord.Collection()
Every time you then reference the collection, instead of doing currency you would then run Client.currency.
As for accessing the currency object across the files, I'd add another parameter to your execute method, something like this:
module.exports = {
name: 'balance',
description: 'get balance',
execute(client, message, args) { // Notice the added "client"
const target = message.mentions.users.first() || message.author;
return message.channel.send(`${target.tag} has ${client.currency.getBalance(target.id)}🍉`); // Added "client." in front of "currency", because currency is a property of your client now
},
};
Then, when executing the execute method, you'd run execute(Client, message, arguments);. Your client would then be passed into the command and be usable in there.

Related

TypeError: commands.options?.map() is not a function when setting slash commands

discord js v13.3.1
I have a set up with my bot that allows me to update and push slash commands via a command, deploy. The deploy command looks like this:
module.exports = {
name: "deploy",
description: "deploys slash commands",
disabled: false,
async execute(interaction, args, client) {
if (interaction.author.id !== process.env.OWNERID) return interaction.reply('You must be the owner to use this!');
const cmds = client.commands
.filter(command => command.slash)
.map(command => {
let {
name,
description = "missing description",
options = [],
slash = false,
defaultPermission = true,
slashPermissions = [],
} = command;
if (typeof name === "string") name = [name];
const cmd = { name: name[0], description, options, defaultPermission, permissions: slashPermissions };
return cmd;
});
await setCommands(interaction.guild?.commands)
.then(interaction.reply(`Registered ${cmds.length} commands to this guild!`));
async function setCommands(commandManager) {
const appCommands = await commandManager.set(
commandManager?.guild ? cmds : cmds.filter(cmd => !cmd.permissions.length)
);
if (commandManager?.guild) {
const fullPermissions = appCommands
.map(appCommand => {
const permissions = cmds.find(cmd => cmd.name === appCommand.name).permissions;
return { id: appCommand.id, permissions };
})
.filter(appCommand => appCommand.permissions.length);
await commandManager.permissions.set({ fullPermissions });
}
}
}
}
I stopped work on my bot awhile back, and now am trying to update the rest of my commands to have slash functionality. I have slash commands registered to my guild, so this command has worked in the past as is. Now, when I try to deploy my slash commands, I am getting this error in my console:
main\node_modules\discord.js\src\managers\ApplicationCommandManager.js:246
options: command.options?.map(o => ApplicationCommand.transformOption(o)),
^
TypeError: command.options?.map is not a function
at Function.transformCommand (main\node_modules\discord.js\src\managers\ApplicationCommandManager.js:246:33)
at main\node_modules\discord.js\src\managers\ApplicationCommandManager.js:163:48
at Array.map (<anonymous>)
at GuildApplicationCommandManager.set (main\node_modules\discord.js\src\managers\ApplicationCommandManager.js:163:22)
at setCommands (main\commands\admin\deploy.js:34:54)
at Object.execute (main\commands\admin\deploy.js:29:19)
at module.exports (main\events\guild\messageCreate.js:28:51)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
For reference, my commands are built as such:
module.exports = {
name: "move",
description: "Move all users from one vc to another",
usage: `\`${process.env.PREFIX}move <vc1> <vc2>\``,
alias: ["mv"],
disabled: false,
slash: true,
options: [
{
name: 'target',
type: 'CHANNEL',
channelTypes: ['GUILD_VOICE'],
description: 'Channel to move users from',
required: true
},
{
name: 'destination',
type: 'CHANNEL',
channelTypes: ['GUILD_VOICE'],
description: 'Channel to move users into',
required: true
}
],
permission: ['MOVE_MEMBERS'],
async execute(interaction, args){
}
}
Is this an issue with how I am building my options blocks in my commands themselves, or how I am parsing them to send to guildCommandManager? I'm assuming the former because the error is a TypeError, but I am historically bad at working with maps and objects, so I could be wrong, and it's hard for me to figure out since the error is being thrown from the djs module and not my code itself
Just use the rest method which you can view the code of it here on the discord.js guide.
https://discordjs.guide/creating-your-bot/creating-commands.html#command-deployment-script
You can create global commands with: applicationCommands
and create local commands for 1 server with: applicationGuildCommands

Importing variables from other files

I am trying to import a variable from one of my files (File 1) and use it in File 2. I have imported File 2 into File 1 but I am receiving error. My channel ID is correct, in this case you would have to choose the channel so the channel ID is not the issue here.
TypeError: setr.send is not a function
File 1
const Discord = require("discord.js");
const axios = require("axios");
let config = require("../config.json");
module.exports = {
name: "setrestart",
description: "sets the restart channel",
async execute(message, args) {
const perm = new Discord.MessageEmbed()
.setDescription(":x: You do not have permission to use this command.")
.setColor("#E74C3C");
if (!message.guild.me.hasPermission("ADMINISTRATOR"))
return message.channel.send(perm);
if (message.author.id !== "ID")
return message.channel.send(perm);
const channelx =
message.mentions.channels.first() ||
message.guild.channels.cache.find((c) => c.id === args[0]);
if (!channelx)
return message.channel.send(
`:x: Please specify the channel where server restarts will go!`
);
message.reply(`All server restart logs will now go to ${channelx}.`)
},
};
File 2
const Discord = require("discord.js");
const axios = require("axios");
let config = require("../config.json");
let setr = require("./setrestart"); // This is importing file 1
module.exports = {
name: "restart",
description: "send a restart message in status channel",
async execute(message, args) {
const perm = new Discord.MessageEmbed()
.setDescription(":x: You do not have permission to use this command.")
.setColor("#E74C3C");
if (!message.guild.me.hasPermission("ADMINISTRATOR"))
return message.channel.send(perm);
if (message.author.id !== "ID")
return message.channel.send(perm);
const restart = new Discord.MessageEmbed()
.setTitle(" Server Restarted! ")
.setDescription(`F8 connect to ${config.SERVER_URL} `)
.setColor("RANDOM")
.setTimestamp()
.setFooter(`${config.SERVER_LOGO}`);
setr.channelx.send(restart) // This does not work.
},
};
Help is much appreciated.
Edit: I left out the most crucial thing about what I am trying to import.
I am trying to import channelx which is in File 1 and I am trying to use the variable in File 2.
Output
User: /setrestart #channel
Bot: All server restart logs will now go to ${channelx}.
User: /restart
Bot: Embed sent in channelx
The variable channelx is accessible only in the function scope of execute(), you can't import it. Basically after the function goes out of scope the variable is lost. Use a global object, note that the object is destroyed when the program exits. So if you are trying to make some kind of bot's configuration, you want to save the object to a file.
Here is an example of how to properly implement what you are trying to do.
File 1 (file1.js):
// ... Load storage from a JSON file ...
const storage = {};
module.exports = {
name: "setrestart",
description: "sets the restart channel",
async execute(message, args) {
// ... Permission checking ...
const channelx = message.mentions.channels.first() ||
message.guild.channels.cache.find((c) => c.id === args[0]);
if (!channelx) {
return message.channel.send(
`:x: Please specify the channel where server restarts will go!`
);
}
// Store restart channel id per guild
storage[message.guild.id] = channelx.id;
message.reply(`All server restart logs will now go to ${channelx}.`);
// ... Write to the storage JSON file and update it with new data ...
},
};
module.exports.storage = storage;
File 2 (file2.js):
const Discord = require("discord.js");
const file1 = require("./file1.js");
module.exports = {
name: "restart",
description: "send a restart message in status channel",
async execute(message, args) {
// ... Permission checking ...
const restart = new Discord.MessageEmbed()
.setTitle(" Server Restarted! ")
.setColor("RANDOM")
.setTimestamp();
const channelId = file1.storage[message.guild.id];
// If there is no restart channel set, default to the system channel
if (!channelId) channelId = message.guild.systemChannelID;
const channel = await message.client.channels.fetch(channelId);
channel.send(restart);
},
};
Note that I have remove some parts of your code, to make it work on my machine.
Using discord.js ^12.5.3.
I am pretty sure you can't use the module.exports in that way. You should just add the channelx to the exports instead.
using this.channelx = channelx.
This is not how importing and exporting works. Your channelx variable is defined within the execution of a function, and you are not returning it.
I am not sure how the whole Discord API works and what are the shapes that get returned, but you should be able to do something like this:
File 1
module.exports = {
name: "setrestart",
description: "sets the restart channel",
async execute(message, args) {
// ... everything as per your file
message.reply(`All server restart logs will now go to ${channelx}.`);
return channelx;
},
};
File 2
module.exports = {
name: "restart",
description: "send a restart message in status channel",
async execute(message, args) {
// ... everything the same as per your file
const channelx = await setr.execute(message, args);
channelx.send(restart);
},
};
Basically, what is happening here is that the first module exposes a function that figures out your target channel and then returns it.
Once you return it, you can do whatever you want with that.
Please be aware that your first function might not need to be async as you don't have any await instruction.
Read more about scope: https://developer.mozilla.org/en-US/docs/Glossary/Scope

How to push data into subcollections in firebase

I'm creating a messaging app with react-native & firebase. Its working quite alright.
Now i want to take it a step further by creating private chats. To my understanding, i need to populate the data into subcollections. e.g : chats>chatroom1>data, chats>chatroom2>data e.t.c
I'm currently working with this code
import firebase from 'firebase';
class Fire {
constructor (props) {
this.init()
this.checkAuth()
}
init = () => {
if (!firebase.apps.length) {
}
};
checkAuth = () => {
firebase.auth().onAuthStateChanged(user => {
if (!user) {
firebase.auth().signInAnonymously();
}
})
}
send = messages => {
messages.forEach(item => {
const message = {
text: item.text,
timestamp: firebase.database.ServerValue.TIMESTAMP,
user: item.name
}
this.db.push(message)
})
}
parse = message => {
const {user, text, timestamp} = message.val();
const {key, _id} = message
const createdAt = new Date(timestamp)
return {
_id,
createdAt,
text,
user
}
}
get = callback => {
this.db.on('child_added', snapshot => callback(this.parse(snapshot)))
}
off() {
this.db.off()
}
get db() {
return firebase.database().ref("messages");
}
get uid(){
return(firebase.auth().currentUser || {}).uid
}
}
How can I populate the subcollections from this code?
I believe for calling out of specific subcollections, firebase.database().ref("messages/chatroomid"); will do the trick, right?
what i mean by sub collection is this
Currently my JSON tree looks like:
database
- messages
- mvhhsjsfurhcb
- text: "hi"
timestamp: 9942313949
user: "David"
firebase.database().ref("messages"); calls out the data under messages
This is what i want
database
- messages
-chatroom1
- mvhhsjsfurhcb
- text: "hi"
timestamp: 9942313949
user: "David"
-chatroom2
- mvhhsjsfurhcb
- text: "hey, this i room2"
timestamp: 9942313949
user: "Sam"
Then for firebase.database().ref("messages/chatroom1"); to call out only messages in chatroom1.
What I intend to achieve with this is to create a private chat for users
To give you more insight, if I was to do this with PHP, I would be doing SELECT * WHERE chatroom = :chatroom;
i believe the answer will be related to this.db.push(message). maybe adding another '.' indicating that there's another branch before pushing the message
If you want to push the chat message to a specific chat room, you can do:
this.db.child("chatroomid1").push(message)

I'm trying to create a channel named like user args. [DISCORD.JS V12]

It just gives me an error that the function message.guild.channels.create does not work because it's not a correct name.
My intention is to create a command where you will be asked how the channel you want to create be named. So it's ask you this. After this you send the wanted name for the channel. Now from this the bot should name the channel.
(sorry for bad english and low coding skills, im a beginner)
module.exports = {
name: "setreport",
description: "a command to setup to send reports or bugs into a specific channel.",
execute(message, args) {
const Discord = require('discord.js')
const cantCreate = new Discord.MessageEmbed()
.setColor('#f07a76')
.setDescription(`Can't create channel.`)
const hasPerm = message.member.hasPermission("ADMINISTRATOR");
const permFail = new Discord.MessageEmbed()
.setColor('#f07a76')
.setDescription(`${message.author}, you don't have the permission to execute this command. Ask an Admin.`)
if (!hasPerm) {
message.channel.send(permFail);
}
else if (hasPerm) {
const askName = new Discord.MessageEmbed()
.setColor(' #4f6abf')
.setDescription(`How should the channel be called?`)
message.channel.send(askName);
const collector = new Discord.MessageCollector(message.channel, m => m.author.id === message.author.id, { max: 1, time: 10000 });
console.log(collector)
var array = message.content.split(' ');
array.shift();
let channelName = array.join(' ');
collector.on('collect', message => {
const created = new Discord.MessageEmbed()
.setColor('#16b47e')
.setDescription(`Channel has been created.`)
message.guild.channels.create(channelName, {
type: "text",
permissionOverwrites: [
{
id: message.guild.roles.everyone,
allow: ['VIEW_CHANNEL','READ_MESSAGE_HISTORY'],
deny: ['SEND_MESSAGES']
}
],
})
.catch(message.channel.send(cantCreate))
})
}
else {
message.channel.send(created)
}
}
}
The message object currently refers to the original message posted by the user. You're not declaring it otherwise, especially seeing as you're not waiting for a message to be collected before defining a new definition / variable for your new channel's name.
NOTE: In the following code I will be using awaitMessages() (Message Collector but promise dependent), as I see it more fitting for this case (Seeing as you're more than likely not hoping for it to be asynchronous) and could clean up the code a little bit.
const filter = m => m.author.id === message.author.id
let name // This variable will later be used to define our channel's name using the user's input.
// Starting our collector below:
try {
const collected = await message.channel.awaitMessages(filter, {
max: 1,
time: 30000,
errors: ['time']
})
name = collected.first().content /* Getting the collected message and declaring it as the variable 'name' */
} catch (err) { console.error(err) }
await message.guild.channels.create(name, { ... })

Module exports async function undefined can't await

So, as far as I google it, I understood that this problem relevant to async / promise coding. I waste over 2Hr plus with this, but still receive no result. Probably because I'm bad in it. So my identifier.js code is right and works fine, it returns the exact data I want. app.js is still good too. So where is the problem? I can't export result value from identifier.js, because if I do it, I receive 'undefined':
const identifier = require("./db/ops/identifier");
trade_log.create({
Flag: req.body.Flag,
Instrument: req.body.Instrument,
Venue: req.body.Venue,
Price: req.body.Price,
Currency: req.body.Currency,
Quantity: req.body.Quantity,
Counterparty: req.body.Counterparty,
Identifier: identifier(req.body.Counterparty),
Commentary: req.body.Commentary,
but if I export it correcty (according to other guides), just like
let x = identifier(req.body.Counterparty).then(return value);
I receive an error at writing trade_log.create phase.
What is identifier.js? This module is a function that should request data from input form (req.body) via get and receive responce, return data & then in app.js it should be written in to MongoDB (writing works fine, already tested it)
app.js
const trade_log = require("./db/models/trade_log");
const identifier = require("./db/ops/identifier");
app.all('/log', function (req, res, next) {
let x = identifier(req.body.Counterparty.then();
trade_log.create({
Flag: req.body.Flag,
Instrument: req.body.Instrument,
Venue: req.body.Venue,
Price: req.body.Price,
Currency: req.body.Currency,
Quantity: req.body.Quantity,
Counterparty: req.body.Counterparty,
Identifier: x,
Commentary: req.body.Commentary,
},function (err, res) {
if (err) return console.log (req.body) + handleError(err);
console.log(res);
});
next();
});
identifier.js:
const identifier = (name) => {
request(['options, name'], { 'whatever' })
.then(response => {
/code that works fine
let charset = result;
return (charset);
module.exports = identifier;
I already tried in Identifier.js this export methods:
function name(param) {
//code here
}
module.exports = name();
and this:
module.exports = {
function: (name) => {
//code here
}
I also find relevant this SW answer: Asynchronous nodejs module exports but I still can't understand what am I doing wrong.
How should I correct my code accrding to new ES6 standard or should I use another module.exports method?

Categories

Resources