Merge pull request #7 from GotPPay/inconsistent-state-fix
Inconsistent state fix
This commit is contained in:
@@ -33,7 +33,7 @@ module.exports = {
|
|||||||
|
|
||||||
updateIntentsJSON: function () {
|
updateIntentsJSON: function () {
|
||||||
databaseHelper
|
databaseHelper
|
||||||
.loadSkill (config.SKILL_DB_ID)
|
.getSkill (config.SKILL_DB_ID)
|
||||||
.then (skill => {
|
.then (skill => {
|
||||||
skill.intents.map (intent => {
|
skill.intents.map (intent => {
|
||||||
alexaApp.intent (
|
alexaApp.intent (
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
var config = {};
|
var config = {};
|
||||||
|
|
||||||
config.dbURL = 'mongodb://localhost:27017/tellall';
|
config.DB_URL = 'mongodb://localhost:27017/tellall';
|
||||||
config.PORT = 5000;
|
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.TOKEN = 'Atza|IwEBIBe6gDqrrowEEav6N-_6s4NztYeP3oG8PGWmu8ZiZw6lbOh3wNla3TK6pY-VEpT1d8an-dVf_n3kXJzVFsNo_4xBfZyFHGoCTDTFjs3yBRul4PVdBOhwwiH3-sgRLcUofZbe2oE06GmTcbfYtaStfXpQI5dfpldfnsJg_CvhSA6AHb_snJT3F6lyXzbV076d_3cYUMJxFldJGnYcviNHHxjjmuQTD06hhGzCbAxxe9eBmkuopRsNfyedLT2UlKP_ublah9CUGA3AdIX_3Iuke82jMwGnNl9gv7pbaDNEjAbj7IQSl3B08uuREtJq-oTBOjALNXRvFxTJmQjZwXNf9eHC7fSHJDdEPdZQU0AcffRQObAyAkUuL6Jv39OHzhb3Q64-zzoyODqnJyLP5SQZ2JVF53Kc_cTBqjIc9pXljqe7yEVk6JDs7q1zKbBibx_AQm57TO79IzWyLBzBMlYL5HdTsqEfRzLeDw2tws-hGMgkx2HWfdbYnmf5Qb4SyIhzvmmdfPLg3MVKTxjIBu1rx0xf3n0PLZP1EO6jsJPoMRPg77Gm4oit5Zp6s37ek3A3Vxh-ntoASpkrkxGTG9kVtRNt';
|
||||||
|
|||||||
@@ -1,24 +1,30 @@
|
|||||||
const constants = {};
|
const constants = {};
|
||||||
|
|
||||||
constants.amazonResultCodes = {
|
constants.amazonResultCodes = {
|
||||||
ok:200,
|
OK:200,
|
||||||
accepted:202,
|
ACCEPTED:202,
|
||||||
badRequest:400,
|
BAD_REQUEST:400,
|
||||||
unauthorized:401,
|
UNAUTHORIZED:401,
|
||||||
notFound:404,
|
NOT_FOUND:404,
|
||||||
conflict:409,
|
CONFLICT:409,
|
||||||
payloadTooLarge:413
|
PAYLOAD_TOO_LARGE:413
|
||||||
}
|
}
|
||||||
|
|
||||||
constants.apiResultCodes = {
|
constants.apiResultCodes = {
|
||||||
genericError : -1,
|
GENERIC_ERROR : -1,
|
||||||
ok:0,
|
OK:0,
|
||||||
amazonError:1,
|
AMAZON_ERROR:1, //amazon api works, but error is some of the amazonResultCodes
|
||||||
databaseError:2,
|
AMAZON_FAIL:2, //amazon api doesn't work
|
||||||
IDLengthError:3,
|
DATABASE_ERROR:3,
|
||||||
|
NO_SKILL:4,
|
||||||
|
INCONSISTEN_STATE:5,
|
||||||
}
|
}
|
||||||
|
|
||||||
constants.skillIDLength = 24;
|
constants.HTTPResultCodes = {
|
||||||
|
INTERNAL_SERVER_ERROR : 500,
|
||||||
|
}
|
||||||
|
|
||||||
|
constants.SKILL_ID_LENGTH = 24;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ var alexa = require ('../components/alexa');
|
|||||||
router.get ('/:id', async (req, res, next) => {
|
router.get ('/:id', async (req, res, next) => {
|
||||||
const id = req.params.id;
|
const id = req.params.id;
|
||||||
|
|
||||||
if (id.length !== constants.skillIDLength) {
|
if (id.length !== constants.SKILL_ID_LENGTH) {
|
||||||
res.json ([]);
|
res.json ([]);
|
||||||
} else {
|
} else {
|
||||||
databaseHelper
|
databaseHelper
|
||||||
@@ -31,63 +31,66 @@ router.put ('/:id', bodyParser.json (), async (req, res, next) => {
|
|||||||
delete skill.updateOnAmazon;
|
delete skill.updateOnAmazon;
|
||||||
delete skill._id;
|
delete skill._id;
|
||||||
|
|
||||||
console.log ('id = ' + id);
|
//First get current skill from DB
|
||||||
|
databaseHelper
|
||||||
//TODO : Fix inconsistency ! If skill is sent to amazon and accepted, but
|
.getSkill (id)
|
||||||
//fails in database (ID doesn't exist)
|
.then (currentSkillState => {
|
||||||
if (id.length === constants.skillIDLength) {
|
//Now let's update skill in DB
|
||||||
if (updateOnAmazon) {
|
|
||||||
amazonHelper
|
|
||||||
.updateSkill (skill)
|
|
||||||
.then (amazonResult => {
|
|
||||||
console.log ('Amazon : ' + amazonResult);
|
|
||||||
if (
|
|
||||||
amazonResult === constants.amazonResultCodes.ok ||
|
|
||||||
amazonResult === constants.amazonResultCodes.accepted
|
|
||||||
) {
|
|
||||||
//Skill uploaded, it's ok to update databaseI
|
|
||||||
databaseHelper
|
|
||||||
.updateSkill (id, skill)
|
|
||||||
.then (result => {
|
|
||||||
res.json ({result: constants.apiResultCodes.ok, message: ''});
|
|
||||||
alexa.updateIntentsJSON ();
|
|
||||||
})
|
|
||||||
.catch (e => {
|
|
||||||
res.json ({
|
|
||||||
result: constants.apiResultCodes.databaseError,
|
|
||||||
message: '',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
res.json ({
|
|
||||||
result: constants.apiResultCodes.amazonError,
|
|
||||||
message: amazonResult,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch (e => {
|
|
||||||
res.json ({
|
|
||||||
result: constants.apiResultCodes.amazonError,
|
|
||||||
message: 'unknown',
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
databaseHelper
|
databaseHelper
|
||||||
.updateSkill (id, skill)
|
.updateSkill (id, skill)
|
||||||
.then (result => {
|
.then (() => {
|
||||||
res.json ({result: constants.apiResultCodes.ok, message: ''});
|
//Ok, done, now update skill on Amazon (if needed)
|
||||||
alexa.updateIntentsJSON ();
|
if (updateOnAmazon) {
|
||||||
|
amazonHelper
|
||||||
|
.updateSkill (skill)
|
||||||
|
.then (amazonResult => {
|
||||||
|
if (
|
||||||
|
amazonResult === constants.amazonResultCodes.OK ||
|
||||||
|
amazonResult === constants.amazonResultCodes.ACCEPTED
|
||||||
|
) {
|
||||||
|
res.json ({result: constants.apiResultCodes.OK, message: ''});
|
||||||
|
alexa.updateIntentsJSON ();
|
||||||
|
} else {
|
||||||
|
res.status(constants.HTTPResultCodes.INTERNAL_SERVER_ERROR).json ({
|
||||||
|
result: constants.apiResultCodes.AMAZON_ERROR,
|
||||||
|
message: amazonResult,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch (e => {
|
||||||
|
res.status(constants.HTTPResultCodes.INTERNAL_SERVER_ERROR).json ({
|
||||||
|
result: constants.apiResultCodes.AMAZON_FAIL,
|
||||||
|
message: e,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
res.json ({result: constants.apiResultCodes.OK, message: ''});
|
||||||
|
alexa.updateIntentsJSON ();
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch (e => {
|
.catch (() => {
|
||||||
res.json ({
|
//Update in database didn't go well, revert changes
|
||||||
result: constants.apiResultCodes.databaseError,
|
databaseHelper
|
||||||
message: '',
|
.updateSkill (id, currentSkillState)
|
||||||
});
|
.then (() => {
|
||||||
|
res.status(constants.HTTPResultCodes.INTERNAL_SERVER_ERROR).json ({
|
||||||
|
result: constants.apiResultCodes.DATABASE_ERROR,
|
||||||
|
message: '',
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch (() => {
|
||||||
|
//This should never happen, something is seriously wrong, like no database connection
|
||||||
|
res.status(constants.HTTPResultCodes.INTERNAL_SERVER_ERROR).json ({
|
||||||
|
result: constants.apiResultCodes.INCONSISTEN_STATE,
|
||||||
|
message: '',
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
})
|
||||||
} else {
|
.catch (e => {
|
||||||
res.json ({result: constants.IDLengthError, message: ''});
|
//I don't know why, but something went wrong, possibly ID of skill is wrong, doesn't exist in DB
|
||||||
}
|
res.status(constants.HTTPResultCodes.INTERNAL_SERVER_ERROR).json ({result: constants.apiResultCodes.NO_SKILL, message: ''});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
@@ -35,17 +35,20 @@ var refreshTokens = function () {
|
|||||||
};
|
};
|
||||||
|
|
||||||
request (options, function (error, response, body) {
|
request (options, function (error, response, body) {
|
||||||
if (error) reject (error);
|
if (error) {
|
||||||
parsedResponse = JSON.parse (body);
|
reject (error);
|
||||||
if (parsedResponse.refresh_token)
|
}else{
|
||||||
return databaseHelper.updateTokens (
|
parsedResponse = JSON.parse (body);
|
||||||
parsedResponse.refresh_token,
|
if (parsedResponse.refresh_token){
|
||||||
parsedResponse.access_token,
|
databaseHelper.updateTokens(parsedResponse.refresh_token, parsedResponse.access_token, parsedResponse.expires_in).then(()=>{
|
||||||
parsedResponse.expires_in
|
resolve();
|
||||||
);
|
}).catch(e=>{
|
||||||
console.log ('Token refresh failed');
|
reject(e);
|
||||||
console.log (body);
|
});
|
||||||
reject (body);
|
}else{
|
||||||
|
reject (body);
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -43,16 +43,19 @@ module.exports = {
|
|||||||
db
|
db
|
||||||
.collection ('token_list')
|
.collection ('token_list')
|
||||||
.update ({id: 1}, newTokenDocument, {upsert: true}, (err, result) => {
|
.update ({id: 1}, newTokenDocument, {upsert: true}, (err, result) => {
|
||||||
if (err) reject (err);
|
if (err) {
|
||||||
config.REFRESH_TOKEN = refresh_token;
|
reject (err)
|
||||||
config.TOKEN = access_token;
|
}else{
|
||||||
config.TOKEN_EXPIRES_IN = newTokenDocument.expires_in;
|
config.REFRESH_TOKEN = refresh_token;
|
||||||
resolve ();
|
config.TOKEN = access_token;
|
||||||
|
config.TOKEN_EXPIRES_IN = newTokenDocument.expires_in;
|
||||||
|
resolve ();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
loadSkill: function (skillDbID) {
|
getSkill: function (skillDbID) {
|
||||||
return new Promise ((resolve, reject) => {
|
return new Promise ((resolve, reject) => {
|
||||||
db
|
db
|
||||||
.collection ('skill_list')
|
.collection ('skill_list')
|
||||||
@@ -92,20 +95,5 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
getSkill: function (id) {
|
|
||||||
return new Promise ((resolve, reject) => {
|
|
||||||
db
|
|
||||||
.collection ('skill_list')
|
|
||||||
.find ({_id: ObjectID (id)})
|
|
||||||
.toArray ((err, result) => {
|
|
||||||
if (err) {
|
|
||||||
reject (err);
|
|
||||||
}else{
|
|
||||||
resolve (result);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
module.exports = function (req, res, next) {
|
module.exports = function (req, res, next) {
|
||||||
res.header ('Access-Control-Allow-Origin', '*');
|
res.header ('Access-Control-Allow-Origin', '*');
|
||||||
res.header ('Access-Control-Allow-Headers', 'Origin, Content-Type');
|
res.header ('Access-Control-Allow-Headers', 'Origin, Content-Type');
|
||||||
res.header ('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
res.header ('Access-Control-Allow-Methods', 'GET, POST, PUT');
|
||||||
res.header ('Access-Control-Allow-Credentials', 'true');
|
res.header ('Access-Control-Allow-Credentials', 'true');
|
||||||
next ();
|
next ();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ app.set ('view engine', 'ejs');
|
|||||||
app.use (require ('./middleware')); //common middleware for all requests
|
app.use (require ('./middleware')); //common middleware for all requests
|
||||||
app.use (require ('./controllers')); //all routes
|
app.use (require ('./controllers')); //all routes
|
||||||
|
|
||||||
MongoClient.connect (config.dbURL)
|
MongoClient.connect (config.DB_URL)
|
||||||
.then (database => {
|
.then (database => {
|
||||||
databaseHelper.initModule (database);
|
databaseHelper.initModule (database);
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,8 @@
|
|||||||
"watch-css": "nodemon -e scss -x \"npm run watch-css-mine\"",
|
"watch-css": "nodemon -e scss -x \"npm run watch-css-mine\"",
|
||||||
"start-js": "react-scripts start",
|
"start-js": "react-scripts start",
|
||||||
"start": "npm-run-all -p watch-css start-js",
|
"start": "npm-run-all -p watch-css start-js",
|
||||||
"build": "react-scripts build",
|
"react-build" : "react-scripts build",
|
||||||
|
"build": "npm-run-all -p build-css react-build",
|
||||||
"test": "react-scripts test --env=jsdom",
|
"test": "react-scripts test --env=jsdom",
|
||||||
"eject": "react-scripts eject"
|
"eject": "react-scripts eject"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -31,11 +31,10 @@ class App extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
getSkill(this.state._id).then(l=>l.json()).then(result=>{
|
getSkill(this.state._id).then(l=>l.json()).then(result=>{
|
||||||
let jResult = result[0];
|
if (result===undefined) return;
|
||||||
if (jResult===undefined) return;
|
this.setState({ skillID:result.skillID,skillName:result.skillName, invocationName: result.invocationName,
|
||||||
this.setState({ skillID:jResult.skillID,skillName:jResult.skillName, invocationName: jResult.invocationName,
|
invocationAnswer: result.invocationAnswer,
|
||||||
invocationAnswer: jResult.invocationAnswer,
|
allIntents: result.intents, contactEmail: result.contactEmail})
|
||||||
allIntents: jResult.intents, contactEmail: jResult.contactEmail})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
this.handleIntentClick = this.handleIntentClick.bind(this);
|
this.handleIntentClick = this.handleIntentClick.bind(this);
|
||||||
|
|||||||
@@ -28,13 +28,13 @@ class IntentDetails extends Component {
|
|||||||
id="intent name"
|
id="intent name"
|
||||||
lineDirection="center"
|
lineDirection="center"
|
||||||
placeholder="Intent name"
|
placeholder="Intent name"
|
||||||
label="Intent name"
|
label="Question name"
|
||||||
className="md-cell md-cell--bottom IntentDetailsInputBoxes"
|
className="md-cell md-cell--bottom IntentDetailsInputBoxes"
|
||||||
onChange={this.handleIntentNameEdit}
|
onChange={this.handleIntentNameEdit}
|
||||||
maxLength={INTENT_NAME_MAX_LENGTH}
|
maxLength={INTENT_NAME_MAX_LENGTH}
|
||||||
value={this.state.intent.intentName} />
|
value={this.state.intent.intentName} />
|
||||||
</div>
|
</div>
|
||||||
<h5 className="QuestionTitle">Questions</h5>
|
<h5 className="QuestionTitle">Question variants</h5>
|
||||||
{
|
{
|
||||||
this.state.intent.questions.map((question, index)=>{
|
this.state.intent.questions.map((question, index)=>{
|
||||||
return (
|
return (
|
||||||
@@ -68,8 +68,8 @@ class IntentDetails extends Component {
|
|||||||
}
|
}
|
||||||
<br></br>
|
<br></br>
|
||||||
<br></br>
|
<br></br>
|
||||||
<Button className="IntentDetailsButton" flat primary onClick={()=>{this.props.onDeleteIntentClick(this.state.intent)}} disabled={this.props.waiting}>Delete intent</Button>
|
<Button className="IntentDetailsButton" flat primary onClick={()=>{this.props.onDeleteIntentClick(this.state.intent)}} disabled={this.props.waiting}>Delete question</Button>
|
||||||
<Button className="IntentDetailsButton" flat primary swapTheming onClick={this.addQuestion} disabled={this.props.waiting}>Add question</Button>
|
<Button className="IntentDetailsButton" flat primary swapTheming onClick={this.addQuestion} disabled={this.props.waiting}>Add variant</Button>
|
||||||
<Button className="IntentDetailsButton" flat primary swapTheming onClick={()=>{this.props.onSaveIntentClick(this.state.intent)}} disabled={this.props.waiting}>Save</Button>
|
<Button className="IntentDetailsButton" flat primary swapTheming onClick={()=>{this.props.onSaveIntentClick(this.state.intent)}} disabled={this.props.waiting}>Save</Button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class IntentList extends Component {
|
|||||||
|
|
||||||
|
|
||||||
<div className="IntentList-title">
|
<div className="IntentList-title">
|
||||||
<h3>Intents</h3>
|
<h3>Questions</h3>
|
||||||
</div>
|
</div>
|
||||||
{
|
{
|
||||||
this.state.intents.map((intent,index)=>{
|
this.state.intents.map((intent,index)=>{
|
||||||
@@ -45,7 +45,7 @@ class IntentList extends Component {
|
|||||||
<br></br>
|
<br></br>
|
||||||
<Button className="AddIntent" flat primary swapTheming
|
<Button className="AddIntent" flat primary swapTheming
|
||||||
onClick={this.props.onAddIntentClick}
|
onClick={this.props.onAddIntentClick}
|
||||||
disabled={this.props.waiting}>Add intent</Button>
|
disabled={this.props.waiting}>Add question</Button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user