Sending Reactions on Bot messages in discord.js - discord.js

I am trying to create a wyr so the user can pick an emoji. I have used variations of the code below and I'm am unable to get the message to send to the message the bot sends.
I did try the return (); but maybe I did it wrong because it did not work. Here is the code I am currently using.
module.exports = {
name: "wyr",
description: "Would You Rather?",
execute(message) {
message.channel.send(dowyr());
function dowyr() {
var theWyr = ["Would you rather...\n\:a: Have the ability to go to the future?\n\:b: Have the ability to go to the past?"];
return wry = theWyr[Math.floor(Math.random() * theWyr.length)];
message.react("🅰️");
message.react("🅱️");
}
},
};

message is the message the user sent, so you need to point the .react() method to the message the bot sent, you can use .then() for that.
So your code would be:
module.exports = {
name: "wyr",
description: "Would You Rather?",
execute(message) {
message.channel.send(dowyr()).then((msg) => {
msg.react("🅰️");
msg.react("🅱️");
});
function dowyr() {
var theWyr = ["Would you rather...\n\:a: Have the ability to go to the future?\n\:b: Have the ability to go to the past?"];
return wry = theWyr[Math.floor(Math.random() * theWyr.length)];
}
},
};

Related

How to send a message based on event Google PubSub?

I need some help with PubSub...
I need to send a message to a topic every time someone accept cookies in my website. This message should contain the encodedURL that contains the services accepted.
I have this script:
const topicName = "myTopic";
const data = JSON.stringify({
encodeConsentURL:""
});
// Imports the Google Cloud client library
const { PubSub } = require("#google-cloud/pubsub");
// Creates a client; cache this for further use
const pubSubClient = new PubSub();
async function publishMessageWithCustomAttributes() {
// Publishes the message as a string, e.g. "Hello, world!" or JSON.stringify(someObject)
const dataBuffer = Buffer.from(data);
// Add two custom attributes, origin and username, to the message
const customAttributes = {};
const messageId = await pubSubClient
.topic(topicName)
.publish(dataBuffer, customAttributes);
console.log(`Message ${messageId} published.`);
console.log(customAttributes);
}
publishMessageWithCustomAttributes().catch(console.error);
This code works, it sends the message, what I'm finding very hard to do is how to set everything right for running this code in my cookie script. In my cookie script I have a function that writes the cookie, in the same function I would like to send the message, is this possible? Thanks in advance!
It is a bit late, but I don't get it, if you already have a working cookie script and a working publish script, isn't it just about putting them together?
If you still need help I'll be happy to help you
Something like
const runEverything = async () => {
try {
await checkCookiesThing()
await publishMessage()
} catch (e) {
console.error(e)
}
}

Discord.js - Why is the messageReactionAdd event completely blocked?

I've been trying to create a Discord bot. A lot of interactions are done through reactions, and I've been aware of the fact that only cached messages triggered the messageReactionAdd event. So I picked the following piece of code that is supposed to emit the packets corresponding to reactions added to "old" (not cached) messages. But it seems to completely block any packets concerning reactions adding because now none is emitted. Is there something that I've been doing wrong ?
Thanks.
My "raw.js" file :
module.exports = {
run: (client, packet) => {
// We don't want this to run on unrelated packets
if (!['MESSAGE_REACTION_ADD', 'MESSAGE_REACTION_REMOVE'].includes(packet.t)) return;
// Grab the channel to check the message from
const channel = client.guilds.cache.get(packet.d.guild_id).channels.cache.get(packet.d.channel_id);
const messageID = packet.d.message_id;
// There's no need to emit if the message is cached, because the event will fire anyway for that
if (channel.messages.has(messageID)) return;
// Since we have confirmed the message is not cached, let's fetch it
channel.messages.fetch(messageID).then(message => {
// Emojis can have identifiers of name:id format, so we have to account for that case as well
const emoji = packet.d.emoji.id ? `${packet.d.emoji.name}:${packet.d.emoji.id}` : packet.d.emoji.name;
// This gives us the reaction we need to emit the event properly, in top of the message object
const reaction = message.reactions.get(emoji);
// Adds the currently reacting user to the reaction's users collection.
if (reaction) reaction.users.set(packet.d.user_id, client.users.get(packet.d.user_id));
// Check which type of event it is before emitting
if (packet.t === 'MESSAGE_REACTION_ADD') {
client.emit('messageReactionAdd', reaction, client.users.get(packet.d.user_id));
}
if (packet.t === 'MESSAGE_REACTION_REMOVE') {
client.emit('messageReactionRemove', reaction, client.users.get(packet.d.user_id));
}
});
}
};
My "event fetcher" :
const fs = require('fs')
fs.readdir('./events/', (err, files) => {
if (err) return console.error(err);
files.forEach((file) => {
const eventFunction = require(`./events/${file}`);
if (eventFunction.disabled) return;
const event = eventFunction.event || file.split('.')[0];
const emitter = (typeof eventFunction.emitter === 'string' ? client[eventFunction.emitter] : eventFunction.emitter) || client;
const { once } = eventFunction;
try {
emitter[once ? 'once' : 'on'](event, (...args) => eventFunction.run(client, ...args));
} catch (error) {
console.error(error.stack);
}
});
});
From the discord.js discord server's #faq channel:
Bug:
• 'messageReactionAdd' does not fire despite proper partials enabled
PR: https://github.com/discordjs/discord.js/pull/4969 (merged, waiting for release)
Temporary fix is to ensure the addition of GUILD_MEMBER partial in the client definition
new Discord.Client({
partials: ['USER', 'GUILD_MEMBER', 'CHANNEL', 'MESSAGE', 'REACTION'],
});

Permission Error Handler - Bot Crashes how to use try catch properly

I want it so my bot can only send embeds in specific channels with the permissions granted but if a user sends the message in a channel where the permissions are not granted the bot stops working and cuts off. I am trying to make it so a try catch works so even if an error is thrown it continues to work, the error I am getting is "UnhandledPromiseRejectionWarning: DiscordAPIError: Missing Permissions - I want to be able to ignore this error.
function catchErr (err, emessage, a){
console.log("Someone tried to use the embed in the");}
let args = message.content.slice(PREFIX.length).split(' ');
switch(args[0]){
case 'discordbot ':
try {
const discordbot = new Discord.MessageEmbed()
.setTitle('My Discord Bot*')
.addFields(
{ name: 'Test Bot:', value: 'Test' },
message.channel.send(discordbot );
} catch (err) {
catchErr(err, message);
}
.send returns a Promise, if you want to catch errors you can either go for Promise.catch or use async / await (this requires your top level function to be async)
// Using Promise.catch
const catchErr = err => {
console.log(err)
}
message.channel.send(embed).catch(catchErr)
// Using async / await
try {
await message.channel.send(embed)
} catch(err) {
catchErr(err)
}
function sendMessage(message,content){
const permissions = message.channel.permissionsFor(message.client.user);
if (permissions.has("SEND_MESSAGES")){
if(content){
message.channel.send(content);
}
}
else{
console.log("[ERR] no msg perms")
message.author.send("I can't send messages on this channel or guild!, Try another channel or contact the server staff to check bot's permissions.");
}
}

How to do restart function with client.destroy and client.login when you already have a listener?

I've done a shutdown command, but now I want to create a restart command that destroy's my client, then reconnects to the websocket. I'm just having a bit of trouble with it since I have command/event handlers set up with a ready listener.
I typed the code out, and started getting errors for the specific command. Or, i'd get the bot up and it would crash upon trying to use the command.
const { prefix } = require("../../botconfig.json");
module.exports = {
config: {
name: "restart",
description: "restarts the bot",
usage: "wrestart",
category: "moderation",
accessableby: "Bot Owner",
aliases: ["rs"]
},
run: async (bot, message, args) => {
if(message.author.id != "id") return message.channel.send("You're not bot the owner!")
try {
//I want to do the destroy/login command here...
//client.destroy()
//client.login('token') <--- and do I really have to define the token if I already have it in my botconfig?
} catch(e) {
message.channel.send(`ERROR: ${e.message}`)
}
}
}
I want to issue a command "wrestart" and it restart my application. Results so far are basically typing the code and getting it incorrect...so starting from scratch basically.
Use:
const token = bot.token; // Copies the token into the Variable
bot.destroy(); // Stops the Bot
bot.login(token); // Uses the token we saved before to reauth
I was able to figure it out with this...
run: async (client, message, args) => {
if(message.author.id != "299957385215344640") return message.channel.send("You're not bot the owner! https://i.imgur.com/8ep8YbI.gif")
try {
message.channel.send("<a:Loading:575715719103381506> Attempting a restart...").then(msg => {
//msg.react('🆗');
setTimeout(function(){
msg.edit("<:CheckMark:550460857625346066> I should be back up now!");
}, 10000);
})
.then(client.destroy())
.then(client.login('tokengoeshere'))
} catch(e) {
message.channel.send(`ERROR: ${e.message}`)
}
}
This is what I use for my bot, a simple one line of code.
client.destroy().then(client.login(process.env.BOT_TOKEN))

How to reply with questions - Alexa

I am trying to build an alexa custom skill. I am facing an issue where I am trying to get a responses from the user for a question which the skill asks the user.
User : Tell me marks of student1 ?
Alexa: Subject
User: Maths
Alexa : student1 marks in maths is {xyz}
or if user doesnt give any input:
User : Tell me marks of student1 ?
Alexa: Subject
User: No Answer
Alexa : Gives marks of all subject for student1.
I am using Node.js.
Please tell me how to do this.
It's your lucky day. This is how I would do this with multiple MODES in Node.js.
Disclaimer: I am providing this lengthy response because I am desperate for reputation points and would like to become
a developer evangelist. ;)
Given the Node.js SDK and it's many features this is the format I would use.
// To zip and upload to lambda
// cd Desktop/StudentSkill
// sudo rm -r foo.zip
// zip -r foo.zip .s
'use strict';
var Alexa = require("alexa-sdk");
var appId = 'YOUR-AMAZON-ALEXA-SKILL-ID';
exports.handler = function(event, context, callback) {
var alexa = Alexa.handler(event, context);
alexa.appId = appId;
alexa.registerHandlers(newSessionHandlers, studentSkillSessionHandlers, specificClassSessionHandlers, functionHandlers);
alexa.execute();
};
var states = {
STUDENTMODE: '_STUDENTMODE',
CLASSMODE: '_CLASSMODE',
};
//Variables
var myStudents = {'josh':{'math':'A Plus','english':'A Plus','gym':'C'},'sam':{'math':'A Plus','english':'A minus','gym':'B Plus'}}; //add more classes.
//Could add an intent to create new students.
//var newStudent = {name:{'math':null,'english':null,'gym':null}};
//Could also add an intent to set grades
var newSessionHandlers = {
'NewSession': function() {
this.handler.state = states.STUDENTMODE;
var message = `Welcome to the School Skill, You may add students, edit grades, and review grades. For a list of uses say information. `; //this skill only contains reviewing grades.
var reprompt = ` try saying, grades for josh. `;
this.emit(':ask',message,reprompt);
},
'Unhandled': function() {
console.log("UNHANDLED");
this.emit('NewSession');
}
};
/////////////////////////////////
var studentSkillSessionHandlers = Alexa.CreateStateHandler(states.STUDENTMODE, {//Your location
'NewSession': function () {
this.emit('NewSession'); // Uses the handler in newSessionHandlers
},
//Primary Intents
'GetGradeIntent': function () { // Sampe Utterance: Tell me the marks of {student} or Grades for {student}
this.handler.state = states.CLASSMODE; //Change mode to accept a class, the intent handler getClassIntent is only available in CLASSMODE
this.attributes['CURRENTSTUDENT'] = this.event.request.intent.slots.student.value;
var message = ` which of `+this.attributes['CURRENTSTUDENT']+`'s classes would you like the grade for, name a class or say all. `;
var reprompt = message;
this.emit(':ask',message,reprompt);
},
//Help Intents
"InformationIntent": function() {
console.log("INFORMATION");
var message = ` Try saying, Tell me the marks of josh. `;
this.emit(':ask', message, message);
},
"AMAZON.StopIntent": function() {
console.log("STOPINTENT");
this.emit(':tell', "Goodbye!");
},
"AMAZON.CancelIntent": function() {
console.log("CANCELINTENT");
this.emit(':tell', "Goodbye!");
},
'AMAZON.HelpIntent': function() {
var message = helpMessage;
this.emit(':ask', message, message);
},
//Unhandled
'Unhandled': function() {
console.log("UNHANDLED");
var reprompt = ` That was not an appropriate response. which student would you like grades for. Say, grades for josh. `;
this.emit(':ask', reprompt, reprompt);
}
});
////////////////////////////
/////////////////////////////////
var specificClassSessionHandlers = Alexa.CreateStateHandler(states.CLASSMODE, {//Your location
'NewSession': function () {
this.emit('NewSession'); // Uses the handler in newSessionHandlers
},
//Primary Intents
'GetClassIntent': function () { // {className} class. ex: gym class, math class, english class. It helps to have a word that's not a slot. but amazon may pick it up correctly if you just say {className}
this.attributes['CLASSNAME'] = this.event.request.intent.slots.className.value;
var message = ``;
var reprompt = ``;
if(this.attributes['CLASSNAME'] != undefined){
message = ` I didn't get that class name. would you please repeat it. `;
reprompt = message;
}else{
grade = myStudents[this.attributes['CURRENTSTUDENT']][this.attributes['CLASSNAME']];
if(grade != undefined){
this.handler.state = states.STUDENTMODE; //Answer was present. return to student mode.
message = this.attributes['CURRENTSTUDENT']+`'s `+[this.attributes['CLASSNAME']+` grade is `+aAn(grade)+` `+grade+`. What else would you like to know?`; //Josh's math grade is an A plus.
reprompt = `what else would you like to know?`;
}else{
message = this.attributes['CURRENTSTUDENT']+` does not appear to have a grade for `+[this.attributes['CLASSNAME']+` please try again with a different class or say back.`;
reprompt = `please try again with a different class or say back.`;
}
}
var message = this.attributes['FROM'] + ' .. '+ ProFirstCity;
var reprompt = ProFirstReprompt;
this.emit(':ask',message,reprompt);
},
"AllIntent": function() {// Utterance: All, All Classes
message = ``;
//Not going to code.
//Pseudo code
// for each in json object myStudents[this.attributes['CURRENTSTUDENT']] append to message class name and grade.
this.emit(':ask', message, message);
},
"BackIntent": function() {// Utterance: Back, go back
var message = ` Who's grade would you like to know. try saying, grades for josh. `;
this.emit(':ask', message, message);
},
//Help Intents
"InformationIntent": function() {
console.log("INFORMATION");
var message = ` You've been asked for which of `+this.attributes['CURRENTSTUDENT']+`'s classes you'd his grade. Please name a class or say back. `;
this.emit(':ask', message, 'Name a class or say back.');
},
"AMAZON.StopIntent": function() {
console.log("STOPINTENT");
this.emit(':tell', "Goodbye!");
},
"AMAZON.CancelIntent": function() {
console.log("CANCELINTENT");
this.emit(':tell', "Goodbye!");
},
'AMAZON.HelpIntent': function() {
var message = helpMessage;
this.emit(':ask', message, message);
},
//Unhandled
'Unhandled': function() {
console.log("UNHANDLED");
var reprompt = ' That was not an appropriate response. Name a class or say back.';
this.emit(':ask', reprompt, reprompt);
}
});
////////////////////////////////////////////////////////////
var functionHandlers = {//NOT USED IN THIS APP //Note tied to a specific mode.
};
//#############################HELPERS VVVV#########################
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function clone(a) {
return JSON.parse(JSON.stringify(a));
}
function responseRandomizer(responseType){
let len = responseType.length;
let index = getRandomInt(0,len-1);
return responseType[index];
}
var vowels = {}
function aAn(word){
if(word != ''){
let first = word[0];
if(/[aAeEiIoOuU]/.test(first)){
return 'an';
}else{
return 'a';
}
}else{
return '';
}
}
Please note: this code was adapted from a live skill but has not been tested on it's own.
To start off requesting a follow up question you need to understand the different stateHandlers. When you invoke a new skill it goes to the newSessionHandlers from there you can run some sort of setup code and then change the MODE to a lobby to capture the main intents for the skill. I've named this lobby STUDENTMODE. Inside STUDENTMODE you can ask for the grades of a student and you could theoretically create a new student or add a class or what not. If you use the existing intent GetGradeIntent and supply it an apropriate name it will save the name of the student in the session state and change the mode to CLASSMODE which only accepts the Intents ClassNameIntent and BackIntent. If you try to invoke some other intent you will be reprompted for the name of a class by the UnhandledIntent. Upon provideing an appropriate class or saying "all" you will be provided a response and the mode will be changed back to STUDENTMODE. this plops you back in the lobby where you can ask questions about other students. Voila!
This process of changing modes is much better than Multi Part Intent Schema's like "Tell me grades for {studentName} in {mathClass}". While this can certainly work one reason modes are better is that they allow you to properly handle errors if one of the input values is incorrect, like student name or class name. You can easily ask for a single piece of information instead of asking the user to restate the entire multi part intent. It also allows you to handle getting multiple pieces of information one small piece at a time with ample instructions as apposed to allowing Alexa to continue to ask reprompt questions until all the required slots are filled.
One items I didn't cover.
Where are you storing your students? I have them hard coded into the lambda function. You could connect to amazon's dynamodb and store your session states there so they are available on the next session. that's actually as simple as adding.
alexa.dynamoDBTableName = 'NAME-OF-YOUR-DynamoDB-TABLE'; //You literally dont need any other code it just does the saving and loading??!! WHAT?
to your function here.
exports.handler = function(event, context, callback) {
var alexa = Alexa.handler(event, context);
alexa.appId = appId;
alexa.dynamoDBTableName = 'NAME-OF-YOUR-DynamoDB-TABLE'; //You literally don't need any other code it just does the saving and loading??!! WHAT?
alexa.registerHandlers(newSessionHandlers, studentSkillSessionHandlers, specificClassSessionHandlers, functionHandlers);
alexa.execute();
};
You'll need to create a dynamoDB data table and an IAm permission to allow your lambda function to access it. Then, magically, Alexa will create a single row in your data table for each unique user. A single teacher could easily add the students in their class. However, if you're looking for each teacher in a school to access one master database this is likely not the correct approach. There are likely other tutorials on how to connect Alexa to a single data table across multiple users.
I believe the core concern of your question was answered by the
different MODES where you can block out unwanted intents. If you
found this response helpful I take payment in trident layers and
reputation. Thanks!
Well, it is complicated. There is couple of approaches here you can either follow a dialogue scheme
https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/dialog-interface-reference
Or you can use intents.
you will have Student intents and Subject Intent.
"intents": [
{
"intent": "Student",
"slots": [
{
"name": "Students",
"type": "LIST_OF_STUDENTS"
}
]
},
{
"intent": "Subject",
"slots": [
{
"name": "Subjects",
"type": "LIST_OF_SUBJECTS"
}
]
}
You will need a dynamo db table where you keep Student name, and in your skill scheme, you will have a list of students, and subjects.
I can not write the whole skill for you, it is way too complicated.
Just follow a tutorial then ask a specific question.
https://github.com/alexa/alexa-skills-kit-sdk-for-nodejs
MAKE ME A SKILL is not a question....
On thing to be aware of is that Alexa doesn't respond to "no answer". So you'll need to coach the user to respond with "all" or "none".

Resources