automatic token refresh, initial stage
This commit is contained in:
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 databaseHelper = require('./helpers/database');
|
||||
|
||||
const config = require('./config');
|
||||
|
||||
require('isomorphic-fetch');
|
||||
|
||||
@@ -7,11 +10,6 @@ var alexa = require('alexa-app');
|
||||
|
||||
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 ObjectID = require ('mongodb').ObjectID;
|
||||
|
||||
@@ -55,40 +53,33 @@ router.get ('/deleteSkill/:skillID', async (req, res, next) => {
|
||||
});
|
||||
|
||||
router.post ('/updateSkill/:id', async (req, res, next) => {
|
||||
try {
|
||||
|
||||
let id = req.params.id;
|
||||
let skill = req.body;
|
||||
delete skill._id;
|
||||
if (id !== '-1'){
|
||||
let completeResult = {databaseUpdate:false, amazonUpdate:false, amazonMessage:''};
|
||||
|
||||
let result = db.collection('skill_list').update({_id: ObjectID(id)}, skill,{upsert:true}, (err, result)=>{
|
||||
if (err) throw(err);
|
||||
|
||||
completeResult.databaseUpdate = (JSON.parse(result).nModified===1);
|
||||
|
||||
let generatedInteractionModel = amazonHelper.generateInteractionModel(skill);
|
||||
|
||||
fetch(`https://api.amazonalexa.com/v0/skills/${skill.skillID}/interactionModel/locales/en-US`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: TOKEN
|
||||
},
|
||||
body: generatedInteractionModel
|
||||
}).then(l=>l.text()).then(result=>{
|
||||
completeResult.amazonUpdate = (JSON.stringify(result)===JSON.stringify({}));
|
||||
completeResult.amazonMessage = JSON.stringify(result);
|
||||
res.json(completeResult);
|
||||
});
|
||||
amazonHelper.updateSkill(skill,db).then(amazonResult=>{
|
||||
if (amazonResult===200 || amazonResult===202){
|
||||
//Skill uploaded, it's ok to update database
|
||||
let result = db.collection('skill_list').update({_id: ObjectID(id)}, skill,{upsert:true}, (err, result)=>{
|
||||
if (JSON.parse(result).nModified===1){
|
||||
//database update ok
|
||||
res.json({result:0, message:'ok'});
|
||||
}else{
|
||||
res.json({result:-1, message:'ok'});
|
||||
}
|
||||
});
|
||||
}else{
|
||||
res.json({result:-1, message:'Amazon result ' + amazonResult});
|
||||
}
|
||||
}).catch(e=>{
|
||||
//skill upload went wrong, don't update database, send error
|
||||
res.json({result:-1, message:e});
|
||||
});
|
||||
|
||||
}else{
|
||||
//no new skills for now
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
console.log ('error:', e);
|
||||
next (e);
|
||||
}
|
||||
});
|
||||
|
||||
var skillID = 'amzn1.ask.skill.7115bfc9-313e-4728-830b-ebd19ce96cb3';
|
||||
@@ -168,10 +159,16 @@ app.use (bodyParser.json ());
|
||||
app.use ('/', router);
|
||||
|
||||
|
||||
MongoClient.connect (dbURL).then (database => {
|
||||
MongoClient.connect (config.dbURL).then (database => {
|
||||
db = database;
|
||||
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');
|
||||
|
||||
var ObjectID = require ('mongodb').ObjectID;
|
||||
const config = require('../config');
|
||||
var request = require("request");
|
||||
var token = require('./token');
|
||||
|
||||
|
||||
var getBuildStatus = function(skillID){
|
||||
@@ -18,45 +19,102 @@ var getBuildStatus = function(skillID){
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
generateInteractionModel: function(skill){
|
||||
try{
|
||||
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);
|
||||
}catch(e){
|
||||
console.log("error generate : " + e);
|
||||
}
|
||||
}
|
||||
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 = {
|
||||
updateSkill: function(skill, db){
|
||||
console.log("update skill function");
|
||||
|
||||
return new Promise((resolve,reject)=>{
|
||||
if (new Date() / 1000 > config.TOKEN_EXPIRES_IN){
|
||||
refreshToken(db).then(()=>{
|
||||
uploadSkill(skill).then(response=>{
|
||||
resolve(response.status);
|
||||
});
|
||||
}).catch(e=>{
|
||||
reject(e);
|
||||
});
|
||||
}else{
|
||||
uploadSkill(skill).then(response=>{
|
||||
resolve(response.status);
|
||||
}).catch(e=>{
|
||||
reject(e);
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
21
backend/helpers/database.js
Normal file
21
backend/helpers/database.js
Normal file
@@ -0,0 +1,21 @@
|
||||
const config = require('../config');
|
||||
|
||||
var db = null;
|
||||
|
||||
|
||||
module.exports = {
|
||||
initModule : function(databaseObject){
|
||||
db=databaseObject;
|
||||
},
|
||||
|
||||
loadTokens : function(){
|
||||
db.collection('token_list').findOne().then(tokens=>{
|
||||
config.TOKEN = tokens.access_token;
|
||||
config.REFRESH_TOKEN = tokens.refresh_token;
|
||||
config.TOKEN_EXPIRES_IN = tokens.expires_in;
|
||||
console.log("Tokens loaded");
|
||||
}).catch(e=>{
|
||||
console.log("Error loading tokens");
|
||||
})
|
||||
}
|
||||
}
|
||||
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;
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -8,7 +8,8 @@
|
||||
"body-parser": "^1.13.1",
|
||||
"ejs": "^2.3.1",
|
||||
"express": "^4.13.0",
|
||||
"isomorphic-fetch": "^2.2.1"
|
||||
"isomorphic-fetch": "^2.2.1",
|
||||
"request": "^2.83.0"
|
||||
},
|
||||
"author": "Matt Kruse <github@mattkruse.com> (http://mattkruse.com/)",
|
||||
"license": "MIT"
|
||||
|
||||
@@ -97,16 +97,14 @@ class App extends Component {
|
||||
|
||||
handleSaveLaunchRequestClick(name, 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=>{
|
||||
let jResult = JSON.parse(result);
|
||||
if (!(jResult.databaseUpdate && jResult.amazonUpdate)){
|
||||
alert('Database update : ' + jResult.databaseUpdate + '\r\nAmazon update : ' + jResult.amazonUpdate + '\r\nMessage : ' + jResult.amazonMessage);
|
||||
}
|
||||
console.log(jResult.result);
|
||||
console.log(jResult.message);
|
||||
}).catch(e=>{
|
||||
console.log("Error :" + e);
|
||||
});
|
||||
}catch(e){
|
||||
alert("exception");
|
||||
}
|
||||
}
|
||||
|
||||
handleDeleteIntentClick(selectedIntent){
|
||||
@@ -120,12 +118,13 @@ class App extends Component {
|
||||
this.setState({allIntents: newAllIntents, selectedIntent: {intentName:'', questions:[''],answer:''}});
|
||||
updateSkill(this.createSkill(newAllIntents)).then(l=>l.text()).then(result=>{
|
||||
let jResult = JSON.parse(result);
|
||||
if (!(jResult.databaseUpdate && jResult.amazonUpdate)){
|
||||
alert('Database update : ' + jResult.databaseUpdate + '\r\nAmazon update : ' + jResult.amazonUpdate + '\r\nMessage : ' + jResult.amazonMessage);
|
||||
}
|
||||
console.log(jResult.result);
|
||||
console.log(jResult.message);
|
||||
}).catch(e=>{
|
||||
console.log("error : " + e);
|
||||
});
|
||||
}catch(e){
|
||||
alert("exception");
|
||||
console.log("error : " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -141,16 +140,15 @@ class App extends Component {
|
||||
newAllIntents[this.state.selectedIndex] = selectedIntent;
|
||||
this.setState({allIntents: newAllIntents, selectedIntent: selectedIntent});
|
||||
}
|
||||
try{
|
||||
updateSkill(this.createSkill(newAllIntents)).then(l=>l.text()).then(result=>{
|
||||
let jResult = JSON.parse(result);
|
||||
if (!(jResult.databaseUpdate && jResult.amazonUpdate)){
|
||||
alert('Database update : ' + jResult.databaseUpdate + '\r\nAmazon update : ' + jResult.amazonUpdate + '\r\nMessage : ' + jResult.amazonMessage);
|
||||
}
|
||||
});
|
||||
}catch(e){
|
||||
alert("exception");
|
||||
}
|
||||
|
||||
updateSkill(this.createSkill(newAllIntents)).then(l=>l.text()).then(result=>{
|
||||
let jResult = JSON.parse(result);
|
||||
console.log(jResult.result);
|
||||
console.log(jResult.message);
|
||||
}).catch(e=>{
|
||||
console.log("error : " + e);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
handleAddIntentClick(){
|
||||
|
||||
Reference in New Issue
Block a user