SuiteScript 2.1 - Invalid Signature when creating TBA Access Token - oauth

Constantly getting Invalid Signature when trying to create a TBA access token.
The function to generate the OAuth1.0a signature is as follows:
const restletSignature = (options) => {
const HMAC_SHA256 = (key, text, output) => {
if ( !output) output = cryptoJS.enc.Base64;
return cryptoJS.HmacSHA256(text, key).toString(output);
};
const companyInfo = config.load({
type: config.Type.COMPANY_INFORMATION,
});
const makeNonce = () => {
var result = "", characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var charactersLength = characters.length;
for (var i = 0; i < this.nonce_length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
};
try {
log.debug('options', JSON.stringify(options));
if ( !options) {
options = {};
}
if ( !options.consumer) {
throw error.create({
name: 'MISSING_PARAMTER',
message: 'consumer option is required',
notifyOff: true,
});
}
if ( !options.token) {
throw error.create({
name: 'MISSING_PARAMTER',
message: 'token option is required',
notifyOff: true,
});
}
if ( !options.restletUrl) {
throw error.create({
name: 'MISSING_PARAMTER',
message: 'restletUrl option is required',
notifyOff: true,
});
}
if (typeof options.last_ampersand === 'undefined') {
this.last_ampersand = true;
}
else {
this.last_ampersand = options.last_ampersand;
}
this.httpMethod = options.httpMethod || "POST";
this.consumer = options.consumer;
this.token = options.token;
this.nonce_length = options.nonce_length || 32;
this.signature_method = options.signature_method || "HMAC-SHA256";
this.version = options.version || '1.0';
this.parameter_separator = options.parameter_separator || ', ';
this.realm = companyInfo.getValue({fieldId: "companyid"});
this.urls = {
system: "https://" + url.resolveDomain({hostType: url.HostType.APPLICATION}),
restlet: "https://" + url.resolveDomain({hostType: url.HostType.RESTLET}),
suitetalk: "https://" + url.resolveDomain({hostType: url.HostType.SUITETALK}),
forms: "https://" + url.resolveDomain({hostType: url.HostType.FORM}),
};
this.restletFullUrl = (options.restletUrl.indexOf("https://") == -1 ? urls.system : "") + options.restletUrl;
this.restletUrl = this.restletFullUrl.indexOf("?") > -1 ? this.restletFullUrl.split("?")[0] : "";
this.restletScript = this.restletFullUrl.match(/(?<=script\=)(.*)(?=\&deploy)/);
this.restletScript = this.restletScript.length ? this.restletScript[0] : null;
this.restletDeploy = this.restletFullUrl.match(/(?<=deploy\=)(.*)(?=\&)/);
this.restletDeploy = this.restletDeploy.length ? this.restletDeploy[0] : null;
this.encodedRestletUrl = encodeURIComponent(this.restletUrl);
this.parameters = {
deploy: this.restletDeploy,
oauth_consumer_key: this.consumer.key,
oauth_nonce: makeNonce(),
oauth_signature_method: this.signature_method,
oauth_timestamp: Math.round(+new Date() / 1000),
oauth_token: this.token.key,
oauth_version: "1.0",
script: this.restletScript,
};
this.encodedParameterString = '&deploy=' + encodeURIComponent(this.parameters.deploy);
this.encodedParameterString += '&oauth_consumer_key=' + encodeURIComponent(this.parameters.oauth_consumer_key);
this.encodedParameterString += '&oauth_nonce=' + encodeURIComponent(this.parameters.oauth_nonce);
this.encodedParameterString += '&oauth_signature_method=' + encodeURIComponent(this.parameters.oauth_signature_method);
this.encodedParameterString += '&oauth_timestamp=' + encodeURIComponent(this.parameters.oauth_timestamp);
this.encodedParameterString += '&oauth_token=' + encodeURIComponent(this.parameters.oauth_token);
this.encodedParameterString += '&oauth_version=' + encodeURIComponent(this.parameters.oauth_version);
this.encodedParameterString += '&script=' + encodeURIComponent(this.parameters.script);
this.encodedParameterString = encodeURIComponent(this.encodedParameterString);
this.baseString = this.httpMethod + "&";
this.baseString += this.encodedRestletUrl + "&";
this.baseString += this.encodedParameterString;
this.signatureKey = encodeURIComponent(this.consumer.secret) + "&" + encodeURIComponent(this.consumer.secret);
this.signature = encodeURIComponent(HMAC_SHA256(this.signatureKey,this.baseString, cryptoJS.enc.Base64 ) );
this.Authorization = "";
this.Authorization += 'OAuth oauth_signature="'+this.signature + '"'+this.parameter_separator;
this.Authorization += 'oauth_version="'+this.parameters.oauth_version + '"'+this.parameter_separator;
this.Authorization += 'oauth_nonce="'+this.parameters.oauth_nonce + '"'+this.parameter_separator;
this.Authorization += 'oauth_signature_method="'+this.parameters.oauth_signature_method + '"'+this.parameter_separator;
this.Authorization += 'oauth_consumer_key="'+this.parameters.oauth_consumer_key + '"'+this.parameter_separator;
this.Authorization += 'oauth_token="'+this.parameters.oauth_token + '"'+this.parameter_separator;
this.Authorization += 'oauth_timestamp="'+this.parameters.oauth_timestamp + '"'+this.parameter_separator;
this.Authorization += 'realm="'+this.realm + '"';
} catch (e) {
this.error = {
name: e.name,
message: e.message,
stack: e.stack,
};
} finally {
return this;
}
};
The Integration record has only "Token Based Authentication" ticked.
Consumer Key/Secret and Token ID/Secret are current, and I've tried setting them multiple times.
It's all running on Server Time (PST) so I don't think Timestamp zone is an issue, but I did try adding +36000 ms (for AEST) but no change.
Logging generates this data:
{
"auth": {
"last_ampersand": true,
"httpMethod": "POST",
"consumer": {
"key": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"secret": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
},
"token": {
"key": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"secret": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
},
"nonce_length": 32,
"signature_method": "HMAC-SHA256",
"version": "1.0",
"parameter_separator": ", ",
"realm": "XXXXXX",
"urls": {
"system": "https://XXXXXX.app.netsuite.com",
"restlet": "https://XXXXXX.restlets.api.netsuite.com",
"suitetalk": "https://XXXXXX.suitetalk.api.netsuite.com",
"forms": "https://XXXXXX.extforms.netsuite.com"
},
"restletFullUrl": "https://XXXXXX.restlets.api.netsuite.com/app/site/hosting/restlet.nl?script=576&deploy=1&compid=XXXXXX",
"restletUrl": "https://XXXXXX.restlets.api.netsuite.com/app/site/hosting/restlet.nl",
"restletScript": "576",
"restletDeploy": "1",
"encodedRestletUrl": "https%3A%2F%9999999.restlets.api.netsuite.com%2Fapp%2Fsite%2Fhosting%2Frestlet.nl",
"parameters": {
"deploy": "1",
"oauth_consumer_key": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"oauth_nonce": "58RInizRvCTdBGuXtugMRPhciQ0OC1xo",
"oauth_signature_method": "HMAC-SHA256",
"oauth_timestamp": 1639901494,
"oauth_token": "b49f1560e07771f8aad11418feae49be6162cf6fbd5d98bff0ae6aac70d4a30f",
"oauth_version": "1.0",
"script": "576"
},
"encodedParameterString": "%26deploy%3D1%26oauth_consumer_key%3XXXXXXXXXXXXXXXXXXXXXXXXXXXXX%26oauth_nonce%3D58RInizRvCTdBGuXtugMRPhciQ0OC1xo%26oauth_signature_method%3DHMAC-SHA256%26oauth_timestamp%3D1639901494%26oauth_token%3Db49f1560e07771f8aad11418feae49be6162cf6fbd5d98bff0ae6aac70d4a30f%26oauth_version%3D1.0%26script%3D576",
"baseString": "POST&https%3A%2F%2F9999999.restlets.api.netsuite.com%2Fapp%2Fsite%2Fhosting%2Frestlet.nl&%26deploy%3D1%26oauth_consumer_key%3DXXXXXXXXXXXXXXXXXXXXXXXXXXXXX%26oauth_nonce%3D58RInizRvCTdBGuXtugMRPhciQ0OC1xo%26oauth_signature_method%3DHMAC-SHA256%26oauth_timestamp%3D1639901494%26oauth_token%3Db49f1560e07771f8aad11418feae49be6162cf6fbd5d98bff0ae6aac70d4a30f%26oauth_version%3D1.0%26script%3D576",
"signatureKey": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX&XXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"signature": "U5iNYAo01jMm3WLdAHUH6R8M7tzooePZ3S0Jc5KQexQ%3D",
"Authorization": "OAuth oauth_signature=\"U5iNYAo01jMm3WLdAHUH6R8M7tzooePZ3S0Jc5KQexQ%3D\", oauth_version=\"1.0\", oauth_nonce=\"58RInizRvCTdBGuXtugMRPhciQ0OC1xo\", oauth_signature_method=\"HMAC-SHA256\", oauth_consumer_key=\"XXXXXXXXXXXXXXXXXXXXXXXXXXXXX\", oauth_token=\"b49f1560e07771f8aad11418feae49be6162cf6fbd5d98bff0ae6aac70d4a30f\", oauth_timestamp=\"1639901494\", realm=\"9999999\""
}
}

Related

How to do multi dynamic stream in one gulp task from object

I´m trying to copy files in gulp file dynamically based on json object.
I tried to use merge-stream package withou success.
const DEV_PATH = "./dev/";
const DIST_PATH = "./dist/";
const DEV_PATH_TOOLS = DEV_PATH + "tools/";
const DEV_PATH_COMMON = DEV_PATH + "common/";
const DIST_PATH_TOOLS = DIST_PATH + "tools/";
const TOOLS_DIST_PATH = [
{
"dir" : 'dir1',
"options" : {
"class" : [ "modules/csv/**/*" ]
}
},
{
"dir" : 'dir2',
"options" : {
"class" : [ "modules/csv/CsvImporter.php" ]
}
}
];
const gulp = require('gulp');
const plumber = require('gulp-plumber');
const merged = require('merge-stream')();
gulp.task( 'copy-class', function(){
TOOLS_DIST_PATH.map( t => function () {
var stream = new stream(
gulp.src( t.options.class.map( c => DEV_PATH_COMMON + c ))
.pipe(plumber({
handleError: function (err) {
console.log(err);
this.emit('end');
}
}))
.pipe( gulp.dest( DIST_PATH_TOOLS + t.dir + '/class' ) )
.pipe(plumber({
handleError: function (err) {
console.log(err);
this.emit('end');
}
}))
);
merged.add(stream);
});
return merged.isEmpty() ? null : merged;
});
gulp.task( 'default', gulp.series( 'copy-class' ) );
I got this error :
The following tasks did not complete: default, copy-class
Did you forget to signal async completion ?
It´s confused for me, someone can helps me ?
I found an answer
Const DEV_PATH = "./dev/";
const DIST_PATH = "./dist/";
const DEV_PATH_TOOLS = DEV_PATH + "tools/";
const DEV_PATH_COMMON = DEV_PATH + "common/";
const DIST_PATH_TOOLS = DIST_PATH + "tools/";
const TOOLS_DIST_PATH = [
{
"dir" : 'dir1',
"options" : {
"class" : [ "modules/csv/**/*" ]
}
},
{
"dir" : 'dir2',
"options" : {
"class" : [ "modules/csv/CsvImporter.php" ]
}
}
];
const gulp = require('gulp');
const plumber = require('gulp-plumber');
const merge= require('merge-stream');
function compileScripts(t) {
const classStream = gulp.src( t.options.class.map( c => DEV_PATH_COMMON + c ))
.pipe(plumber({
handleError: function (err) {
console.log(err);
this.emit('end');
}
}))
.pipe( gulp.dest( DIST_PATH_TOOLS + t.dir + '/class' ) )
.pipe(plumber({
handleError: function (err) {
console.log(err);
this.emit('end');
}
}))
/* TODO : when there wil be several options
return merge(classStream , otherStream );*/
return classStream;
}
gulp.task( 'copy-options', function(){
var streams = TOOLS_DIST_PATH.map( t => {
return compileScripts(t);
});
return merge(streams);
});
gulp.task( 'default', gulp.series( 'copy-options' ) );

Alexa skill testing error: Error handled: Cannot read property 'value' of undefined

Please help me if any body resolved the issue and below is my lambda funciton code.
when i comment all funcitons in exports.handler funciton and execute/test single function it is working but if we enable all funcitons then i am getting the error as Error handled: Cannot read property 'value' of undefined
Node JS code for alexa skill kit for different intents created.
GetNewFactHandler,
CreateJIRAIssueHandler,
UpdateJIRAIssueHandler,
GetJIRAIssueHandler,
GetJIRAIssueCountHandler,
/* eslint-disable func-names */
/* eslint-disable no-console */
var http = require('http');
var https = require('https');
var projectKey='';
var iType='';
var keyValueID='';
var userName='';
var IssueNumber='';
const Alexa = require('ask-sdk');
const GetNewFactHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'LaunchRequest'
|| (request.type === 'IntentRequest'
&& request.intent.name === 'GetNewFactIntent');
},
handle(handlerInput) {
const factArr = data;
const factIndex = Math.floor(Math.random() * factArr.length);
const randomFact = factArr[factIndex];
const speechOutput = GET_FACT_MESSAGE + randomFact;
return handlerInput.responseBuilder
.speak(speechOutput)
.withSimpleCard(SKILL_NAME, randomFact)
.getResponse();
},
};
var reqTimeout = 3000;
const CreateJIRAIssueHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
const proKey = request.intent.slots.PROJECTKEY.value;
const issueType = request.intent.slots.ISSUETYPE.value;
iType = capitalize_Words(issueType);
projectKey = proKey.toUpperCase();
return request.type === 'IntentRequest' &&
request.intent.name === 'CreateJIRAIssue';
},
async handle(handlerInput) {
const createIssue = await createJiraIssue(projectKey, iType);
const speechOutput = JSON.parse(createIssue).key;
return handlerInput.responseBuilder
.speak('Issue ' + speechOutput + ' created')
.getResponse();
},
};
function capitalize_Words(str) {
return str.replace(/\w\S*/g, function(txt) {
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
});
};
//mule real time server
var muleCreateIssuePath = '/jira/createissue';
var muleProtocol = 'https';
var createIssueMethod = 'POST';
var muleUpdateIssuePath = '/jira/issue/';
var updateIssueMethod = 'PUT';
var getIssueMethod = 'GET';
var MuleReqOpts = {
host: '',
port: 443,
path: undefined, // To be set.
method: undefined,
headers: {
'Content-Type': 'application/json'
},
agent: false,
// auth: jiraUsername + ':' + jiraPassword
auth: ''
};
var MuleHttp = muleProtocol === 'https' ? https : http;
function createJiraIssue(projectKey, iType) {
MuleReqOpts.path = muleCreateIssuePath;
MuleReqOpts.method = createIssueMethod;
var MuleReqBody = {
'fields': {
'project': {
'key': projectKey
},
'summary': 'Test Message',
'description': 'Issue created for alexa skill kit from Integration alexa to jira',
'issuetype': {
'name': iType // Make sure your JIRA project configuration(s) supports this Issue Type.
}
}
};
return doApiCall(MuleHttp, MuleReqOpts, MuleReqBody, 'creating issue', 201);
};
function doApiCall(httplib, reqOpts, reqBody, happening, successCode) {
return new Promise(((resolve, reject) => {
var req = httplib.request(reqOpts, (res) => {
res.setEncoding('utf8');
let returnData = '';
res.on('data', (chunk) => {
returnData += chunk;
});
res.on('end', () => {
resolve(returnData);
});
res.on('error', (error) => {
reject(error);
});
});
req.write(JSON.stringify(reqBody));
req.end();
req.on('error', function(err) {
context.done(new Error(' request error: ' + err.message));
});
req.setTimeout(reqTimeout, function() {
context.done(new Error(' request timeout after ' + reqTimeout + ' milliseconds.'));
});
}));
};
const UpdateJIRAIssueHandler = {
canHandle(handlerInput) {
console.log('1');
const request = handlerInput.requestEnvelope.request;
console.log('2');
userName = request.intent.slots.USER.value;
var keyValue = request.intent.slots.PROJECTKEY.value;
console.log('keyValue : ' + keyValue);
keyValueID = keyValue.toUpperCase();
IssueNumber = request.intent.slots.ISSUENUMBER.value;
let INumber = Number(IssueNumber);
console.log('IssueNumber value: '+INumber);
console.log('key value id: ' + keyValueID);
return request.type === 'IntentRequest' &&
request.intent.name === 'UpdateJIRAIssue';
},
async handle(handlerInput) {
const updateIssue = await updateJiraIssue(userName);
console.log('updateIssue log: ' + updateIssue);
const speechOutput = JSON.parse(updateIssue).responseMessage;
console.log('speechOutput log: ' + speechOutput);
return handlerInput.responseBuilder
.speak(speechOutput)
.getResponse();
},
};
function updateJiraIssue(userName) {
console.log('inside method: ' +userName);
MuleReqOpts.method = updateIssueMethod;
var postdata = {
"fields": {
"assignee": {
"name": userName
}
}
}
return doApiUpdateCall(MuleHttp, MuleReqOpts, postdata, 'updating issue', 201);
};
function doApiUpdateCall(httplib, options, postdata, happening, successCode) {
options.path = muleUpdateIssuePath + keyValueID +'-'+IssueNumber ;
return new Promise(((resolve, reject) => {
var req = httplib.request(options, (res) => {
console.log(options);
res.setEncoding('utf8');
let returnData = '';
res.on('data', (body) => {
returnData += body;
console.log(returnData);
});
res.on('end', () => {
resolve(returnData);
});
console.log('1');
console.log('Body: ');
});
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
var jirapostString = JSON.stringify(postdata);
console.log(jirapostString);
req.write(jirapostString);
req.end();
}));
};
const GetJIRAIssueHandler = {
canHandle(handlerInput) {
console.log('1');
const request = handlerInput.requestEnvelope.request;
var keyValue = request.intent.slots.Issue.value;
console.log('keyValue: ' + keyValue);
keyValueID = keyValue.toUpperCase();
return request.type === 'IntentRequest' &&
request.intent.name === 'GetJIRAIssue';
},
async handle(handlerInput) {
const getIssue = await GetJIRAIssue();
console.log('getIssue log: ' + getIssue);
const assigneeName = JSON.parse(getIssue).fields.assignee.name;
const key = JSON.parse(getIssue).fields.assignee.key;
const reporterName = JSON.parse(getIssue).fields.reporter.name;
const issueType = JSON.parse(getIssue).fields.issuetype.name;
const projectName = JSON.parse(getIssue).fields.project.name;
const summaryDetails = JSON.parse(getIssue).fields.summary;
const speechOutput = 'Here are the issue details summary: Assignee : ' + assigneeName.concat(' ,reporter : ' + reporterName, ' ,Issue Key : ' + key, ' ,IssueType : ' + issueType, ' ,ProjectName : ' + projectName, ' ,Summary : ' + summaryDetails);
console.log('speechOutput log: ' + speechOutput);
return handlerInput.responseBuilder
.speak(speechOutput)
.getResponse();
},
};
function GetJIRAIssue() {
MuleReqOpts.method = getIssueMethod;
return doApiGetIssueCall(MuleHttp, MuleReqOpts, 'get issue details', 201);
};
function doApiGetIssueCall(httplib, options, happening, successCode) {
options.path = muleUpdateIssuePath + keyValueID;
return new Promise(((resolve, reject) => {
https.get(options, (res) => {
console.log(options);
res.setEncoding('utf8');
let returnData = '';
res.on('data', (body) => {
returnData += body;
console.log('response :', returnData);
});
res.on('end', () => {
resolve(returnData);
});
});
}));
};
const GetJIRAIssueCountHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
userName = request.intent.slots.USER.value;
console.log('userName Value: ' + userName);
const issueType = request.intent.slots.ISSUETYPE.value;
iType = capitalize_Words(issueType);
return request.type === 'IntentRequest' &&
request.intent.name === 'GetJIRAIssueCount';
},
async handle(handlerInput) {
const getIssueCount = await GetJIRAIssueCount();
console.log('getIssue log: ' + getIssueCount);
const total = JSON.parse(getIssueCount).total;
const speechOutput = ('Here is the '+iType+' count details: ' +total );
console.log('speechOutput log: ' + speechOutput);
return handlerInput.responseBuilder
.speak(speechOutput)
.getResponse();
},
};
function GetJIRAIssueCount() {
MuleReqOpts.method = getIssueMethod;
return doApiGetIssueCountCall(MuleHttp, MuleReqOpts, 'get issue count details', 201);
};
function doApiGetIssueCountCall(httplib, options, happening, successCode) {
options.path = muleUpdateIssuePath + userName +'/'+iType;
return new Promise(((resolve, reject) => {
https.get(options, (res) => {
console.log(options);
res.setEncoding('utf8');
let returnData = '';
res.on('data', (body) => {
returnData += body;
console.log('response :', returnData);
});
res.on('end', () => {
resolve(returnData);
});
});
}));
};
const HelpHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest'
&& request.intent.name === 'AMAZON.HelpIntent';
},
handle(handlerInput) {
return handlerInput.responseBuilder
.speak(HELP_MESSAGE)
.reprompt(HELP_REPROMPT)
.getResponse();
},
};
const ExitHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest'
&& (request.intent.name === 'AMAZON.CancelIntent'
|| request.intent.name === 'AMAZON.StopIntent');
},
handle(handlerInput) {
return handlerInput.responseBuilder
.speak(STOP_MESSAGE)
.getResponse();
},
};
const SessionEndedRequestHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'SessionEndedRequest';
},
handle(handlerInput) {
console.log(`Session ended with reason: ${handlerInput.requestEnvelope.request.reason}`);
return handlerInput.responseBuilder.getResponse();
},
};
const ErrorHandler = {
canHandle() {
return true;
},
handle(handlerInput, error) {
console.log(`Error handled: ${error.message}`);
return handlerInput.responseBuilder
.speak('Sorry, an error occurred.')
.reprompt('Sorry, an error occurred.')
.getResponse();
},
};
const SKILL_NAME = 'Space Facts';
const GET_FACT_MESSAGE = 'Here\'s your fact: ';
const HELP_MESSAGE = 'You can say tell me a space fact, or, you can say exit... What can I help you with?';
const HELP_REPROMPT = 'What can I help you with?';
const STOP_MESSAGE = 'Goodbye!';
const data = [
'A year on Mercury is just 88 days long.',
'Despite being farther from the Sun, Venus experiences higher temperatures than Mercury.',
'Venus rotates counter-clockwise, possibly because of a collision in the past with an asteroid.',
'On Mars, the Sun appears about half the size as it does on Earth.',
'Earth is the only planet not named after a god.',
'Jupiter has the shortest day of all the planets.',
'The Milky Way galaxy will collide with the Andromeda Galaxy in about 5 billion years.',
'The Sun contains 99.86% of the mass in the Solar System.',
'The Sun is an almost perfect sphere.',
'A total solar eclipse can happen once every 1 to 2 years. This makes them a rare event.',
'Saturn radiates two and a half times more energy into space than it receives from the sun.',
'The temperature inside the Sun can reach 15 million degrees Celsius.',
'The Moon is moving approximately 3.8 cm away from our planet every year.',
];
const skillBuilder = Alexa.SkillBuilders.custom();
exports.handler = skillBuilder
.addRequestHandlers(
GetNewFactHandler,
CreateJIRAIssueHandler,
UpdateJIRAIssueHandler,
GetJIRAIssueHandler,
GetJIRAIssueCountHandler,
HelpHandler,
ExitHandler,
SessionEndedRequestHandler
)
.addErrorHandlers(ErrorHandler)
.lambda();
Check all of your code for instances where you are looking for someObject.someNestedProperty.value.
I suspect that your slot values in your Intents are not the same as defined in your model/some-LANG.json file. Trying to access value property from someObject without a someNestedProperty will cause your error (i.e. request.intent.slots.PROJECTKEY.value).
If this is a Alexa-hosted skill, CloudWatch logging is built right in. Open the Alexa Developer Console, edit your skill, then go to the Code tab. On the bottom left, you should see a link for Logs: Amazon CloudWatch. You can log anything you want with a simple console.log() statement.
Also, be aware that the ask-sdk-core npm package contains helper methods to get slotValues (among other great tools). For more information, see this link: https://developer.amazon.com/en-US/docs/alexa/alexa-skills-kit-sdk-for-nodejs/utilities.html
Thanks all for your suggestions and prompt response.
Now the issue is resolved and the solution is the addRequestHandlers method will execute methods sequentially even if you execute/trigger third handler it will execute 1st and 2nd and goes to 3rd one. Here the issue is when you trigger a 3rd handler command from alexa it will passs the slot values related to the 3rd handler utterance and hence the 1st and 2nd haldler having slot values are not able to resolve and failed. so i put a condition overthere to skip 1st and 2nd handler execution and it worked.

IE 11 changing URL

I am getting strange behaviour in IE 11.
When I go to my web application using URL
"hostname:port/myapp-web/app/login.jsp"
The login page is displayed, And Login is done successfully.
Now. Problem is that, after logging in, App's landing page is index.html.
So URL should be "hostname:port/myapp-web/app/index.html"
Instead, IE changes it to "hostname:port///index.html"
Now, when I try to do any other operation or navigation, it fails because base URL is changed and my JS code cannot find app context root and all AJAX calls fails.
I tried searching over internet for the same, but couldn;t find any answer.
Please help if anyone has idea about such behaviour.
P.S. App is working fine in IE: 8/9, Chrome and FF.
I found something related to UTF-* character URLs but my app uses plain text URL with NO special characters.
App is developed using Spring for server side and KnockoutJS, HTML for UI.
Thanks in advance for the help.
index.html:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=9; IE=8; IE=EDGE" />
<!-- script includes -->
</head>
<body>
<!-- NavigationBar -->
</body>
<script type="text/javascript">
app.initialize(); // app.js
$.getJSON('/myapp-web/Security/authorise', function (response) {
app.common.navbar.reRenderNavBar(response);
app.navigation = new Navigation("AdminHome"); // navigation.js
// This navigation causes IE11 to change URL to http://host:port///#AdminHome
// it should be // http://host:port/myapp-web/app/index.html#AdminHome
});
</script>
</html>
Navigation.js
var ua = window.navigator.userAgent
var msie = ua.indexOf("MSIE ")
var ieVer = -1;
if (msie > 0) {
var ieVer = ua.substring(msie + 5, ua.indexOf(".", msie));
//console.log(ieVer);
}
var NavigationInput = function (pName, pValue) {
this.paramName = pName;
this.paramValue = pValue;
this.toString = function () {
return pName + ":" + pValue;
}
}
var Navigation = function (startupView) {
var self = this;
this.navInput = [];
this.navViewModel = null;
this.navViewModelInitComplete = false;
// this.navigate = function navigate(view) {
//
// if (view !== this.currentView) {
// self.loadView(view, true, null);
// }
// }
this.navigateWithParams = function navigateWithParams(view, params) {
self.loadView(view, true, params);
}
this.goBack = function goBack() {
history.go(-1);
//history.back();
}
this.loadView = function (view, pushHistory, params) {
var contentframe = $("#content");
//app.consolePrintInfo("navigation", "previous view: " + self.currentView + " new view: " + view);
if (typeof (self.currentView) != 'undefined' && self.currentView
&& self.currentView.toLowerCase() == view.toLowerCase()
&& isParamsEqual(params)) {
return;
}
var constructedView;
constructedView = "Views/" + view + "/" + view + ".html"
contentframe.load(constructedView, function () {
self.currentView = view;
modUrl = view;
if (params != null) {
if (params instanceof String) {
modUrl = params;
}
else {
var queryStr = self.convertParamsToQueryString(params);
modUrl += "?" + queryStr;
}
// if (typeof(app.navigation.navViewModel) != 'undefined'
// && app.navigation.navViewModel
// && !app.navigation.navViewModelInitComplete)
// {
// app.navigation.navViewModelInitComplete = app.navigation.navViewModel.initViewModel(self.convertQueryStringToParams(modUrl));
// }
}
if (pushHistory) {
if (ieVer > 6) {
window.history.pushState(view, null, modUrl);
}
else {
window.history.pushState(view, null, "#" + modUrl);
}
}
app.consolePrintInfo("navigation", "modified url:" + modUrl + " view model: " + app.navigation.navViewModel);
var navInputs = self.convertQueryStringToParams(modUrl);
self.urlInputs = navInputs;
app.navigation.navViewModelInitComplete = app.navigation.navViewModel.initViewModel(navInputs);
//$.getScript("Views/" + view + ".js", function () {
//});
});
isParamsEqual = function (iParams) {
if ((typeof(self.urlInputs) == 'undefined' || !self.urlInputs)
&& (typeof(iParams) == 'undefined' || !iParams)) {
return true;
}
else if (app.utility.isObjectNull(self.urlInputs) && app.utility.isObjectNull(iParams)) {
return true;
}
else {
return false;
}
}
}
this.convertParamsToQueryString = function (params) {
var result = "";
for (var i = 0; i < params.length; i++) {
if (i > 0) {
result += "&";
}
result += params[i].paramName + "=" +
params[i].paramValue;
}
return result;
};
this.convertQueryStringToParams = function (modUrl) {
var inputs = null;
var fragments = modUrl.split("?");
if (fragments && fragments.length == 2) {
var f = fragments[1].split("&");
if (f && f.length > 0) {
for (var i = 0; i < f.length; i++) {
var inp = f[i].split("=");
if (inputs == null) inputs = [];
inputs.push(new NavigationInput(inp[0], inp[1]));
}
}
}
return inputs;
};
this.back = function () {
if (history.state) {
var view = self.getView();
self.loadView(view, false, self.convertQueryStringToParams(location.href));
} else {
var view = self.getView();
self.loadView(view, true, self.convertQueryStringToParams(location.href));
}
};
this.getView = function () {
var fragments = location.href.split('#');
if (fragments && fragments.length === 2) {
var inFrag = fragments[1].split('?');
if (inFrag && inFrag.length === 2) {
return inFrag[0];
}
else {
return fragments[1];
}
} else {
return startupView;
}
};
this.loadView(this.getView(), true, this.convertQueryStringToParams(location.href));
$(window).on('popstate', self.back);
}
app.js:
-----------------
app = {};
// utilities
app.utility = {};
app.ui = {};
// common
app.common = {};
// validation
app.validation = {};
// common components
app.common.navbar = {};
app.common.authorisation = {};
app.initialize = function () {
$.blockUI.defaults.message = '<h4><img src="images/busy.gif" /> Processing...</h4>';
$.blockUI.defaults.css.border = '2px solid #e3e3e3';
$(document).ajaxStart($.blockUI).ajaxStop($.unblockUI);
//$(document).click(function() { $(".popover").remove(); });
}
app.consolePrintInfo = function (tag, message) {
if (typeof(console) != 'undefined' && console)
console.info(tag + ": " + message);
}
app.ui.showAppError = function (message) {
app.consolePrintInfo("App", "displaying error message: " + message);
$('#error-console').removeClass('app-error-console-hidden');
$('#error-console').removeClass('alert-info');
$('#error-console').addClass('alert-error');
$('#error-console').html(message);
}
app.ui.showAppInfo = function (message) {
app.consolePrintInfo("App", "displaying info message: " + message);
$('#error-console').show();
$('#error-console').removeClass('app-error-console-hidden');
$('#error-console').removeClass('alert-error');
$('#error-console').addClass('alert-info');
$('#error-console').html(message);
$('#error-console').fadeOut(4000);
}
app.utility.addQueryParameter = function (url, paramName, paramValue) {
var rUrl = url;
if (typeof(paramName) != 'undefined' && paramName
&& typeof(paramValue) != 'undefined' && paramValue) {
if (rUrl.indexOf("?") != -1) {
rUrl = rUrl + "&" + paramName + "=" + paramValue;
}
else {
rUrl = rUrl + "?" + paramName + "=" + paramValue;
}
}
return rUrl;
}
app.utility.addSearchParameter = function (paramName, paramValue) {
var rValue = undefined;
if (typeof(paramName) != 'undefined' && paramName
&& typeof(paramValue) != 'undefined' && paramValue) {
rValue = paramName + ":" + paramValue;
}
return rValue;
}
app.utility.searchParameter = function (inputKeyArray, paramName) {
if (inputKeyArray instanceof Array) {
for (var i = 0; i < inputKeyArray.length; i++) {
if (inputKeyArray[i].paramName == paramName) {
return inputKeyArray[i].paramValue;
}
}
}
return undefined;
}
app.utility.isObjectNull = function (obj) {
return typeof(obj) == 'undefined' || obj == undefined || !obj;
}
app.utility.isObjectNotNull = function (obj) {
return typeof(obj) != 'undefined' && obj;
}
app.utility.isFunction = function (obj) {
return !!(obj && obj.constructor && obj.call && obj.apply);
};
app.utility.parseError = function (em) {
if (!app.utility.isObjectNull(em)) {
jem = JSON.parse(em);
var keyArray = new Array();
keyArray.push(jem.errorCode);
keyArray.push(jem.errorMessage);
return keyArray;
}
else {
return undefined;
}
}
app.utility.showAppErrorDialog = function (errTitle, errMessage) {
if (!app.utility.isObjectNull(errMessage)) {
var $message = $("Error:" + errMessage)
.dialog({autoOpen: false, width: 300, title: errTitle, modal: true, buttons: {
Ok: function () {
$(this).dialog("close");
}
}}
);
$message.dialog('open');
}
}
app.utility.showErrorDialog = function (err) {
if (!app.utility.isObjectNull(err)) {
var $message = $('<div><p>Unfortunately, there has been error in the server!</p><p>' + err[1] + '</p><p>Please send the screenshot to developer team</div>')
.dialog({autoOpen: false, width: 300, title: err[0], modal: true, buttons: {
Ok: function () {
$(this).dialog("close");
}
}}
);
$message.dialog('open');
}
}
app.utility.showDialog = function (heading, text) {
if (!app.utility.isObjectNull(heading) && !app.utility.isObjectNull(text)) {
var $message = $('<div><p>' + text + '</p></div>')
.dialog({autoOpen: false, width: 300, title: heading, modal: true, buttons: {
Ok: function () {
$(this).dialog("close");
}
}}
);
$message.dialog('open');
}
}
app.utility.populateToolTip = function () {
$("img[id^='tooltip']").each(function () {
var idName = $(this).attr("id");
$('#' + idName).tooltip('toggle');
$('#' + idName).tooltip('hide');
});
};
app.utility.isNotEmptyNumberValue = function (input) {
if (app.utility.isObjectNull(input)) {
return true;
}
if (!isNaN(input) && isFinite(input) && ("" + input).indexOf("-") == -1 && ("" + input).indexOf("e") == -1) {
return true;
}
return false;
};
app.utility.isNotEmptyWholeNumberValue = function (input) {
if (app.utility.isObjectNull(input)) {
return true;
}
if (!isNaN(input) && isFinite(input) &&
("" + input).indexOf("-") == -1 && ("" + input).indexOf(".") == -1 && ("" + input).indexOf("e") == -1) {
return true;
}
return false;
};
app.utility.isNumberValue = function (input) {
if (!isNaN(input) && isFinite(input)) {
return true;
}
return false;
};
app.utility.doHttpRequest = function (input) {
if (app.utility.isObjectNull(input) || app.utility.isObjectNull(input.rURL)) {
app.utility.showDialog("Error!", "Unable to find required inputs. Error in sending request");
return false;
}
app.consolePrintInfo("HTTP REQUEST: ", "[URL] :" + input.rURL);
app.consolePrintInfo("HTTP REQUEST: ", "[Type] :" + input.rType);
app.consolePrintInfo("HTTP REQUEST: ", "[Input] :" + input.rDataToSend);
$.ajax({
url: input.rURL,
type: input.rType,
contentType: 'application/json',
cache: false,
data: input.rDataToSend,
dataType: 'json'
}).success(function (response) {
app.consolePrintInfo("HTTP REQUEST: ", "[Output - success] :" + JSON.stringify(response));
if (!app.utility.isObjectNull(input.rOnSuccessFunction)) {
input.rOnSuccessFunction(response);
}
else if (!app.utility.isObjectNull(input.rOnSuccessMessage)) {
app.utility.showDialog("Complete", input.rOnSuccessMessage);
}
}).error(function (response) {
if (response.status == 401) {
// session expired. redirect to login page.
app.consolePrintInfo("HTTP REQUEST: ", "[Output - failure] : Session Expired");
var $message = $('<div><p>' + response.responseText + '</p></div>')
.dialog({autoOpen: false, width: 300, title: 'Session Expired', modal: true, buttons: {
Ok: function () {
$(this).dialog("close");
// Remove the cached data
//comp_storage.remove("lastStoredValue");
//comp_storage.remove("permissionStr");
//window.open("/aid-web/logout", "_self");
app.utility.doLogout();
}
}}
);
$message.dialog('open');
}
else if (response.status == 400) {
app.consolePrintInfo("HTTP REQUEST: ", "[Output - failure] : Server Error");
var $message = $('<div><p>' + response.responseText + '</p></div>')
.dialog({autoOpen: false, width: 300, title: 'Server Error', modal: true, buttons: {
Ok: function () {
$(this).dialog("close");
}
}}
);
$message.dialog('open');
}
else {
app.consolePrintInfo("HTTP REQUEST: ", "[Output - failure] :" + response.responseText);
if (!app.utility.isObjectNull(input.rOnErrorFunction)) {
input.rOnErrorFunction(response.responseText);
}
else if (!app.utility.isObjectNull(input.rOnErrorMessage)) {
app.utility.showDialog("Error", input.rOnErrorMessage);
}
}
});
};
app.utility.doLogout = function () {
comp_storage.remove("lastStoredValue");
comp_storage.remove("permissionStr");
window.open("/aid-web/logout", "_self");
};
// common
// Nav bar component
app.common.navbar.reRenderNavBar = function (content) {
// [SAMPLE] To update the common component. create a view model of that
// component. set the needed variables.
// and *definately call applyBindings()*
app.common.navbar.navBarViewModel = new ko.navBarComponent.viewModel({
// set compt. values if needed. like below.
//navBarComponent_isEmpty:ko.observable(false)
});
app.common.navbar.navBarViewModel.navBarComponent_reRender(content);
ko.applyBindings(app.common.navbar.navBarViewModel, $('#nav-bar').get(0));
}
// Authorisation component
app.common.authorisation.storeRoleInfo = function (permissionArr) {
comp_auth.storeRoleInfo(permissionArr);
};
app.common.authorisation.isRolePresent = function (roleName) {
return comp_auth.isRolePresent(roleName);
};
// validation
app.validation.highlightElement = function (id, text) {
}
app.validation.highlightError = function (eleId, heading, text) {
if (!app.utility.isObjectNull(heading) && !app.utility.isObjectNull(text) && !app.utility.isObjectNull(eleId)) {
$("#" + eleId).addClass("ui-state-error");
var $message = $('<div><p>' + text + '</p></div>')
.dialog({
autoOpen: true,
width: 300,
title: heading, modal: true,
close: function () {
setTimeout(function () {
jQuery("#" + eleId).removeClass("ui-state-error");
}, 500);
},
buttons: {
Ok: function () {
$(this).dialog("close");
setTimeout(function () {
jQuery("#" + eleId).removeClass("ui-state-error");
}, 500);
}
},
overlay: {
opacity: 0.1,
},
}
).parent().addClass("ui-state-error");
}
}

Jquery autocomplete Select not working

i want to select the Autocomplete box item list . but it is not working . i have write this code to get the item. whenever i use self._renderItemData = function (ul, item) this function customized way the selection stops and when i comment this function my code works fine . please help me to know where am i wrong. i have used jquery ui 1.9 to write the code.
$(document).ready(function () {
var term = "";
var type = "";
var key = "";
$("#searchTextBox").autocomplete({
minLength: 2,
autoFocus: true,
source: function (request, response) {
$.ajax({
url: "../CustomHandlers/SearchHandler.ashx",
dataType: "json",
contentType: 'application/json; charset=utf-8',
data: { term: request.term },
success: function (data) {
if (!data || data.length == 0) {
response([{
label: "noMatched",
hcount:0,
type: "noResult",
key: "noResult"
}]);
}
else {
response($.map(data, function(item) {
return {
label: item.label,
hcount:item.record,
type: item.type,
key: item.key
}
}))
}
}
});
$.ui.autocomplete.prototype._renderMenu=function (ul, items) {
var self = this;
currentType = "";
$.each(items, function (index, item) {
if (item.type != currentType) {
ul.append("<li class='ui-autocomplete-type'>" + item.type + "</li>");
currentType = item.type;
}
self._renderItemData(ul, item);
});
self._renderItemData = function (ul, item) {
var searchhtml = "<a class='autocomplitList'>" + item.label + "<span>" + "(" + item.hcount + ") " + "</span>" + "</a>";
return $("<li></li>")
.data("item.autocomplete", item)
.append(searchhtml)
.appendTo(ul);
};
}
}
, select: function (event, ui)
{
term = ui.item.label;
type = ui.item.type;
key = ui.item.key;
// ui.item.option.selected = true;
// $("#searchTextBox").val(ui.item.label);
// return false;
//var selectedObj = ui.item.key;
// alert("Selected: " + selectedObj);
}
,open: function (event, ui) {
//event.addClass("nodis");
}
,close: function () {
// event.removeClass("nodis")
this._trigger("close");
}
});
Try this
$(document).ready(function() {
var term = "";
var type = "";
var key = "";
$.ui.autocomplete.prototype._renderMenu = function(ul, items) {
var self = this;
currentType = "";
$.each(items, function(index, item) {
if (item.type != currentType) {
ul.append("<li class='ui-autocomplete-type'>"
+ item.type + "</li>");
currentType = item.type;
}
self._renderItemData(ul, item);
});
self._renderItemData = function(ul, item) {
var searchhtml = "<a class='autocomplitList'>" + item.label
+ "<span>" + "(" + item.hcount + ") " + "</span>" + "</a>";
return $("<li></li>").data("item.autocomplete", item)
.append(searchhtml).appendTo(ul);
};
}
$("#searchTextBox").autocomplete({
minLength : 2,
autoFocus : true,
source : function(request, response) {
response([{
label : "Value 1",
hcount : 0,
type : "t1",
key : "v1"
}, {
label : "Value 2",
hcount : 0,
type : "t1",
key : "v2"
}, {
label : "Value 3",
hcount : 0,
type : "t2",
key : "v3"
}, {
label : "Value 4",
hcount : 0,
type : "t3",
key : "v4"
}]);
}
,
select : function(event, ui) {
term = ui.item.label;
type = ui.item.type;
key = ui.item.key;
// ui.item.option.selected = true;
// $("#searchTextBox").val(ui.item.label);
// return false;
// var selectedObj = ui.item.key;
// alert("Selected: " + selectedObj);
},
open : function(event, ui) {
// event.addClass("nodis");
},
close : function() {
// event.removeClass("nodis")
this._trigger("close");
}
});
$("#searchTextBox").data('autocomplete')._renderMenu = function(ul, items) {
var that = this;
var currentType = "";
$.each(items, function(index, item) {
if (item.type != currentType) {
ul.append("<li class='ui-autocomplete-type'>"
+ item.type + "</li>");
currentType = item.type;
}
$("<li></li>").addClass('newp').append($("<a></a>")
.text(item.label)).appendTo(ul).data(
"ui-autocomplete-item", item);;
});
}
});
Demo: Fiddle

why jquery autocomplete doesnt work on https (secure pages)?

I am trying to make jquery autocomplete to be work on https (secured pages) pages but its not showing any dropdown.
I searched on this issue and found that its security issue.
can any one tell me how to turn on this autocomplete dropdown on https pages.
here is my code to jquery autocomplete :
function zipAutoCompletet(prefix) {
jQuery("#" + prefix + "_zip").autocomplete({
source: function (request, response) {
jQuery.ajax({
url: "http://ws.geonames.org/postalCodeSearchJSON",
dataType: "jsonp",
data: {
style: "full",
maxRows: 12,
postalcode_startsWith: request.term
},
success: function (data) {
response(jQuery.map(data.postalCodes, function (item) {
return {
label: item.placeName + (item.adminCode1 ? ", " + item.adminCode1 : "") + ", " + item.postalCode + ", " + item.countryCode,
value: item.postalCode
}
}));
jQuery('.ui-autocomplete').css('width', '188px');
}
});
},
minLength: 2,
select: function (event, ui) {
var myString = new String(ui.item.label);
var address = myString.split(',')
jQuery('#' + prefix + '_city').val(address[0]);
jQuery('#' + prefix + '_city').addClass('activated');
jQuery('#' + prefix + '_city').trigger('change');
jQuery('#' + prefix + '_city').parents('.row').removeClass('error-row')
jQuery('#' + prefix + '_city').parents('.row').addClass('ok-row')
var countryCode = address[3] ? address[3] : address[2]
countryCode = jQuery.trim(countryCode);
var countryName = jQuery('#' + prefix + '_country option[value="' + jQuery.trim(countryCode) + '"]').text()
jQuery('#countryContainer .jqTransformSelectWrapper span').html(countryName)
jQuery('#countryContainer .jqTransformSelectWrapper').addClass('selected-jqtranform');
jQuery('#' + prefix + '_country').parents('.row').addClass('ok-row')
jQuery('#' + prefix + '_country').parents('.row').removeClass('error-row')
jQuery('#' + prefix + '_country').val(jQuery.trim(countryCode))
var stateCode = address[2] ? address[1] : '';
stateCode = jQuery.trim(stateCode)
if (countryCode == 'US') {
var base = base_url;
base = base.replace("https", "http");
jQuery.ajax({
url: base + "/getStateName",
dataType: "jsonp",
data: {
stateCode: stateCode
},
success: function (data) {
stateName = data
jQuery('#jc_state').val(stateName);
jQuery('#jc_state').addClass('activated');
jQuery('#jc_state').parents('.row').removeClass('error-row')
jQuery('#jc_state').parents('.row').addClass('ok-row')
jQuery('#jc_state').trigger('change');
formValidate();
}
});
} else {
stateName = stateCode
jQuery('#jc_state').val(stateName);
jQuery('#jc_state').addClass('activated');
jQuery('#jc_state').parents('.row').removeClass('error-row')
jQuery('#jc_state').parents('.row').addClass('ok-row')
jQuery('#jc_state').trigger('change');
formValidate();
}
jQuery('#' + prefix + '_zip').parents('.row').addClass('ok-row')
jQuery('#' + prefix + '_zip').parents('.row').removeClass('error-row');
},
open: function () {
jQuery(this).removeClass("ui-corner-all").addClass("ui-corner-top");
},
close: function () {
jQuery(this).removeClass("ui-corner-top").addClass("ui-corner-all");
},
change: function (event, ui) {
if (ui.item === null) {
jQuery("#" + prefix + "_zip").parents('.row').removeClass('ok-row');
jQuery("#" + prefix + "_zip").parents('.row').addClass('error-row');
$("#" + prefix + "_zip").val('');
}
}
});
}
I am using above code for zipcode field.This code works fine on non-https pages it works fine but when I tried it with https pages it doesnt shows.
any solutions are welcome.
As I looked into the service provider they are supporting jsonp and the following sample worked
$("input").autocomplete({
source: function (request, response) {
$.getJSON("http://ws.geonames.org/postalCodeSearchJSON?callback=?",
{ 'postalcode_startsWith': request.term, maxRows: 12, style: "full" },
function(data) {
if(data.postalCodes){
var x = $.map(data.postalCodes, function(v, i){
console.log(v)
return {
label: v.placeName + ' - ' + v.postalCode,
v: v.postalCode
}
});
response(x);
}
}
);
}
});
Demo: Fiddle

Resources