I created a join to create system that creates a channel when a user join and delete it when they leave. However, it only deletes if the last person that's leaving is the user who created the room. Any ideas?
const { Collection } = require("discord.js");
const voiceCollection = new Collection();
module.exports = async (Discord, client, oldState, newState) => {
const user = await client.users.fetch(newState.id);
const member = newState.guild.member(user);
// JOIN
if (!voiceName || voiceName === "") {
if (!oldState.channel && newState.channelID === "898245212541976667") {
const channel = await newState.guild.channels.create(user.tag, {
type: "voice",
parent: newState.channel.parent,
});
member.voice.setChannel(channel);
voiceCollection.set(user.id, channel.id);
await channel.overwritePermissions([
{
id: user.id,
allow: ["MANAGE_CHANNELS", "CONNECT"],
},
{
id: member.guild.id,
deny: ["CONNECT"],
},
]);
} else if (!newState.channel) {
if (oldState.channelID === voiceCollection.get(newState.id)) {
if (oldState.channel.members.size < 1) {
return oldState.channel.delete();
}
}
}
var newchannel_id = config.Channel_id;
var category_id = config.category;
var userchannellist = []
client.login(token);
client.on('voiceStateUpdate', async (oldMember, newMember) => {
if (newMember.channel !== null && oldMember.channel === null && newMember.channel.id === newchannel_id || newMember.channel !== null && oldMember.channel !== null && newMember.channel.id === newchannel_id) {
var current_user = newMember.member.user;
console.log(current_user.username + 'creating the channel');
// Start the creation of the new channel
var server = newMember.guild;
let USERA = newMember.member.nickname || newMember.member.user.username;
var channel = {
type: 'voice', bitrate: 384000, parent: category_id, permissionOverwrites: [{
// permissions
id: server.id, allow: ['VIEW_CHANNEL'],
},
{
id: current_user.id, allow: ['MOVE_MEMBERS', 'MANAGE_CHANNELS']
}
]
};
server.channels.create('🔊' + USERA, channel).then(channel => {
newMember.setChannel(channel).catch(console.error)
userchannellist.push(channel)
//channel region
client.api.channels(channel.id).patch({ data: { rtc_region: "rotterdam" } })
}).catch(console.error);
}
// delete Chaneel
if (oldMember.channel) {
let filter = (ch) =>
(ch.parentID == category_id)
&& (ch.id !== newchannel_id)
&& (oldMember.channel == ch.id)
&& (oldMember.channel.members.size == 0);
return oldMember.guild.channels.cache
.filter(filter)
.forEach((ch) => ch.delete()
.catch(console.error));
}
});
Related
I'm still trying to place an order for the voice bot to enter. I want to make a music system using youtube-dl and I always get this error saying that it doesn't know what "Voice" means in the line "message.member.voiceChannel"
I'm already getting nervous about this problem, I tried to add permissions, but it doesn't work, I want to specify that it uses Discord.js#v12
below you have all the files that I use for the command, such as message event and command class.
Error Code:
2022-06-02 05:39:42 [info] [Command] "n!join" (join) ran by "GhostStru#1982" (780808189226123294) on guild "GhostStru🌿's server" (939865905708552242) channel "#cmmds" (980923745768181831)
TypeError: Cannot read properties of undefined (reading 'voice')
at module.exports.run (C:\Users\Ghost\Desktop\NucleusNEW\commands\music\join.js:23:36)
at module.exports.runCommand (C:\Users\Ghost\Desktop\NucleusNEW\events\message\message.js:417:23)
at module.exports.run (C:\Users\Ghost\Desktop\NucleusNEW\events\message\message.js:391:20)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
This is my Join command
const { joinVoiceChannel } = require('#discordjs/voice');
const { MessageEmbed, Util } = require('discord.js');
const discord = require("discord.js")
const Command = require('../../structures/Command');
module.exports = class extends Command {
constructor(...args) {
super(...args, {
name: 'join',
aliases: ['add'],
usage: "",
category: "Music",
examples: ["join"],
description: "Join into you'r voice channel.",
cooldown: 5,
})
}
async run(client, message, args) {
const voiceChannel = message.member.voice.channel;
if (!message.member.voiceChannel) return message.channel.send({embeds: [new MessageEmbed().setColor(client.color.error).setDescription(`You must be a voice channel before using this command.`)]});
if (message.guild.me.voiceChannel && message.member.voiceChannel.id !== message.guild.me.voiceChannel.id) return message.channel.send({embeds: [new MessageEmbed().setColor(client.color.error).setDescription(`You are not in same voice channel.`)]});
try {
joinVoiceChannel({
channelId: message.member.voiceChannel.id,
guildId: message.guild.id,
adapterCreator: message.guild.voiceAdapterCreator,
});
await message.react('👍').catch(() => { });
} catch {
return message.channel.send({embeds: [new MessageEmbed().setColor(client.color.error).setDescription(`An error occurred while joining the voice channel.`)]});
}
}
}
This is my message event
const Event = require('../../structures/Event');
const { Permissions, Collection } = require("discord.js");
const afk = require("../../models/afk");
const Statcord = require("statcord.js");
const moment = require('moment');
const discord = require("discord.js");
const config = require('./../../config.json');
const { MessageEmbed } = require('discord.js');
const logger = require('../../utils/logger');
const nsfwplease = require('../../assets/json/nfsw.json');
const mongoose = require('mongoose');
const Guild = require('../../database/schemas/Guild');
const User = require('../../database/schemas/User');
const Moderation = require('../../database/schemas/logging');
const Blacklist = require('../../database/schemas/blacklist');
const customCommand = require('../../database/schemas/customCommand');
const autoResponse = require('../../database/schemas/autoResponse');
const autoResponseCooldown = new Set();
const inviteFilter = require('../../filters/inviteFilter');
const linkFilter = require('../../filters/linkFilter');
const maintenanceCooldown = new Set();
const metrics = require('datadog-metrics');
const permissions = require('../../assets/json/permissions.json')
const Maintenance = require('../../database/schemas/maintenance')
require("moment-duration-format");
module.exports = class extends Event {
constructor(...args) {
super(...args);
this.impliedPermissions = new Permissions([
"VIEW_CHANNEL",
"SEND_MESSAGES",
"SEND_TTS_MESSAGES",
"EMBED_LINKS",
"ATTACH_FILES",
"READ_MESSAGE_HISTORY",
"MENTION_EVERYONE",
"USE_EXTERNAL_EMOJIS",
"ADD_REACTIONS"
]);
this.ratelimits = new Collection();
}
async run(message) {
try {
if (!message.guild) return;
if(config.datadogApiKey){
metrics.init({ apiKey: this.client.config.datadogApiKey, host: 'nucleus', prefix: 'nucleus.' });
}
const mentionRegex = RegExp(`^<#!?${this.client.user.id}>$`);
const mentionRegexPrefix = RegExp(`^<#!?${this.client.user.id}>`);
if (!message.guild || message.author.bot) return;
const settings = await Guild.findOne({
guildId: message.guild.id,
}, async (err, guild) => {
if (err) console.log(err)
if (!guild) {
const newGuild = await Guild.create({
guildId: message.guild.id,
prefix: config.prefix || 'p!',
language: "english"
});
}
});
//if (!settings) return message.channel.send('Oops, this server was not found in the database. Please try to run the command again now!');
if (message.content.match(mentionRegex)) {
const proofita = `\`\`\`css\n[ Prefix: ${settings.prefix || '!'} ]\`\`\``;
const proofitaa = `\`\`\`css\n[ Help: ${settings.prefix || '!'}help ]\`\`\``;
const embed = new MessageEmbed()
.setTitle('Hello, I\'m Nucleus. What\'s Up?')
.addField(`Prefix`,proofita, true)
.addField(`Usage`,proofitaa, true)
.setDescription(`\nIf you like Nucleus, Consider [voting](https://top.gg/bot/980373513691090974), or [inviting](https://discord.com/oauth2/authorize?client_id=980373513691090974&scope=bot&permissions=470150262) it to your server! Thank you for using Nucleus, we hope you enjoy it, as we always look forward to improve the bot`)
.setFooter('Thank you for using Nucleus!!')
.setColor('#FF2C98')
message.channel.send(embed);
}
if(config.datadogApiKey){
// Add increment after every darn message lmfao!
metrics.increment('messages_seen');
}
// Filters
if (settings && await inviteFilter(message)) return;
if (settings && await linkFilter(message)) return;
let mainPrefix = settings ? settings.prefix : '!';
const prefix = message.content.match(mentionRegexPrefix) ?
message.content.match(mentionRegexPrefix)[0] : mainPrefix
const guildDB = await Guild.findOne({
guildId: message.guild.id
});
const moderation = await Moderation.findOne({
guildId: message.guild.id
});
if(!moderation){
Moderation.create({
guildId: message.guild.id
})
}
// maintenance mode
const maintenance = await Maintenance.findOne({
maintenance: "maintenance"
})
const userBlacklistSettings = await Blacklist.findOne({ discordId: message.author.id,});
const guildBlacklistSettings = await Blacklist.findOne({ guildId: message.guild.id });
//autoResponse
const autoResponseSettings = await autoResponse.findOne({ guildId: message.guild.id, name: message.content.toLowerCase() });
if (autoResponseSettings && autoResponseSettings.name) {
if (userBlacklistSettings && userBlacklistSettings.isBlacklisted) return;
if(maintenance && maintenance.toggle == "true") return;
if(autoResponseCooldown.has(message.author.id)) return message.channel.send(`${message.client.emoji.fail} Slow Down - ${message.author}`)
message.channel.send(autoResponseSettings.content
.replace(/{user}/g, `${message.author}`)
.replace(/{user_tag}/g, `${message.author.tag}`)
.replace(/{user_name}/g, `${message.author.username}`)
.replace(/{user_ID}/g, `${message.author.id}`)
.replace(/{guild_name}/g, `${message.guild.name}`)
.replace(/{guild_ID}/g, `${message.guild.id}`)
.replace(/{memberCount}/g, `${message.guild.memberCount}`)
.replace(/{size}/g, `${message.guild.memberCount}`)
.replace(/{guild}/g, `${message.guild.name}`)
.replace(/{member_createdAtAgo}/g, `${moment(message.author.createdTimestamp).fromNow()}`)
.replace(/{member_createdAt}/g, `${moment(message.author.createdAt).format('MMMM Do YYYY, h:mm:ss a')}`))
autoResponseCooldown.add(message.author.id)
setTimeout(()=>{
autoResponseCooldown.delete(message.author.id)
}, 2000)
return;
}
//afk
let language = require(`../../data/language/english.json`)
if(guildDB) language = require(`../../data/language/${guildDB.language}.json`)
moment.suppressDeprecationWarnings = true;
if(message.mentions.members.first()){
if(maintenance && maintenance.toggle == "true") return;
const afklist = await afk.findOne({ userID: message.mentions.members.first().id, serverID: message.guild.id});
if(afklist){
await message.guild.members.fetch(afklist.userID).then(member => {
let user_tag = member.user.tag;
return message.channel.send(`**${afklist.oldNickname || user_tag || member.user.username}** ${language.afk6} ${afklist.reason} **- ${moment(afklist.time).fromNow()}**`).catch(() => {});
});
}
}
const afklis = await afk.findOne({ userID: message.author.id, serverID: message.guild.id});
if(afklis) {
if(maintenance && maintenance.toggle == "true") return;
let nickname = `${afklis.oldNickname}`;
message.member.setNickname(nickname).catch(() => {});
await afk.deleteOne({ userID: message.author.id });
return message.channel.send(new discord.MessageEmbed().setColor('GREEN').setDescription(`${language.afk7} ${afklis.reason}`)).then(m => {
setTimeout(() => {
m.delete().catch(() => {});
}, 10000);
});
};
if (!message.content.startsWith(prefix)) return;
// eslint-disable-next-line no-unused-vars
const [cmd, ...args] = message.content.slice(prefix.length).trim().split(/ +/g);
const command = this.client.commands.get(cmd.toLowerCase()) || this.client.commands.get(this.client.aliases.get(cmd.toLowerCase()));
// maintenance mode
if(!this.client.config.developers.includes(message.author.id)){
if(maintenance && maintenance.toggle == "true") {
if(maintenanceCooldown.has(message.author.id)) return;
message.channel.send(`Nucleus is currently undergoing maintenance which won't allow anyone to access Nucleus Commands. Feel free to try again later. For updates: https://discord.gg/FqdH4sfKBg`)
maintenanceCooldown.add(message.author.id);
setTimeout(() => {
maintenanceCooldown.delete(message.author.id)
}, 10000);
return;
}
}
// Custom Commands
const customCommandSettings = await customCommand.findOne({ guildId: message.guild.id, name: cmd.toLowerCase() });
const customCommandEmbed = await customCommand.findOne({ guildId: message.guild.id, name: cmd.toLowerCase() });
if (customCommandSettings && customCommandSettings.name && customCommandSettings.description) {
if (userBlacklistSettings && userBlacklistSettings.isBlacklisted) return;
let embed = new MessageEmbed()
.setTitle(customCommandEmbed.title)
.setDescription(customCommandEmbed.description)
.setFooter(``)
if( customCommandEmbed.image !== "none") embed.setImage(customCommandEmbed.image)
if( customCommandEmbed.thumbnail !== "none") embed.setThumbnail(customCommandEmbed.thumbnail)
if( customCommandEmbed.footer !== "none") embed.setFooter(customCommandEmbed.footer)
if( customCommandEmbed.timestamp !== "no") embed.setTimestamp()
if( customCommandEmbed.color == 'default') {
embed.setColor(message.guild.me.displayHexColor)
} else embed.setColor(`${customCommandEmbed.color}`)
return message.channel.send(embed)
}
if (customCommandSettings && customCommandSettings.name && !customCommandSettings.description && customCommandSettings.json == "false") {
if (userBlacklistSettings && userBlacklistSettings.isBlacklisted) return;
return message.channel.send(customCommandSettings.content
.replace(/{user}/g, `${message.author}`)
.replace(/{user_tag}/g, `${message.author.tag}`)
.replace(/{user_name}/g, `${message.author.username}`)
.replace(/{user_ID}/g, `${message.author.id}`)
.replace(/{guild_name}/g, `${message.guild.name}`)
.replace(/{guild_ID}/g, `${message.guild.id}`)
.replace(/{memberCount}/g, `${message.guild.memberCount}`)
.replace(/{size}/g, `${message.guild.memberCount}`)
.replace(/{guild}/g, `${message.guild.name}`)
.replace(/{member_createdAtAgo}/g, `${moment(message.author.createdTimestamp).fromNow()}`)
.replace(/{member_createdAt}/g, `${moment(message.author.createdAt).format('MMMM Do YYYY, h:mm:ss a')}`)
)
}
if (customCommandSettings && customCommandSettings.name && !customCommandSettings.description && customCommandSettings.json == "true") {
if (userBlacklistSettings && userBlacklistSettings.isBlacklisted) return;
const command = JSON.parse(customCommandSettings.content)
return message.channel.send(command).catch((e)=>{message.channel.send(`There was a problem sending your embed, which is probably a JSON error.\nRead more here --> https://nucleus.xyz/embeds\n\n__Error:__\n\`${e}\``)})
}
if (command) {
await User.findOne({
discordId: message.author.id
}, (err, user) => {
if (err) console.log(err)
if (!user) {
const newUser = new User({
discordId: message.author.id
})
newUser.save()
}
});
const disabledCommands = guildDB.disabledCommands;
if (typeof(disabledCommands) === 'string') disabledCommands = disabledCommands.split(' ');
const rateLimit = this.ratelimit(message, cmd);
if (!message.channel.permissionsFor(message.guild.me).has('SEND_MESSAGES')) return;
// Check if user is Blacklisted
if (userBlacklistSettings && userBlacklistSettings.isBlacklisted) {
logger.warn(`${message.author.tag} tried to use "${cmd}" command but the user is blacklisted`, { label: 'Commands' })
return message.channel.send(`${message.client.emoji.fail} You are blacklisted from the bot :(`);
}
// Check if server is Blacklisted
if (guildBlacklistSettings && guildBlacklistSettings.isBlacklisted) {
logger.warn(`${message.author.tag} tried to use "${cmd}" command but the guild is blacklisted`, { label: 'Commands' })
return message.channel.send(`${message.client.emoji.fail} This guild is Blacklisted :(`);
}
let number = Math.floor((Math.random() * 10) + 1);
if (typeof rateLimit === "string") return message.channel.send(` ${message.client.emoji.fail} Please wait **${rateLimit}** before running the **${cmd}** command again - ${message.author}\n\n${number === 1 ? "*Did You know that Nucleus has its own dashboard? `https://nucleus.xyz/dashboard`*" : ""}${number === 2 ? "*You can check our top.gg page at `https://vote.nucleus.xyz`*" : ""}`).then((s)=>{
message.delete().catch(()=>{});
s.delete({timeout: 4000}).catch(()=>{})
}).catch(()=>{})
if (command.botPermission) {
const missingPermissions =
message.channel.permissionsFor(message.guild.me).missing(command.botPermission).map(p => permissions[p]);
if (missingPermissions.length !== 0) {
const embed = new MessageEmbed()
.setAuthor(`${this.client.user.tag}`, message.client.user.displayAvatarURL({ dynamic: true }))
.setTitle(`<:wrong:822376943763980348> Missing Bot Permissions`)
.setDescription(`Command Name: **${command.name}**\nRequired Permission: **${missingPermissions.map(p => `${p}`).join(' - ')}**`)
.setTimestamp()
.setFooter('https://nucleus.xyz')
.setColor(message.guild.me.displayHexColor);
return message.channel.send(embed).catch(()=>{})
}
}
if (command.userPermission) {
const missingPermissions =
message.channel.permissionsFor(message.author).missing(command.userPermission).map(p => permissions[p]);
if (missingPermissions.length !== 0) {
const embed = new MessageEmbed()
.setAuthor(`${message.author.tag}`, message.author.displayAvatarURL({ dynamic: true }))
.setTitle(`<:wrong:822376943763980348> Missing User Permissions`)
.setDescription(`Command Name: **${command.name}**\nRequired Permission: **${missingPermissions.map(p => `${p}`).join('\n')}**`)
.setTimestamp()
.setFooter('https://nucleus.xyz')
.setColor(message.guild.me.displayHexColor);
return message.channel.send(embed).catch(()=>{})
}
}
if(disabledCommands.includes(command.name || command)) return;
if (command.ownerOnly) {
if (!this.client.config.developers.includes(message.author.id)) return
}
if(config.datadogApiKey){
metrics.increment('commands_served');
}
if (command.disabled) return message.channel.send(`The owner has disabled the following command for now. Try again Later!\n\nFor Updates: https://discord.gg/duBwdCvCwW`)
if (command.nsfwOnly && !message.channel.nsfw && message.guild) return message.channel.send(`${nsfwplease[Math.round(Math.random() * (nsfwplease.length - 1))]}`)
Statcord.ShardingClient.postCommand(cmd, message.author.id, this.client);
await this.runCommand(message, cmd, args)
.catch(error => {
if(config.datadogApiKey){
metrics.increment('command_error');
}
return this.client.emit("commandError", error, message, cmd);
})
}
} catch(error) {
if(config.datadogApiKey){
metrics.increment('command_error');
}
return this.client.emit("fatalError", error, message);
}
}
async runCommand(message, cmd, args) {
if (!message.channel.permissionsFor(message.guild.me) || !message.channel.permissionsFor(message.guild.me).has('EMBED_LINKS'))
return message.channel.send(`${message.client.emoji.fail} Missing bot Permissions - **Embeds Links**`)
const command = this.client.commands.get(cmd.toLowerCase()) || this.client.commands.get(this.client.aliases.get(cmd.toLowerCase()));
logger.info(`"${message.content}" (${command.name}) ran by "${message.author.tag}" (${message.author.id}) on guild "${message.guild.name}" (${message.guild.id}) channel "#${message.channel.name}" (${message.channel.id})`, { label: 'Command' })
await command.run(message, args)
}
ratelimit(message, cmd) {
try {
const command = this.client.commands.get(cmd.toLowerCase()) || this.client.commands.get(this.client.aliases.get(cmd.toLowerCase()));
if (message.author.permLevel > 4) return false;
const cooldown = command.cooldown * 1000
const ratelimits = this.ratelimits.get(message.author.id) || {}; // get the ENMAP first.
if (!ratelimits[command.name]) ratelimits[command.name] = Date.now() - cooldown; // see if the command has been run before if not, add the ratelimit
const difference = Date.now() - ratelimits[command.name]; // easier to see the difference
if (difference < cooldown) { // check the if the duration the command was run, is more than the cooldown
return moment.duration(cooldown - difference).format("D [days], H [hours], m [minutes], s [seconds]", 1); // returns a string to send to a channel
} else {
ratelimits[command.name] = Date.now(); // set the key to now, to mark the start of the cooldown
this.ratelimits.set(message.author.id, ratelimits); // set it
return true;
}
} catch(e) {
this.client.emit("fatalError", error, message);
}
}
}
And this is my Command class
module.exports = class Command {
constructor(client, name, options = {}) {
this.client = client;
this.name = options.name || name;
this.aliases = options.aliases || [];
this.description = options.description || "No description provided.";
this.category = options.category || "General";
this.usage = `${this.name} ${options.usage || ''}` || "No usage provided.";
this.examples = options.examples || [];
this.disabled = options.disabled || false;
this.cooldown = "cooldown" in options ? options.cooldown : 5 || 5;
this.ownerOnly = options.ownerOnly || false;
this.guildOnly = options.guildOnly || false;
this.nsfwOnly = options.nsfwOnly || false;
this.botPermission = options.botPermission || ['SEND_MESSAGES', 'EMBED_LINKS'];
this.userPermission = options.userPermission || null;
}
// eslint-disable-next-line no-unused-vars
async run(message, args) {
throw new Error(`The run method has not been implemented in ${this.name}`);
}
reload() {
return this.store.load(this.file.path);
}
}
In this "code cases" i put my personal codes, and i dont know where can i find the problem, or what can i modifiy in my code, thats all i can say..
Can someone tell me what can i do?...
Its a simple join command, and he cannot read voice.channel...
Everytime adding a new data or updating existing data, new_data and updated_data variables will get increment. But when I try to console log the total count's (new_data and updated_data) at the bottom of the code the result is 0. How do we address this in Node using async ?
Code
let new_data = 0
let updated_data = 0
let vehicles = _.each(results.data, function (value, key) {
let condition = { VIN: value.VIN }
Vehicle.model.findOne(condition, function (err, doc) {
if (doc) {
let condition2 = { VIN: doc.VIN }
Vehicle.model.update(condition2, value, function (err, doc1) {
updated_data += 1
if (doc && typeof doc.log === 'function') {
const data = {
action: 'Update',
category: 'Inventory Import',
message: 'Import Successful',
status: '200'
}
return doc.log(data);
}
})
} else {
Vehicle.model.create(value, function (err, doc2) {
new_data += 1
if (doc2 && typeof doc2.log === 'function') {
const data = {
action: 'Create',
category: 'Inventory Import',
message: 'Import Successful',
status: '200'
}
return doc2.log(data);
}
})
}
})
})
console.log("new datad : ", new_data)
console.log("updated_data : ", updated_data)
You can Use ASYNC/AWAIT for that put that code in an async function and then wait for each query for that.I used for of loop because it is synchronous.
const func = async() => {
let new_data = 0
let updated_data = 0
for(value of results.data){
try{
let condition = { VIN: value.VIN }
let doc = await Vehicle.model.findOne(condition);
if (doc) {
let condition2 = { VIN: doc.VIN }
let doc1 = await Vehicle.model.update(condition2)
updated_data += 1
if (doc && typeof doc.log === 'function') {
const data = {
action: 'Update',
category: 'Inventory Import',
message: 'Import Successful',
status: '200'
}
doc.log(data);
}
} else {
let doc2 = await Vehicle.model.create(value);
new_data += 1
if (doc2 && typeof doc2.log === 'function') {
const data = {
action: 'Create',
category: 'Inventory Import',
message: 'Import Successful',
status: '200'
}
doc2.log(data);
}
}
}catch(err){
console.log(err);
}
}
console.log("new datad : ", new_data)
console.log("updated_data : ", updated_data)
}
func();
I am working on a project of Amazon Alexa of booking a table in a restaurant and I have four intents:
makeReservation
futureOrCurrentLocation
getRestaurantName
selectRestaurants
I am facing one issue that the linear flow of intent is not working. I have stored the previous intent in the session and checked the previous intent from the session and on that basic I am calling the next intent.
But when I say Alexa with the previous intent String in the response of the current intent, it jumps to the new intent we have called, but it throws an exception.
Actually it should work like if I say some intent String in the response of other intent then it should repeat the current intent once again.
And one more issue I am facing is that I need to append the String in the user utterance like e.g.:
Alexa: "Where would you like to go?"
User: "Go to {Restaurant Name}"
I didn't want to append this "Go to" in the restaurant name.
// Lambda Function code for Alexa.
const Alexa = require("ask-sdk");
// Book a table
const makeReservation_Handler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest' && request.intent.name === 'makeReservation' ;
},
handle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
const responseBuilder = handlerInput.responseBuilder;
let sessionAttributes = handlerInput.attributesManager.getSessionAttributes();
sessionAttributes.tableTalkType = 1;
handlerInput.attributesManager.setSessionAttributes(sessionAttributes);
return responseBuilder
.addDelegateDirective({
name: 'futureOrCurrentLocation',
confirmationStatus: 'NONE',
slots: {}
})
.withShouldEndSession(false)
.getResponse();
},
};
const futureOrCurrentLocation_Handler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest' && request.intent.name === 'futureOrCurrentLocation' ;
},
async handle(handlerInput) {
const { requestEnvelope, serviceClientFactory, responseBuilder } = handlerInput;
let sessionAttributes = handlerInput.attributesManager.getSessionAttributes();
let previousIntentName = getPreviousIntent(sessionAttributes);
if (previousIntentName == 'makeReservation') {
const request = handlerInput.requestEnvelope.request;
// const responseBuilder = handlerInput.responseBuilder;
const slotValues = getSlotValues(request.intent.slots);
const location = slotValues.locationType.heardAs;
const tableTalkType = sessionAttributes.tableTalkType;
let say = '';
// delegate to Alexa to collect all the required slots
const currentIntent = request.intent;
if (request.dialogState && request.dialogState !== 'COMPLETED') {
return handlerInput.responseBuilder
.addDelegateDirective(currentIntent)
.getResponse();
}
if (location == 'future location') {
say = `Future location not available at this moment. Please ask to current location.`;
return responseBuilder
.speak(say)
.reprompt(say)
.getResponse();
} else if(location == 'current location' && tableTalkType == 1){
return responseBuilder
.addDelegateDirective({
name: 'getRestaurantName',
confirmationStatus: 'NONE',
slots: {}
})
.getResponse();
} else if (location == 'current location' && tableTalkType == 2) {
return userCreatedTableListing_Handler.handle(handlerInput);
} else {
say = `invalid input.Please try again`;
return responseBuilder
.speak(say)
.reprompt(say)
.getResponse();
}
} else {
return errorIntent_Handler.handle(handlerInput);
}
},
};
const getRestaurantName_Handler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest' && request.intent.name === 'getRestaurantName' ;
},
handle(handlerInput) {
let sessionAttributes = handlerInput.attributesManager.getSessionAttributes();
let previousIntentName = getPreviousIntent(sessionAttributes);
if (previousIntentName == 'futureOrCurrentLocation') {
const request = handlerInput.requestEnvelope.request;
let slotValues = getSlotValues(request.intent.slots);
// delegate to Alexa to collect all the required slots
const currentIntent = request.intent;
if (request.dialogState && request.dialogState !== 'COMPLETED') {
return handlerInput.responseBuilder
.addDelegateDirective(currentIntent)
.getResponse();
}
// SLOT: restaurantname
if (request.dialogState && request.dialogState == 'COMPLETED' && slotValues.restaurantname.heardAs) {
return new Promise((resolve) => {
getRestaurants(slotValues, handlerInput).then(say => {
resolve(handlerInput.responseBuilder.speak(say).reprompt(say).withShouldEndSession(false).getResponse());
}).catch(error => {
console.log(error);
});
});
}
} else {
return errorIntent_Handler.handle(handlerInput);
}
}
};
const selectRestaurants_Handler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest' && request.intent.name === 'selectRestaurants' ;
},
handle(handlerInput) {
let sessionAttributes = handlerInput.attributesManager.getSessionAttributes();
let previousIntentName = getPreviousIntent(sessionAttributes);
if (previousIntentName == 'getRestaurantName') {
const request = handlerInput.requestEnvelope.request;
const responseBuilder = handlerInput.responseBuilder;
let slotValues = getSlotValues(request.intent.slots);
let say = '';
let restaurantListArray = sessionAttributes.sessionrestaurantList ? sessionAttributes.sessionrestaurantList : [];
sessionAttributes.previousIntent = '';
handlerInput.attributesManager.setSessionAttributes(sessionAttributes);
let restaurantIndex = slotValues.selectRestaurant.heardAs;
let restaurantData = {
name: '',
address: '',
restaurantlatitude: '',
restaurantlongitude: '',
restaurantID:'',
restaurantImageUrl: '',
date: '',
time:'',
people: '',
};
if (restaurantListArray.length >= restaurantIndex) {
let jsonData = JSON.parse(restaurantListArray[restaurantIndex - 1]);
if ((restaurantIndex) && (jsonData[restaurantIndex].name !== '' && typeof jsonData[restaurantIndex].name !== undefined && jsonData[restaurantIndex].name !== null)) {
let restaurantAddress1 = jsonData[restaurantIndex].location.address1 ? jsonData[restaurantIndex].location.address1: '';
let restaurantAddress2 = jsonData[restaurantIndex].location.address2 ? jsonData[restaurantIndex].location.address2: '';
let restaurantAddress3 = jsonData[restaurantIndex].location.address3 ? jsonData[restaurantIndex].location.address3: '';
restaurantData['name'] = jsonData[restaurantIndex].name;
restaurantData['address'] = restaurantAddress1.concat(restaurantAddress2, restaurantAddress3);
restaurantData['restaurantID'] = jsonData[restaurantIndex].id;
restaurantData['restaurantImageUrl'] = jsonData[restaurantIndex].image_url;
restaurantData['restaurantlatitude'] = jsonData[restaurantIndex].coordinates.latitude;
restaurantData['restaurantlongitude'] = jsonData[restaurantIndex].coordinates.longitude;
sessionAttributes.restaurantData = restaurantData;
handlerInput.attributesManager.setSessionAttributes(sessionAttributes);
say = `selected Restaurant name is ${jsonData[restaurantIndex].name} in ${restaurantAddress1} ${restaurantAddress2} ${restaurantAddress3}.`;
return responseBuilder
.addDelegateDirective({
name: 'bookingDate',
confirmationStatus: 'NONE',
slots: {}
})
.speak(say)
// .reprompt('try again, Please provide date')
.withShouldEndSession(false)
.getResponse();
} else {
say = 'Restaurant not available. please say again';
return responseBuilder
.speak(say)
.reprompt('Restaurant not available. please say again')
.withShouldEndSession(false)
.getResponse();
}
} else {
say = 'Please select valid input.';
return responseBuilder
.speak(say)
.reprompt('Please select valid input')
.withShouldEndSession(false)
.getResponse();
}
} else {
return errorIntent_Handler.handle(handlerInput);
}
},
};
const errorIntent_Handler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest' && request.intent.name === 'errorIntent' ;
},
handle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
const responseBuilder = handlerInput.responseBuilder;
let sessionAttributes = handlerInput.attributesManager.getSessionAttributes();
let say = 'Sorry. There is some problem with the response. Please say again';
return responseBuilder
.speak(say)
.reprompt(say)
.getResponse();
},
};
Let's say i have this:
let res = body.classes.find(c => c.name.toLowerCase() === args[0].toLowerCase()) || body.typedefs.find(t => t.name.toLowerCase() === args[0].toLowerCase())
How would I check if the output of res is from body.classes or body.typedefs?
The output will be from body.classes if body.classes.find instruction returns something. Else, it will be the result from body.typedefs.find.
const body = {
classes: [
{ name: 'name1' },
{ name: 'name2' },
{ name: 'name3' },
],
typedefs: [
{ name: 'name1' },
{ name: 'name2' },
{ name: 'name3' },
{ name: 'name4' }
]
};
const arg1 = 'NAME1';
const res1 = body.classes.find(c => c.name.toLowerCase() === arg1.toLowerCase()) || body.typedefs.find(t => t.name.toLowerCase() === arg1.toLowerCase());
console.log(res1);
const arg2 = 'NAME4';
const res2 = body.classes.find(c => c.name.toLowerCase() === arg2.toLowerCase()) || body.typedefs.find(t => t.name.toLowerCase() === arg2.toLowerCase());
console.log(res2);
So if you want to check if the output is from body.classes or from body.typedefs, you just have to store the output of each find function in different variables and then check them. Something like
const findClasses = body.classes.find(c => c.name.toLowerCase() === args[0].toLowerCase());
const findTypedefs = body.typedefs.find(c => c.name.toLowerCase() === args[0].toLowerCase());
let res = findClasses || findTypedefs;
if (findClasses) {
console.log('Ouput from body.classes.find:', findClasses);
}
if (findTypedefs) {
console.log('Ouput from body.typedefs.find:', findTypedefs);
}
I am having an issue with Vue Test Utils. When I run a unit test, I am always confronted with:
TypeError{line: 73983, sourceURL: 'http://localhost:9876/base/index.js?045b00affe888fcd6b346c4fe50eadd13d471383', stack: 'mounted#http://localhost:9876/base/index.js?045b00affe888fcd6b346c4fe50eadd13d471383:73983:30.....
This only happens when I have the mounted() function in the Vue component
Settings.vue
mounted() {
this.$refs.address.update(this.profile.address)
},
Settings.spec.js
it('calls updateUserInformation before mount', () => {
const spy = sinon.spy(Settings.methods, 'updateUserInformation')
shallow(Settings, { propsData })
Vue.nextTick().then(() => {
spy.should.have.calledOnce()
})
})
I am using Mocha & Chai with vue-test-utils. Does anyone know why this is happening?
Thank you in advance!
UPDATE
Settings.vue component HTML
<vue-google-autocomplete
ref="address"
id="map"
classname="input"
placeholder="Address"
v-on:placechanged="getAddressPlaceChanged"
v-on:inputChange="getAddressInputChange"
:country="['sg']"
>
</vue-google-autocomplete>
Settings.vue component Javascript
export default {
components: {
GoogleMaps,
AutoComplete,
VueGoogleAutocomplete,
Partner,
},
watch: {
// whenever school changes, this function will run
school() {
// Check if school value is an empty string or character is lesser than FIX_STR_LENGTH
if (this.school === '' || this.school.length < this.FIX_STR_LENGTH) {
this.removeMarker('school')
}
this.fetchSchools()
},
},
methods: {
async onSubmit() {
// Check if input fields are empty
if (this.address !== undefined && this.phoneNumber !== null && this.school !== '') {
const { placeResultData = {}, addressData = {} } = this.address
let isSuccessful = false
let tempLat = null
let tempLong = null
let tempAddress = null
// Check if address is an empty object
if (_.isEmpty(this.address)) {
const { latlong = {}, address = '' } = this.profile
const [lat, long] = latlong.coordinates
tempLat = lat
tempLong = long
tempAddress = address
} else {
// User changed address location
tempLat = addressData.latitude
tempLong = addressData.longitude
tempAddress = placeResultData.formatted_address
}
// Validate school address array
let tempSchoolAddress = []
if (this.selectedSchool !== null) {
tempSchoolAddress.push(this.selectedSchool.postal_code)
} else {
tempSchoolAddress = this.profile.schoolAddress
}
// Construct user object for registration/update
const user = new User(
this.profile.name,
tempAddress,
tempLat,
tempLong,
tempSchoolAddress,
)
// If user does not exist in database, perform a POST API registration request
if (this.userExist === false) {
// Add user properties for user registration
user.phoneNumber = this.phoneNumber
await UserSession.register(user, localStorage.getItem('id_token')).then((response) => {
const { data = {} } = response
const profile = data.user
this.updateUserInformation(profile)
isSuccessful = true
this.profile = profile
}).catch((error) => {
console.log(error.response)
})
}
// Perform a PUT API update request
await UserSession.update(user, localStorage.getItem('id_token')).then((response) => {
const { data = {} } = response
const profile = data.user
this.updateUserInformation(profile)
isSuccessful = true
this.profile = profile
}).catch((error) => {
console.log(error.response)
})
if (isSuccessful) {
this.profileChanged()
this.hasChanged = true
}
}
},
profileChanged() {
this.$emit('profileChanged', this.profile)
},
addMarker(name, params) {
if (params === null || params === '') {
return
}
gMapSession.default(params).then((response) => {
const { location = {} } = response.data.results[0].geometry
// Remove existing marker before replacing it
this.removeMarker(name)
this.markers.push({
position: location,
name,
})
this.zoom = 11
}).catch((error) => {
console.log(error.response)
})
},
removeMarker(name) {
let index = 0
let exist = false
for (let i = 0; i < this.markers.length; i++) {
if (this.markers[i].name === name) {
index = i
exist = true
break
}
}
if (exist) {
this.markers.splice(index, 1)
}
},
// Function called when user selects an option from the school autocomplete dropdown
getSelectedSchoolData(event) {
this.selectedSchool = event
// Check if selected school is defined
if (this.selectedSchool !== undefined && this.selectedSchool !== null) {
this.addMarker('school', this.selectedSchool.postal_code)
} else {
this.removeMarker('school')
}
},
// Function called when user types in the address autocomplete input field
getAddressInputChange(data) {
const { newVal = {} } = data
if (newVal === '' || newVal.length < this.FIX_STR_LENGTH) {
this.removeMarker('user')
}
},
// Function called when user selects an option from the address autocomplete dropdown
getAddressPlaceChanged(addressData, placeResultData) {
this.address = {
placeResultData,
addressData,
}
if (addressData !== undefined && addressData !== null) {
this.addMarker('user', addressData.postal_code)
} else {
this.removeMarker('user')
}
},
async updateUserInformation(profile) {
this.phoneNumber = profile.phoneNumber
this.addMarker('user', profile.address)
// TODO: schoolAddress is an array and UI must cater to multiple schools
await SchoolSession.default(profile.schoolAddress[0]).then(async (res) => {
const { result = {} } = res.data
const { records = [] } = result
// Assume that a single postal code contains only 1 school
this.school = records[0].school_name
this.addMarker('school', records[0].postal_code)
})
},
// Fetch school information base on school search query
fetchSchools: _.debounce(function getSchools() {
if (this.school.trim() === '') {
this.schools = []
return
}
const vm = this
SchoolSession.default(this.school).then((response) => {
// JSON responses are automatically parsed.
const { records = {} } = response.data.result
vm.schools = records
}).catch((error) => {
console.log(error.response)
})
}, 500),
},
data() {
return {
FIX_STR_LENGTH: 5,
school: '',
address: '',
schools: [],
markers: [],
phoneNumber: null,
selectedSchool: null,
userExist: false,
hasChanged: false,
center: { lat: 1.3521, lng: 103.8198 },
zoom: 7,
}
},
async created() {
this.profile = this.$attrs
// Check if user was a registered member by phone number
if (this.profile.phoneNumber === undefined) {
return
}
// User exist in the database
this.userExist = !this.userExist
// Update form information
this.updateUserInformation(this.profile)
},
mounted() {
this.$refs.address.update(this.profile.address)
},
}