Compare commits
8 Commits
bilal-step
...
bilal-step
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3fe9ebde9d | ||
|
|
b7a778691f | ||
|
|
beb575ef7f | ||
|
|
c3bba7ffa7 | ||
|
|
2990fad6cf | ||
|
|
03c346f5d2 | ||
|
|
b55dd56859 | ||
|
|
32e0f4d6d7 |
15
backend/config.js
Normal file
15
backend/config.js
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
var config = {};
|
||||||
|
|
||||||
|
config.dbURL = 'mongodb://localhost:27017/tellall';
|
||||||
|
config.PORT = 5000;
|
||||||
|
|
||||||
|
config.TOKEN = 'Atza|IwEBIBe6gDqrrowEEav6N-_6s4NztYeP3oG8PGWmu8ZiZw6lbOh3wNla3TK6pY-VEpT1d8an-dVf_n3kXJzVFsNo_4xBfZyFHGoCTDTFjs3yBRul4PVdBOhwwiH3-sgRLcUofZbe2oE06GmTcbfYtaStfXpQI5dfpldfnsJg_CvhSA6AHb_snJT3F6lyXzbV076d_3cYUMJxFldJGnYcviNHHxjjmuQTD06hhGzCbAxxe9eBmkuopRsNfyedLT2UlKP_ublah9CUGA3AdIX_3Iuke82jMwGnNl9gv7pbaDNEjAbj7IQSl3B08uuREtJq-oTBOjALNXRvFxTJmQjZwXNf9eHC7fSHJDdEPdZQU0AcffRQObAyAkUuL6Jv39OHzhb3Q64-zzoyODqnJyLP5SQZ2JVF53Kc_cTBqjIc9pXljqe7yEVk6JDs7q1zKbBibx_AQm57TO79IzWyLBzBMlYL5HdTsqEfRzLeDw2tws-hGMgkx2HWfdbYnmf5Qb4SyIhzvmmdfPLg3MVKTxjIBu1rx0xf3n0PLZP1EO6jsJPoMRPg77Gm4oit5Zp6s37ek3A3Vxh-ntoASpkrkxGTG9kVtRNt';
|
||||||
|
config.REFRESH_TOKEN = 'Atzr|IwEBICA3kDhfSJxlwvnQp9AD1o115AC_KBbFd5GBg8oN_QHWn2or5xFQ09BruuK6a07tGHtTt_9q2Y21mnOMH4RDtYXTVG9ADgLE6mHWKZFxYVwt3kHMiUJdY5lJcsOtWLoblrS-bJ0BEXXK5nVDt_bSI5IB7NUf-9QVZxhovRH_ANSxdTjJT0_rMIAZY3WEj68FEap49q_pg72BhnxHVZD2TC3zvX96_DN65HE5SoSgT7OiMAeiJewB_SyemW_HxBwaB-_X-G1ifOtnrzZ4gXTpOrEUlHI2YPuvRMBMtmz1h-nXDZYv3vwU3RA57Qj_ZNVcScj8_RXf2xq8w48v0PzZFXYBSalfnqPq6eUvSSbAJUp6bB8y596JlvR5dFQe_Z--X0Gkfo85IcyrI9D44vK9sJhrGhCVi2FDDa8pHczmNSen99JYZvDif-zpYzgbcymAkOV0gC7JvYMxlZfETT3NTBy7eVA7fJI1SZaeA_qW49xRcBkZBu5gkqTpeGWUU1cGr2aXRVVmXGM22NfV5E7KzvEBsCeHml_tCfxZeKY8Msd8hJb0Cd59u-_hsuc8oNjsOpIdFF976dY3uTmAgHWpG2PH';
|
||||||
|
config.TOKEN_EXPIRES_IN = 1515100500;
|
||||||
|
|
||||||
|
config.SKILL_ID = 'amzn1.ask.skill.efbf0564-a732-4ba9-958f-57939138adae';
|
||||||
|
|
||||||
|
config.CLIENT_ID = 'amzn1.application-oa2-client.c748ca56ded04a95b236979898585ff7';
|
||||||
|
config.CLIENT_SECRET = '6dea8125cecd049d3c4cff7bb5bdfd3ff17bc6fed246c4c8f6b519d9ed08d0b3';
|
||||||
|
|
||||||
|
module.exports=config;
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
var amazonHelper = require('./helpers/amazon');
|
var amazonHelper = require('./helpers/amazon');
|
||||||
|
var databaseHelper = require('./helpers/database');
|
||||||
|
|
||||||
|
const config = require('./config');
|
||||||
|
|
||||||
require('isomorphic-fetch');
|
require('isomorphic-fetch');
|
||||||
|
|
||||||
@@ -7,16 +10,75 @@ var alexa = require('alexa-app');
|
|||||||
|
|
||||||
var bodyParser = require('body-parser');
|
var bodyParser = require('body-parser');
|
||||||
|
|
||||||
const dbURL = 'mongodb://localhost:27017/tellall';
|
|
||||||
const PORT = 5000;
|
|
||||||
const TOKEN = 'Atza|IwEBIMv0spn-eZhjP8-R2Jjkb4VUi-EY4V3MX-wlJyr2P6YBUmIChl7VKgRberEdQ-Wolp53SqfwHbxlSo4-rdUgFYFAxImB622boeqUBBCtwybP0OTBJBT1CVm_FBr48Li5LkwR9DxPciCnc052ddohpjGuGZxsCqIJo2c-7LPEhH0Lx63VOFgfPIfBsrVqjDbPNrr5ApPUijKYZWurktb6ytTks8eFUSTyv3FDbE5HEng0qpE4mgSjdgBkEc8BgUfpm2QGvctINH9SioUJOJonxgTPYhbD4BEd-jdQHsltKFzkb3-Rm3lFhEu3_CQFxCeQ6yGe1the_qID3vnPfpSY6hyblgF5L_5d7bE7BWg8fm6rSwXv67L2sMwBOji6cuR0wVVvXfYxmgGIMGkVQrq-SPSdtCpx2BvBz2SqqN6a_98svP8ukvhwc_oJsN6VwEmTDFgutNf-XuGkuVii-k9-DncwuwD00LvJG1FhBvbvSyuv-a3LAJSqTmroemTDG0xzLn7ULFY5p-93sM0_ZNGFeW-lL_r1ldqM_5lFRKDta1Tkg7lT9-rHftgnpGs4zv7vGLIPzHpNiXjsKyCk-wMQrihhWlR15kiz7oKDeTf6wCIETg';
|
|
||||||
const USER_ID = 'amzn1.ask.account.AGE34MG3VIQ75D4Q5CXFK25GUOXHZ2MIVSII3QUCOT3CP44IPE25PLD3DWW7HLWO2KVC7PC7VUXSZZEFPVHJ6PTDYVYYESJE35CE6VEXCE3BI3AK24TGO4CJXFF3SZ7IA4QVJRZC6EN4MUF2WUP4IB4CGDLRZZMYQENOFNBYWFXZHMZ5PA6S6ERK7NGEPUSDHXWKH26UGMIATMI';
|
|
||||||
|
|
||||||
var MongoClient = require ('mongodb').MongoClient;
|
var MongoClient = require ('mongodb').MongoClient;
|
||||||
var ObjectID = require ('mongodb').ObjectID;
|
var ObjectID = require ('mongodb').ObjectID;
|
||||||
|
|
||||||
const router = express.Router ();
|
const router = express.Router ();
|
||||||
|
|
||||||
|
var skillID = 'amzn1.ask.skill.7115bfc9-313e-4728-830b-ebd19ce96cb3';
|
||||||
|
var skillDbID = '5a232fb86ce046c749739455'; //_id in database
|
||||||
|
|
||||||
|
var app = express();
|
||||||
|
|
||||||
|
// ALWAYS setup the alexa app and attach it to express before anything else.
|
||||||
|
var alexaApp = new alexa.app('step3'); // 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 normal
|
||||||
|
app.set("view engine", "ejs");
|
||||||
|
alexaApp.launch(function(request, response) {
|
||||||
|
console.log("Alexa launch");
|
||||||
|
console.log(request);
|
||||||
|
const skill = db.collection('skill_list').findOne({_id: ObjectID(skillDbID)}, (err,result)=>{
|
||||||
|
if (err){
|
||||||
|
response.say("I could not find desired skill")
|
||||||
|
}else{
|
||||||
|
response.say(skill.invocationAnswer);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var findElementByAttr = function (data, attr, val){
|
||||||
|
for(var i = 0; i < data.length; i ++) {
|
||||||
|
if(data[i][attr] === val) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
alexaApp.request = (jsonRequest) => {
|
||||||
|
const alexaRequest = new alexa.request(jsonRequest);
|
||||||
|
if (alexaRequest.type() === "IntentRequest") {
|
||||||
|
const skill = db.collection('skill_list').findOne({
|
||||||
|
_id: skillDbID
|
||||||
|
});
|
||||||
|
if (skill) {
|
||||||
|
let intentId = findElementByAttr(skill.intents, 'intentName', alexaRequest.data.request.intent.name);
|
||||||
|
const response = new alexa.response(alexaRequest.getSession());
|
||||||
|
if (intentId !== -1){
|
||||||
|
return response.say(skill.intents[intentId].answer);
|
||||||
|
}else{
|
||||||
|
return response.say('Sorry, I could not find desired intent');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
router.get ('/getSkill/:id', async (req, res, next) => {
|
router.get ('/getSkill/:id', async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
const id = req.params.id;
|
const id = req.params.id;
|
||||||
@@ -55,103 +117,35 @@ router.get ('/deleteSkill/:skillID', async (req, res, next) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
router.post ('/updateSkill/:id', async (req, res, next) => {
|
router.post ('/updateSkill/:id', async (req, res, next) => {
|
||||||
try {
|
|
||||||
let id = req.params.id;
|
let id = req.params.id;
|
||||||
let skill = req.body;
|
let skill = req.body;
|
||||||
delete skill._id;
|
delete skill._id;
|
||||||
if (id !== '-1'){
|
if (id !== '-1'){
|
||||||
let completeResult = {databaseUpdate:false, amazonUpdate:false, amazonMessage:''};
|
amazonHelper.updateSkill(skill,db).then(amazonResult=>{
|
||||||
|
if (amazonResult===200 || amazonResult===202){
|
||||||
let result = db.collection('skill_list').update({_id: ObjectID(id)}, skill,{upsert:true}, (err, result)=>{
|
//Skill uploaded, it's ok to update database
|
||||||
if (err) throw(err);
|
let result = db.collection('skill_list').update({_id: ObjectID(id)}, skill,{upsert:true}, (err, result)=>{
|
||||||
|
if (JSON.parse(result).nModified===1){
|
||||||
completeResult.databaseUpdate = (JSON.parse(result).nModified===1);
|
//database update ok
|
||||||
|
res.json({result:0, message:'ok'});
|
||||||
let generatedInteractionModel = amazonHelper.generateInteractionModel(skill);
|
}else{
|
||||||
|
res.json({result:-1, message:'ok'});
|
||||||
fetch(`https://api.amazonalexa.com/v0/skills/${skill.skillID}/interactionModel/locales/en-US`, {
|
}
|
||||||
method: 'POST',
|
});
|
||||||
headers: {
|
}else{
|
||||||
Authorization: TOKEN
|
res.json({result:-1, message:'Amazon result ' + amazonResult});
|
||||||
},
|
}
|
||||||
body: generatedInteractionModel
|
}).catch(e=>{
|
||||||
}).then(l=>l.text()).then(result=>{
|
//skill upload went wrong, don't update database, send error
|
||||||
completeResult.amazonUpdate = (JSON.stringify(result)===JSON.stringify({}));
|
res.json({result:-1, message:e});
|
||||||
completeResult.amazonMessage = JSON.stringify(result);
|
|
||||||
res.json(completeResult);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
}else{
|
}else{
|
||||||
//no new skills for now
|
//no new skills for now
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (e) {
|
|
||||||
console.log ('error:', e);
|
|
||||||
next (e);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var skillID = 'amzn1.ask.skill.7115bfc9-313e-4728-830b-ebd19ce96cb3';
|
|
||||||
var skillDbID = '5a232fb86ce046c749739455'; //_id in database
|
|
||||||
|
|
||||||
var app = express();
|
|
||||||
|
|
||||||
// ALWAYS setup the alexa app and attach it to express before anything else.
|
|
||||||
var alexaApp = new alexa.app('step3'); // 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 normal
|
|
||||||
|
|
||||||
alexaApp.launch(function(request, response) {
|
|
||||||
const skill = db.collection('skill_list').findOne({_id: ObjectID(skillDbID)}, (err,result)=>{
|
|
||||||
if (err){
|
|
||||||
response.say("I could not find desired skill")
|
|
||||||
}else{
|
|
||||||
response.say(skill.invocationAnswer);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
var findElementByAttr = function (data, attr, val){
|
|
||||||
for(var i = 0; i < data.length; i ++) {
|
|
||||||
if(data[i][attr] === val) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
alexaApp.request = (jsonRequest) => {
|
|
||||||
const alexaRequest = new alexa.request(jsonRequest);
|
|
||||||
if (alexaRequest.type() === "IntentRequest") {
|
|
||||||
const skill = db.collection('skill_list').findOne({
|
|
||||||
_id: skillDbID
|
|
||||||
});
|
|
||||||
if (skill) {
|
|
||||||
let intentId = findElementByAttr(skill.intents, 'intentName', alexaRequest.data.request.intent.name);
|
|
||||||
const response = new alexa.response(alexaRequest.getSession());
|
|
||||||
if (intentId !== -1){
|
|
||||||
return response.say(skill.intents[intentId].answer);
|
|
||||||
}else{
|
|
||||||
return response.say('Sorry, I could not find desired intent');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
app.use (function (req, res, next) {
|
app.use (function (req, res, next) {
|
||||||
res.header ('Access-Control-Allow-Origin', '*');
|
res.header ('Access-Control-Allow-Origin', '*');
|
||||||
@@ -168,10 +162,16 @@ app.use (bodyParser.json ());
|
|||||||
app.use ('/', router);
|
app.use ('/', router);
|
||||||
|
|
||||||
|
|
||||||
MongoClient.connect (dbURL).then (database => {
|
MongoClient.connect (config.dbURL).then (database => {
|
||||||
db = database;
|
db = database;
|
||||||
db.collection ('intent_list');
|
db.collection ('intent_list');
|
||||||
app.listen (PORT, () =>
|
|
||||||
console.log ('Express server running on port ' + PORT)
|
databaseHelper.initModule(db);
|
||||||
);
|
|
||||||
|
app.listen (config.PORT, () =>{
|
||||||
|
console.log ('Express server running on port ' + config.PORT);
|
||||||
|
databaseHelper.loadTokens();
|
||||||
|
});
|
||||||
|
}).catch(e=>{
|
||||||
|
console.log("error : " + e);
|
||||||
});
|
});
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
require('isomorphic-fetch');
|
require('isomorphic-fetch');
|
||||||
|
const config = require('../config');
|
||||||
var ObjectID = require ('mongodb').ObjectID;
|
var request = require("request");
|
||||||
|
var token = require('./token');
|
||||||
|
|
||||||
|
|
||||||
var getBuildStatus = function(skillID){
|
var getBuildStatus = function(skillID){
|
||||||
@@ -18,45 +19,100 @@ var getBuildStatus = function(skillID){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var refreshToken = function(db){
|
||||||
|
return new Promise((resolve, reject)=>{
|
||||||
|
var options = { method: 'POST',
|
||||||
|
url: 'https://api.amazon.com/auth/o2/token',
|
||||||
|
headers:
|
||||||
|
{ 'cache-control': 'no-cache',
|
||||||
|
'content-type': 'application/x-www-form-urlencoded' },
|
||||||
|
form:
|
||||||
|
{ grant_type: 'refresh_token',
|
||||||
|
refresh_token: config.REFRESH_TOKEN,
|
||||||
|
client_id: config.CLIENT_ID,
|
||||||
|
client_secret: config.CLIENT_SECRET } };
|
||||||
|
|
||||||
|
request(options, function (error, response, body) {
|
||||||
|
if (error) reject(error);
|
||||||
|
parsedResponse = JSON.parse(body);
|
||||||
|
if (parsedResponse.refresh_token){
|
||||||
|
try{
|
||||||
|
token.updateTokens(parsedResponse.refresh_token, parsedResponse.access_token, parsedResponse.expires_in,db);
|
||||||
|
resolve();
|
||||||
|
}catch(e){
|
||||||
|
reject(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var generateInteractionModel = function(skill){
|
||||||
|
let result = {};
|
||||||
|
let allIntents = [];
|
||||||
|
let defaultIntents = [{
|
||||||
|
name: "AMAZON.CancelIntent",
|
||||||
|
samples: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "AMAZON.HelpIntent",
|
||||||
|
samples: []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "AMAZON.StopIntent",
|
||||||
|
samples: []
|
||||||
|
}];
|
||||||
|
|
||||||
|
/*
|
||||||
|
defaultIntents.map(intent=>{
|
||||||
|
allIntents.push(intent);
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
|
||||||
|
skill.intents.map(intent=>{
|
||||||
|
allIntents.push({name: intent.intentName, samples: intent.questions});
|
||||||
|
});
|
||||||
|
|
||||||
|
result.interactionModel = {};
|
||||||
|
|
||||||
|
result.interactionModel.languageModel = {
|
||||||
|
invocationName: skill.invocationName,
|
||||||
|
intents: allIntents
|
||||||
|
};
|
||||||
|
|
||||||
|
return JSON.stringify(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
var uploadSkill = function(skill){
|
||||||
|
return fetch(`https://api.amazonalexa.com/v0/skills/${skill.skillID}/interactionModel/locales/en-US`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Authorization: config.TOKEN
|
||||||
|
},
|
||||||
|
body: generateInteractionModel(skill)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
generateInteractionModel: function(skill){
|
updateSkill: function(skill, db){
|
||||||
try{
|
return new Promise((resolve,reject)=>{
|
||||||
let result = {};
|
if (new Date() / 1000 > config.TOKEN_EXPIRES_IN){
|
||||||
let allIntents = [];
|
refreshToken(db).then(()=>{
|
||||||
let defaultIntents = [{
|
uploadSkill(skill).then(response=>{
|
||||||
name: "AMAZON.CancelIntent",
|
resolve(response.status);
|
||||||
samples: []
|
});
|
||||||
},
|
}).catch(e=>{
|
||||||
{
|
reject(e);
|
||||||
name: "AMAZON.HelpIntent",
|
});
|
||||||
samples: []
|
}else{
|
||||||
},
|
uploadSkill(skill).then(response=>{
|
||||||
{
|
resolve(response.status);
|
||||||
name: "AMAZON.StopIntent",
|
}).catch(e=>{
|
||||||
samples: []
|
reject(e);
|
||||||
}];
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
/*
|
|
||||||
defaultIntents.map(intent=>{
|
|
||||||
allIntents.push(intent);
|
|
||||||
});
|
|
||||||
*/
|
|
||||||
|
|
||||||
skill.intents.map(intent=>{
|
|
||||||
allIntents.push({name: intent.intentName, samples: intent.questions});
|
|
||||||
});
|
|
||||||
|
|
||||||
result.interactionModel = {};
|
|
||||||
|
|
||||||
result.interactionModel.languageModel = {
|
|
||||||
invocationName: skill.invocationName,
|
|
||||||
intents: allIntents
|
|
||||||
};
|
|
||||||
|
|
||||||
return JSON.stringify(result);
|
|
||||||
}catch(e){
|
|
||||||
console.log("error generate : " + e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
27
backend/helpers/database.js
Normal file
27
backend/helpers/database.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
const config = require('../config');
|
||||||
|
|
||||||
|
var db = null;
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
initModule : function(databaseObject){
|
||||||
|
db=databaseObject;
|
||||||
|
},
|
||||||
|
|
||||||
|
loadTokens : function(){
|
||||||
|
db.collection('token_list').findOne().then(tokens=>{
|
||||||
|
if (tokens !== null){
|
||||||
|
config.TOKEN = tokens.access_token;
|
||||||
|
config.REFRESH_TOKEN = tokens.refresh_token;
|
||||||
|
config.TOKEN_EXPIRES_IN = tokens.expires_in;
|
||||||
|
}else{
|
||||||
|
//Cannot continue without tokens
|
||||||
|
console.log("Cannot continue without tokens in database");
|
||||||
|
process.exit(-1);
|
||||||
|
}
|
||||||
|
}).catch(e=>{
|
||||||
|
console.log("Error loading tokens ! Cannot continue without tokens in database");
|
||||||
|
process.exit(-1);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
19
backend/helpers/token.js
Normal file
19
backend/helpers/token.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
const config = require('../config');
|
||||||
|
var ObjectID = require ('mongodb').ObjectID;
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
updateTokens : function (refresh_token, access_token, expires_in, db){
|
||||||
|
let newTokenDocument = {
|
||||||
|
id:1,
|
||||||
|
refresh_token:refresh_token,
|
||||||
|
access_token: access_token,
|
||||||
|
expires_in: (new Date() / 1000) + expires_in
|
||||||
|
}
|
||||||
|
let result = db.collection('token_list').update({id:1}, newTokenDocument,{upsert:true}, (err, result)=>{
|
||||||
|
if (err) throw new Error(err);
|
||||||
|
config.REFRESH_TOKEN = refresh_token;
|
||||||
|
config.TOKEN = access_token;
|
||||||
|
config.TOKEN_EXPIRES_IN = newTokenDocument.expires_in;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -6,9 +6,11 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"alexa-app": "4.2.0",
|
"alexa-app": "4.2.0",
|
||||||
"body-parser": "^1.13.1",
|
"body-parser": "^1.13.1",
|
||||||
"ejs": "^2.3.1",
|
"ejs": "^2.5.7",
|
||||||
"express": "^4.13.0",
|
"express": "^4.13.0",
|
||||||
"isomorphic-fetch": "^2.2.1"
|
"isomorphic-fetch": "^2.2.1",
|
||||||
|
"mongodb": "^2.2.33",
|
||||||
|
"request": "^2.83.0"
|
||||||
},
|
},
|
||||||
"author": "Matt Kruse <github@mattkruse.com> (http://mattkruse.com/)",
|
"author": "Matt Kruse <github@mattkruse.com> (http://mattkruse.com/)",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
|
|||||||
10
backend/views/test.ejs
Normal file
10
backend/views/test.ejs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<div style="white-space:pre;border:1px solid black;margin:5px;padding:5px;font-family:monospace;">
|
||||||
|
Schema:
|
||||||
|
|
||||||
|
<%=schema%>
|
||||||
|
|
||||||
|
Utterances:
|
||||||
|
|
||||||
|
<%=utterances%>
|
||||||
|
|
||||||
|
</div>
|
||||||
2239
web/README.md
2239
web/README.md
File diff suppressed because it is too large
Load Diff
@@ -3,9 +3,11 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"keymaster": "^1.6.2",
|
||||||
"react": "^16.2.0",
|
"react": "^16.2.0",
|
||||||
"react-dom": "^16.2.0",
|
"react-dom": "^16.2.0",
|
||||||
"react-md": "^1.2.8",
|
"react-md": "^1.2.8",
|
||||||
|
"react-popup": "^0.9.1",
|
||||||
"react-scripts": "1.0.17",
|
"react-scripts": "1.0.17",
|
||||||
"webfontloader": "^1.6.28"
|
"webfontloader": "^1.6.28"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import './css/App.css';
|
import './css/App.css';
|
||||||
|
import './css/popup.css';
|
||||||
import IntentList from './components/IntentList';
|
import IntentList from './components/IntentList';
|
||||||
import IntentDetails from './components/IntentDetails';
|
import IntentDetails from './components/IntentDetails';
|
||||||
import LaunchRequest from './components/LaunchRequest';
|
import LaunchRequest from './components/LaunchRequest';
|
||||||
|
import Popup from 'react-popup';
|
||||||
|
|
||||||
import {getSkill, updateSkill} from './lib/api'
|
import {getSkill, updateSkill} from './lib/api'
|
||||||
|
|
||||||
@@ -42,6 +44,7 @@ class App extends Component {
|
|||||||
if(this.state.launchRequest){
|
if(this.state.launchRequest){
|
||||||
return (
|
return (
|
||||||
<div className="App">
|
<div className="App">
|
||||||
|
<Popup/>
|
||||||
<div className="App-header">
|
<div className="App-header">
|
||||||
<h1> Tell All </h1>
|
<h1> Tell All </h1>
|
||||||
</div>
|
</div>
|
||||||
@@ -59,6 +62,7 @@ class App extends Component {
|
|||||||
}else{
|
}else{
|
||||||
return (
|
return (
|
||||||
<div className="App">
|
<div className="App">
|
||||||
|
<Popup/>
|
||||||
<div className="App-header">
|
<div className="App-header">
|
||||||
<h1> Tell All </h1>
|
<h1> Tell All </h1>
|
||||||
</div>
|
</div>
|
||||||
@@ -97,16 +101,19 @@ class App extends Component {
|
|||||||
|
|
||||||
handleSaveLaunchRequestClick(name, answer){
|
handleSaveLaunchRequestClick(name, answer){
|
||||||
this.setState({invocationName: name, invocationAnswer: answer});
|
this.setState({invocationName: name, invocationAnswer: answer});
|
||||||
try{
|
console.log("handleSaveLaunchRequest");
|
||||||
updateSkill(this.createSkill(this.state.allIntents,name,answer)).then(l=>l.text()).then(result=>{
|
updateSkill(this.createSkill(this.state.allIntents,name,answer)).then(l=>l.text()).then(result=>{
|
||||||
let jResult = JSON.parse(result);
|
let jResult = JSON.parse(result);
|
||||||
if (!(jResult.databaseUpdate && jResult.amazonUpdate)){
|
if (jResult.result !== 0){
|
||||||
alert('Database update : ' + jResult.databaseUpdate + '\r\nAmazon update : ' + jResult.amazonUpdate + '\r\nMessage : ' + jResult.amazonMessage);
|
Popup.alert('Model was not saved. Please try again');
|
||||||
|
}else{
|
||||||
|
Popup.alert('Saved');
|
||||||
}
|
}
|
||||||
|
console.log(jResult.message);
|
||||||
|
}).catch(e=>{
|
||||||
|
console.log("Error :" + e);
|
||||||
|
Popup.alert('Model was not saved. Please try again');
|
||||||
});
|
});
|
||||||
}catch(e){
|
|
||||||
alert("exception");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDeleteIntentClick(selectedIntent){
|
handleDeleteIntentClick(selectedIntent){
|
||||||
@@ -120,12 +127,18 @@ class App extends Component {
|
|||||||
this.setState({allIntents: newAllIntents, selectedIntent: {intentName:'', questions:[''],answer:''}});
|
this.setState({allIntents: newAllIntents, selectedIntent: {intentName:'', questions:[''],answer:''}});
|
||||||
updateSkill(this.createSkill(newAllIntents)).then(l=>l.text()).then(result=>{
|
updateSkill(this.createSkill(newAllIntents)).then(l=>l.text()).then(result=>{
|
||||||
let jResult = JSON.parse(result);
|
let jResult = JSON.parse(result);
|
||||||
if (!(jResult.databaseUpdate && jResult.amazonUpdate)){
|
if (jResult.result !== 0){
|
||||||
alert('Database update : ' + jResult.databaseUpdate + '\r\nAmazon update : ' + jResult.amazonUpdate + '\r\nMessage : ' + jResult.amazonMessage);
|
Popup.alert('Model was not saved. Please try again');
|
||||||
|
}else{
|
||||||
|
Popup.alert('Saved');
|
||||||
}
|
}
|
||||||
|
console.log(jResult.message);
|
||||||
|
}).catch(e=>{
|
||||||
|
console.log("error : " + e);
|
||||||
|
Popup.alert('Model was not saved. Please try again');
|
||||||
});
|
});
|
||||||
}catch(e){
|
}catch(e){
|
||||||
alert("exception");
|
console.log("error : " + e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -141,16 +154,20 @@ class App extends Component {
|
|||||||
newAllIntents[this.state.selectedIndex] = selectedIntent;
|
newAllIntents[this.state.selectedIndex] = selectedIntent;
|
||||||
this.setState({allIntents: newAllIntents, selectedIntent: selectedIntent});
|
this.setState({allIntents: newAllIntents, selectedIntent: selectedIntent});
|
||||||
}
|
}
|
||||||
try{
|
|
||||||
updateSkill(this.createSkill(newAllIntents)).then(l=>l.text()).then(result=>{
|
updateSkill(this.createSkill(newAllIntents)).then(l=>l.text()).then(result=>{
|
||||||
let jResult = JSON.parse(result);
|
let jResult = JSON.parse(result);
|
||||||
if (!(jResult.databaseUpdate && jResult.amazonUpdate)){
|
if (jResult.result !== 0){
|
||||||
alert('Database update : ' + jResult.databaseUpdate + '\r\nAmazon update : ' + jResult.amazonUpdate + '\r\nMessage : ' + jResult.amazonMessage);
|
Popup.alert('Model was not saved. Please try again');
|
||||||
}
|
}else{
|
||||||
});
|
Popup.alert('Saved');
|
||||||
}catch(e){
|
}
|
||||||
alert("exception");
|
console.log(jResult.message);
|
||||||
}
|
}).catch(e=>{
|
||||||
|
Popup.alert('Model was not saved. Please try again');
|
||||||
|
console.log("error : " + e);
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleAddIntentClick(){
|
handleAddIntentClick(){
|
||||||
|
|||||||
205
web/src/css/popup.scss
Normal file
205
web/src/css/popup.scss
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
.mm-popup {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-popup--visible {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-popup__overlay {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 1000;
|
||||||
|
overflow: auto;
|
||||||
|
background: rgba(0, 0, 0, .1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-popup__close {
|
||||||
|
position: absolute;
|
||||||
|
top: 15px;
|
||||||
|
right: 20px;
|
||||||
|
padding: 0;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: none;
|
||||||
|
text-indent: -9999px;
|
||||||
|
background: transparent url('data:image/png;base64,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') no-repeat center center;
|
||||||
|
background-size: 100%;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-popup__input {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
height: 30px;
|
||||||
|
border-radius: 3px;
|
||||||
|
background: #f5f5f5;
|
||||||
|
border: 1px solid #e9ebec;
|
||||||
|
outline: none;
|
||||||
|
-moz-box-sizing: border-box !important;
|
||||||
|
-webkit-box-sizing: border-box !important;
|
||||||
|
box-sizing: border-box !important;
|
||||||
|
font-size: 14px;
|
||||||
|
padding: 0 12px;
|
||||||
|
color: #808080;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-popup__btn {
|
||||||
|
border-radius: 3px;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 0 10px;
|
||||||
|
margin: 0;
|
||||||
|
line-height: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border: 1px solid #666;
|
||||||
|
text-align: center;
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #333;
|
||||||
|
background: transparent;
|
||||||
|
outline: none;
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-family: "Open Sans", sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-popup__btn--success {
|
||||||
|
background-color: #27ae60;
|
||||||
|
border-color: #27ae60;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-popup__btn--danger {
|
||||||
|
background-color: #c5545c;
|
||||||
|
border-color: #c5545c;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-popup__box {
|
||||||
|
width: 350px;
|
||||||
|
position: fixed;
|
||||||
|
top: 10%;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -175px;
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: 0px 5px 20px 0px rgba(126,137,140,0.20);
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 1px solid #B8C8CC;
|
||||||
|
overflow: hidden;
|
||||||
|
z-index: 1001;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-popup__box__header {
|
||||||
|
padding: 15px 20px;
|
||||||
|
background: #EDF5F7;
|
||||||
|
color: #454B4D;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-popup__box__header__title {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 16px;
|
||||||
|
text-align: left;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-popup__box__body {
|
||||||
|
padding: 20px;
|
||||||
|
line-height: 1.4;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #454B4D;
|
||||||
|
background: #fff;
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-popup__box__body p {
|
||||||
|
margin: 0 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-popup__box__footer {
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 40px 20px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-popup__box__footer__right-space {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-popup__box__footer__right-space .mm-popup__btn {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-popup__box__footer__left-space {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-popup__box__footer__left-space .mm-popup__btn {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-popup__box--popover {
|
||||||
|
width: 300px;
|
||||||
|
margin-left: -150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-popup__box--popover .mm-popup__close {
|
||||||
|
position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
right: 5px;
|
||||||
|
padding: 0;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
outline: none;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: none;
|
||||||
|
text-indent: -9999px;
|
||||||
|
background: transparent url('data:image/png;base64,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') no-repeat center center;
|
||||||
|
background-size: 100%;
|
||||||
|
margin: 0;
|
||||||
|
z-index: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-popup__box--popover .mm-popup__box__body {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 420px) {
|
||||||
|
.mm-popup__box {
|
||||||
|
width: auto;
|
||||||
|
left: 10px;
|
||||||
|
right: 10px;
|
||||||
|
top: 10px;
|
||||||
|
margin-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-popup__box__footer__left-space {
|
||||||
|
float: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-popup__box__footer__right-space {
|
||||||
|
float: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-popup__box__footer {
|
||||||
|
padding-top: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mm-popup__box__footer .mm-popup__btn {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user