var amazonHelper = require ('./helpers/amazon'); var databaseHelper = require ('./helpers/database'); const config = require ('./config'); require ('isomorphic-fetch'); var express = require ('express'); var alexa = require ('alexa-app'); var bodyParser = require ('body-parser'); var MongoClient = require ('mongodb').MongoClient; var ObjectID = require ('mongodb').ObjectID; const router = express.Router (); var app = express (); //User data for sending message, this is skill-related and will be in some skill container var Name = null; var Email = null; var Message = null; var State = 0; // states should be defined in seperate file. (Not sending message, Waiting for name, Waiting for email, Waiting for message) //For now : // 0 : Not sending Message // 1 : Waiting for name // 2 : Waiting for email // 3 : Waiting for message // ALWAYS setup the alexa app and attach it to express before anything else. var alexaApp = new alexa.app ('saburly'); // this means we still work with one skill alexaApp.express ({ expressApp: app, // verifies requests come from amazon alexa. Must be enabled for production. // You can disable this if you're running a dev environment and want to POST // things to test behavior. enabled by default. checkCert: false, // sets up a GET route when set to true. This is handy for testing in // development, but not recommended for production. disabled by default debug: true, }); // now POST calls to /test in express will be handled by the app.request() function // from here on you can setup any other express routes or middlewares as nor app.set ('view engine', 'ejs'); var updateIntentsJSON = function () { databaseHelper .loadSkill (config.SKILL_DB_ID) .then (skill => { skill.intents.map (intent => { alexaApp.intent ( intent.intentName, { slots: [], utterances: intent.questions, }, function (request, response) { return response.say (intent.answer).shouldEndSession(false); } ); }); alexaApp.launch ((request, response) => { return response.say (skill.invocationAnswer).shouldEndSession(false); }); alexaApp.intent('EmailIntentLaunch',{ slots:[], utterances: [ 'I want to send a message', 'I would like to send a message', 'I would like to leave a message', 'Leave a message' ] }, function(request,response){ Name = null; Email = null; Message = null; State = 1; return response.say('Ok. What is your name').shouldEndSession(false); } ); //TODO : Watch out for this intent. It will make trouble with other regular intents //if other intents have utterance with just one slot like {Data} //It should be taken care somwhere before this, to check if Email Intent is invoked //This is problem only if we introduce slot options for regular intents for users alexaApp.intent('EmailIntent',{ slots:{ 'Name':'AMAZON.US_FIRST_NAME', 'Email' : 'AMAZON.LITERAL', 'Message': 'AMAZON.LITERAL', 'Data': 'AMAZON.LITERAL' }, utterances: [ 'My name is {-|Name}', 'I am {-|Name}', '{dawdw at dwd wdw|Data}', 'My email is {wadwwdw at wadwwd wdw|Email}', 'Send replay to {fkofkeofe at dppfam wd|Email}', 'My message is {Quick brown fox jumps over lazy dog|Message}' ] }, function(request,response){ let Data = undefined; try{if (!Name) Name = request.slot('Name');}catch(e){console.log('Error. No name slot ');Name=undefined;} try{if (!Email) Email = request.slot('Email');}catch(e){console.log('Error. No Email slot');Email=undefined;} try{if (!Message) Message = request.slot('Message');}catch(e){console.log('Error. No Message slot');Message=undefined;} try{Data = request.slot('Data');}catch(e){console.log('Error. No Data slot');Data=undefined;} console.log('State : ' + State); //TODO : Responses could be configurable for each skill ? if (State === 1){ //Was waiting for name, so if Name is null, name is probably in Data if ((!Name && Data) || Name){ //got the name, let's continue for the email if (!Name) Name = Data; State = 2; return response.say('Ok ' + Name + '. What is your email ?').shouldEndSession(false); }else{ //Something is wrong, ask for name again return response.say('Sorry, I didnt understand your name. Can you say it again ?').shouldEndSession(false); } }else if (State === 2){ //was waiting for email, so if Email is null, email is probably in Data if ((!Email && Data) || Email){ //Got the email, first verify email and than continue to message if (!Email) Email = Data; //TODO : verify email State = 3; return response.say('Great. Whats the message ?').shouldEndSession(false); }else{ //Something is wrong, ask for the email again return response.say('Sorry, I didnt understan you email. Can you say it again ?').shouldEndSession(false); } }else if (State === 3){ //Was waiting for message, so if Message is null, message is probably in Data if ((!Message && Data) || Message){ //Ok, we got all informations. Exit email intent if (!Message) Message=Data; State = 0; //TODO : Send email console.log('Name : ' + Name + ' | Email : ' + Email + ' | Message : ' + Message); return response.say('Message sent. Someone will contact you ASAP'); }else{ //Something is wrong, ask for the message again return response.say('Sorry, I didnt understand your message. Can you say it again ?').shouldEndSession(false); } }else{ console.log('State strange ! ' + State); } } ); }) .catch (err => { console.log (err); alexaApp.launch ((request, response) => { return response.say ('Sorry, there was no skill with that name'); }); }); }; router.get ('/getSkill/:id', async (req, res, next) => { const id = req.params.id; if (id.length !== 24) { res.json ([]); } else { databaseHelper .getSkill (id) .then (result => { res.json (result); }) .catch (err => { res.json ([]); }); } }); router.get ('/deleteSkill/:skillID', async (req, res, next) => { databaseHelper .deleteSkill (req.params.id) .then (result => { res.json (result); }) .catch (err => { res.json (err); }); }); router.post ('/updateSkill/:id', async (req, res, next) => { let id = req.params.id; let dataFromWeb = JSON.stringify(req.body); let skill = JSON.parse(dataFromWeb); let updateOnAmazon = skill.updateOnAmazon; delete skill.updateOnAmazon; delete skill._id; console.log('id = ' + id); if (id !== '-1') { if (updateOnAmazon){ amazonHelper.updateSkill(skill).then(amazonResult=>{ console.log('Amazon : ' + amazonResult); if (amazonResult === 200 || amazonResult === 202) { //Skill uploaded, it's ok to update databaseI databaseHelper .updateSkill (id, skill) .then (result => { res.json ({result: 0, message: 'ok'}); updateIntentsJSON (); }) .catch (e => { res.json ({result: -1, message: 'error'}); }); }else{ res.json({result: -1, message: 'amazon error : ' + amazonResult}); } }).catch(e=>{ res.json ({result: -1, message: e}); }); }else{ databaseHelper .updateSkill (id, skill) .then (result => { res.json ({result: 0, message: 'ok'}); updateIntentsJSON (); }) .catch (e => { res.json ({result: -1, message: 'error'}); }); } } else { //no new skills for now } }); app.use (function (req, res, next) { res.header ('Access-Control-Allow-Origin', '*'); res.header ('Access-Control-Allow-Headers', 'Origin, Content-Type'); res.header ('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); res.header ('Access-Control-Allow-Credentials', 'true'); next (); }); app.use (bodyParser.json ()); app.use ('/', router); MongoClient.connect (config.dbURL) .then (database => { databaseHelper.initModule (database); app.listen (config.PORT, () => { console.log ('Express server running on port ' + config.PORT); updateIntentsJSON (); databaseHelper.loadTokens (); }); }) .catch (e => { console.log ('error : ' + e); });