Merge pull request #7 from GotPPay/inconsistent-state-fix

Inconsistent state fix
This commit is contained in:
MirnaM
2018-01-16 17:05:21 +01:00
committed by GitHub
12 changed files with 116 additions and 116 deletions

View File

@@ -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 (

View File

@@ -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';

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);
}
}
}); });
}); });
}; };

View File

@@ -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);
}
});
});
},
}; };

View File

@@ -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 ();
}; };

View File

@@ -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);

View File

@@ -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"
}, },

View File

@@ -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);

View File

@@ -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>

View File

@@ -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>
); );
} }