256 lines
7.8 KiB
JavaScript
256 lines
7.8 KiB
JavaScript
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.Person',
|
|
'Email' : 'AMAZON.LITERAL',
|
|
'Message': 'AMAZON.LITERAL',
|
|
'Data': 'AMAZON.LITERAL'
|
|
},
|
|
utterances: [
|
|
'My name is {Name}',
|
|
'I am {Name}',
|
|
'{Data}',
|
|
'My email is {Email}',
|
|
'Send replay to {Email}',
|
|
'My message is {Message}'
|
|
]
|
|
},
|
|
function(request,response){
|
|
if (!Name) Name = response.slots['Name'];
|
|
if (!Email) Email = response.slots['Email'];
|
|
if (!Message) Message = response.slots['Message'];
|
|
let Data = reponse.slots['Data'];
|
|
|
|
//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
|
|
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
|
|
|
|
//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
|
|
State = 0;
|
|
//TODO : Send email
|
|
return response.say('Message sent. Someone will contact you ASAP');
|
|
}
|
|
}
|
|
|
|
}
|
|
);
|
|
|
|
})
|
|
.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=>{
|
|
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'});
|
|
});
|
|
}
|
|
}).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);
|
|
});
|