Alexa Request Interceptor - Cant kill the session - alexa

Is it possible to have a RequestInterceptor abort the Session based on some logic inside the RequestInterceptor?
I have a routine coded that verifies the validity of a User. If the validity check fails, I want to play a message to the USer and abort the session.
What I see happening is that the LaunchRequest still runs even though I try and kill the seesion in the RequestInterceptor
A simplified version is as follows
const Alexa = require('ask-sdk-core');
const requestInterceptor = {
var isUserOk = false;
if(!isUserOk){
process(handlerInput) {
return handlerInput.responseBuilder
.speak("You are inside the Request Interceptor")
.withShouldEndSession(true)
.getResponse();
}
}
}
const launchRequestHandler = {
canHandle(handlerInput) {
return (handlerInput.requestEnvelope.session.new &&
handlerInput.requestEnvelope.request.type === 'LaunchRequest');
},
handle(handlerInput) {
return handlerInput.responseBuilder
.speak("Hi, welcome to the test skill. What is your name?")
.reprompt("You did not respond. Please tell me your name")
.getResponse();
}
};
const skillBuilder = Alexa.SkillBuilders.custom();
exports.handler = skillBuilder
.addRequestHandlers(
launchRequestHandler,
)
.addRequestInterceptors(
requestInterceptor
)
.lambda();
Can anyone tell me if it is possible to have the logic in the RequestInterceptor kill off the Session and prevent the LaunchRequest handler from running?
Thanks
-bc

It doesn't work because interceptors do not return responses (note that the interceptor method is called process() and not handle()) In the interceptor, instead of trying to close the session, use the handlerInput to set a session attribute named e.g. validUser:
let attributes = handlerInput.attributesManager.getSessionAttributes();
attributes.validUser = isUserOk(); //call your user check function here
handlerInput.attributesManager.setSessionAttributes(attributes);
Now create a launchRequestBadUserHandler where in the canHandle() you require that session attribute to be false:
const attributes = handlerInput.attributesManager.getSessionAttributes();
const isUserOk = attributes.validUser;
canHandle(handlerInput) {
return (handlerInput.requestEnvelope.session.new &&
handlerInput.requestEnvelope.request.type === 'LaunchRequest' &&
!isUserOk);
In this handler handle() function send the response you originally planned for the interceptor. Don't forget to call this handler before your original launch request handler in addRequestHandlers()

Related

Alexa Custom Skill not triggering my custom intent

Here is a sample code of it
my Intent is this https://imgur.com/a/9nG3MVD
Does anyone have an idea as to why the Alexa Simulator Test doesn't trigger my custom intent?
const MyCustomHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& Alexa.getIntentName(handlerInput.requestEnvelope) === 'MyCustomIntent';
},
handle(handlerInput) {
let speakOutput = 'Place Call Intent';
return handlerInput.responseBuilder
.speak(speakOutput)
.getResponse();
}
};
/**
* This handler acts as the entry point for your skill, routing all request and response
* payloads to the handlers above. Make sure any new handlers or interceptors you've
* defined are included below. The order matters - they're processed top to bottom
* */
exports.handler = Alexa.SkillBuilders.custom()
.addRequestHandlers(
LaunchRequestHandler,
MyCustomHandler,
HelpIntentHandler,
CancelAndStopIntentHandler,
FallbackIntentHandler,
SessionEndedRequestHandler,
IntentReflectorHandler,
).addErrorHandlers(
ErrorHandler
).lambda();

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'],
});

How to run code with await in filter/collect code

I'm trying to make a confirmation portion of my command where if you activate the command, you need to say "yes" before the code activates. The reoccurring problem is that the code right after the message that says
Confirmed... Please wait.
After this, it completely skips over the code and does nothing. When I was writing the code in VSC, the async portion of the code wasn't highlighted with yellow, but more of a darker yellow.
I've tried removing this portion of the code
const async = async () => {
But the code with await cannot run unless it's connected to async.
I've tried changing how the async is ran.
async () => {
Still the same result.
Removing the beginning async code will also just result in the command breaking.
I've placed the big chunk of code outside of the then(collected code, but after a few seconds of waiting when the command activates, it immediately runs, then brings up a value error. But I want it so that code activates when the author says "Yes"
async run(message, args){
if (message.channel instanceof Discord.DMChannel) return message.channel.send('This command cannot be executed here.')
let replyMessage = message.reply('Please make sure that my integration role "Synthibutworse" is above the default role used for this server. Is this correct? [Reply with "YES"] if so. Will expire in 20 seconds...');
let filter = msg => msg.author.id == message.author.id && msg.content.toLowerCase() == 'yes';
message.channel.awaitMessages(filter, {max: 1, time: 20000}).then(collected => {
message.reply('Confirmed... Please wait.');
const async = async () => {
if(!message.member.guild.me.hasPermission(['MANAGE_WEBHOOKS'])) return message.channel.send('I don\'t have the permissions to make webhooks, please contact an admin or change my permissions!')
if(!message.member.guild.me.hasPermission(['MANAGE_ROLES'])) return message.channel.send('I don\'t have the permissions to make roles, please contact an admin or change my permissions!')
if (!message.member.hasPermission(['MANAGE_WEBHOOKS'])) return message.channel.send('You need to be an admin or webhook manager to use this command.')
if (!message.member.hasPermission(['MANAGE_ROLES'])) return message.channel.send('You need to be an admin or role manager to use this command.')
const avatar = `https://cdn.discordapp.com/attachments/515307677656678420/557050444954992673/Generic5.png`;
const name2 = "SYNTHIBUTWORSE-1.0WOCMD";
let woaID = message.mentions.channels.first();
if(!woaID) return message.channel.send("Channel is nonexistant or command was not formatted properly. Please do s!woa #(channelname)");
let specifiedchannel = message.guild.channels.find(t => t.id == woaID.id);;
const hook = await woaID.createWebhook(name2, avatar).catch(error => console.log(error))
await hook.edit(name2, avatar).catch(error => console.log(error))
message.channel.send("Please do not tamper with the webhook or else the command implied before will no longer function with this channel.")
var role = message.guild.createRole({
name: `Synthibutworse marker v1.0`,
color: 0xcc3b3b,}).catch(console.error);
specifiedchannel.send("Created role...");
if(message.guild.roles.name == "Synthibutworse marker v1.0") {
role.setMentionable(false, 'SBW Ping Set.')
role.setPosition(1)
role.setPermissions(['CREATE_INSTANT_INVITE', 'SEND_MESSAGES'])
.then(role => console.log(`Edited role`))
.catch(console.error)};
message.channel.send("Role set up...");
const sbwrID = message.guild.roles.find(`Synthibutworse marker v1.0`);
let specifiedrole = message.guild.roles.find(r => r.id == sbwrID.id)
message.channel.send('Created Role... Please wait.');
message.guild.specifiedchannel.replacePermissionOverwrites({
overwrites: [
{
id: specifiedrole,
denied: ['SEND_MESSAGES'],
allowed: ['VIEW_CHANNEL'],
},
],
reason: 'Needed to change permissions'
});
var bot = message.client
bot.on('message', function(message) { {
if(webhook.name == `Synthibutworse marker`) return
if(message.channel.id == webhook.channelID) return
{let bannedRole = message.guild.roles.find(role => role.id === specifiedrole);
message.member.addRole(bannedRole)};
}});
}});
}};
module.exports = woa;
I expect the command to run with the async and continue with the code when the message author says "yes", and doesn't stop at the Please wait. message.
What actually happens is the code doesn't run right after the Please wait message.
In your current code, you're declaring an async function but never calling it. That's why the code is never run and why VSC darkens its name.
Solution:
Define your awaitMessages(...)'s .then() callback as async:
.then(async collected => {
// do async stuff
});
For future reference, if you need to use async code somewhere that you can't define a function as async, use the following setup:
(async function() {
// do async stuff
})();

how to retrieve user first name in alexa

I am creating an alexa app and for that i have permission for the user's location and customer's firstname. My first question is if customer's first name is what is user's first name or it is something different. But if it is asking for the user's first name then to get that. For location info, we use ConsentToken, so is there any way to get the user name out of it?
I can ask for the user name and store it and then can greet the user. But i have to ask everytime user launches the app. I am using php.
First, the user has to link his account with your skill and accept the permission
(you need to set it in your skill configuration)
once the user is loged in, You will just be able to use a access/refresh token to get the user name from Alexa output
Check this, could be clearest: https://developer.amazon.com/fr/docs/custom-skills/request-customer-contact-information-for-use-in-your-skill.html
In addition to Neryuk's answer pointing correctly the documentation, I give some code sample in NodeJS.
Assuming you already gave all the permissions needed from Alexa Skill Developer Portal, you can ask for user information within your intent handler in this way:
const PERMISSIONS = ['alexa::profile:name:read', 'alexa::profile:email:read', 'alexa::profile:mobile_number:read'];
const MyIntentHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
// checks request type
return request.type === 'LaunchRequest'
|| (request.type === 'IntentRequest'
&& request.intent.name === 'MyIntent');
},
async handle(handlerInput) {
const { requestEnvelope, serviceClientFactory, responseBuilder } = handlerInput;
const requestAttributes = handlerInput.attributesManager.getRequestAttributes();
const consentToken = handlerInput.requestEnvelope.context.System.apiAccessToken;
if (!consentToken) {
return responseBuilder
.speak('Missing permissions')
.withAskForPermissionsConsentCard(PERMISSIONS)
.getResponse();
}
const client = serviceClientFactory.getUpsServiceClient();
const userName = await client.getProfileName();
const userEmail = await client.getProfileEmail();
const userMobileNumber = await client.getProfileMobileNumber();
console.log('Name successfully retrieved '+ userName);
console.log('Email successfully retrieved '+ userEmail);
console.log('PhoneNumber successfully retrieved '+ JSON.stringify(userMobileNumber));
const speakOutput = 'The username is '+userName;
return handlerInput.responseBuilder
.speak(speakOutput)
.withSimpleCard('MyFavSkill')
.getResponse();
},
};
Note that you must declare your handlerInput code as async because you are invoking an async request you must wait within your method.
Code is missing the "try-catch" block to simplify its reading, but you should manage unexpected errors.
Hope this may help.

Using refresh tokens within AngularJS SPA

What is the correct way to request a new JWT authentication token via refresh tokens within AngularJS?
I already have an implementation that, on every API request, checks whether the session needs refreshing and, if so, requests a new token from the webserver. But, if a page makes 3 calls at once it requests a new refresh token for each call which seems incorrect - I would think it should only update the token once.
Is there a way to block other calls or should I put the refresh on an interval and not do it via interceptors?
Interceptor request method
request = (config: angular.IRequestConfig) => {
this.setBearerToken(config);
var responsePromise = this.$q.when(config);
if (config.url !== this.tokenUrl) {
const factSession = this.$injector.get("factSession") as Session;
if (factSession.shouldRefreshToken()) {
responsePromise = factSession
.refreshSession()
.then(() => {
this.setBearerToken(config);
return config;
});
}
}
return responsePromise;
}
Just enhance your refreshSession method, so it wont refresh several times.
var refreshPromise;
refreshSession: () => {
if (!refreshPromise) {
refreshPromise = $http.get(...);
refreshPromise.finally(() => refreshPromise = null);
}
return refreshPromise;
}

Resources