Sending a GET request within a Google Action intent - javascript
I'm new to Actions on Google and Node.js, but this seems like it should be straightforward and I'm not sure why it's not working. I just want to send a GET request within the code that handles a specific intent. At the moment, I'm not even looking for a return value; I just want to fire off the request. I'm using the Blaze tier of Firebase, which is supposed to allow outgoing HTTPS requests. Indeed, I can get the Action to play an audio file from my server in SSML. But when I put in a GET request to a PHP page that increments a value in a database, it isn't being executed successfully.
My code is taken directly from Google's CodeLabs tutorials for Actions. Below is the only function I'm modifying. This code runs, but the GET request is never received.
// Handle the Dialogflow intent named 'favorite color'.
// The intent collects a parameter named 'color'.
app.intent('favorite color', (conv, {color}) => {
const luckyNumber = color.length;
const audioSound = 'https://my.server.tld/path/to/sound.mp3';
// These two lines don't seem to do what I'm expecting them to.
var https = require("https");
https.get('https://my.server.tld/path/to/file.php?value=1');
conv.ask(`<speak>Your lucky number is ${luckyNumber}.` +
`<audio src="${audioSound}"></audio>` +
`Would you like to hear some fake colors?</speak>`);
});
There's nothing that jumps out at me as unusual in the Firebase logs (excerpted below). There doesn't seem to be any mention of the GET call I'm trying to make.
4:19:11.631 PM dialogflowFirebaseFulfillment Function execution took 569 ms, finished with status code: 200
4:19:11.543 PM dialogflowFirebaseFulfillment Response { "status": 200, "headers": { "content-type": "application/json; charset=utf-8" }, "body": { "payload": { "google": { "expectUserResponse": true, "richResponse": { "items": [ { "simpleResponse": { "textToSpeech": "<speak>Three. Your lucky number is 4.<audio src=\"https://actions.google.com/sounds/v1/cartoon/clang_and_wobble.ogg\"></audio>Would you like to hear some fake colors?</speak>" } } ] }, "userStorage": "{\"data\":{}}" } }, "outputContexts": [ { "name": "projects/actions-rwag/agent/sessions/ABwppHEUBtwbVHv-ECaw2yqSzZwdKjejoN3HrlpD8e0anrJytaT9jX8_zRMrW1-lJtC-W1TUFWKXLqLh/contexts/_actions_on_google", "lifespanCount": 99, "parameters": { "data": "{}" } } ] } }
4:19:11.434 PM dialogflowFirebaseFulfillment Conversation { "responses": [], "expectUserResponse": true, "digested": false, "noInputs": [], "_responded": false, "request": "[Excluded]", "headers": "[Excluded]", "sandbox": true, "input": { "raw": "blue", "type": "KEYBOARD" }, "surface": { "capabilities": { "list": [ { "name": "actions.capability.WEB_BROWSER" }, { "name": "actions.capability.MEDIA_RESPONSE_AUDIO" }, { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.AUDIO_OUTPUT" } ] } }, "available": { "surfaces": { "list": [ { "capabilities": { "list": [ { "name": "actions.capability.WEB_BROWSER" }, { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.AUDIO_OUTPUT" } ] } } ], "capabilities": { "surfaces": [ { "capabilities": { "list": [ { "name": "actions.capability.WEB_BROWSER" }, { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.AUDIO_OUTPUT" } ] } } ] } } }, "user": { "raw": { "userStorage": "{\"data\":{}}", "lastSeen": "2018-09-26T23:19:06Z", "locale": "en-US", "userId": "ABwppHHp5yhn_VrB_SIGG93tCzMx9o0A_W9bIDlbCClkqcV85LrVbJ42vLQ7hWXfe3UOd7pASDIm6v_q" }, "storage": {}, "_id": "ABwppHHp5yhn_VrB_SIGG93tCzMx9o0A_W9bIDlbCClkqcV85LrVbJ42vLQ7hWXfe3UOd7pASDIm6v_q", "locale": "en-US", "permissions": [], "last": { "seen": "2018-09-26T23:19:06.000Z" }, "name": {}, "entitlements": [], "access": {}, "profile": {} }, "arguments": { "parsed": { "input": { "text": "blue" }, "list": [ "blue" ] }, "status": { "input": {}, "list": [ null ] }, "raw": { "list": [ { "rawText": "blue", "textValue": "blue", "name": "text" } ], "input": { "text": { "rawText": "blue", "textValue": "blue", "name": "text" } } } }, "device": {}, "id": "ABwppHEUBtwbVHv-ECaw2yqSzZwdKjejoN3HrlpD8e0anrJytaT9jX8_zRMrW1-lJtC-W1TUFWKXLqLh", "type": "ACTIVE", "screen": true, "body": "[Excluded]", "version": 2, "action": "", "intent": "favorite color", "parameters": { "color": "blue" }, "contexts": { "_session": "projects/actions-rwag/agent/sessions/ABwppHEUBtwbVHv-ECaw2yqSzZwdKjejoN3HrlpD8e0anrJytaT9jX8_zRMrW1-lJtC-W1TUFWKXLqLh", "input": { "actions_capability_screen_output": { "name": "projects/actions-rwag/agent/sessions/ABwppHEUBtwbVHv-ECaw2yqSzZwdKjejoN3HrlpD8e0anrJytaT9jX8_zRMrW1-lJtC-W1TUFWKXLqLh/contexts/actions_capability_screen_output", "parameters": { "color": "blue", "color.original": "blue" } }, "actions_capability_audio_output": { "name": "projects/actions-rwag/agent/sessions/ABwppHEUBtwbVHv-ECaw2yqSzZwdKjejoN3HrlpD8e0anrJytaT9jX8_zRMrW1-lJtC-W1TUFWKXLqLh/contexts/actions_capability_audio_output", "parameters": { "color": "blue", "color.original": "blue" } }, "google_assistant_input_type_keyboard": { "name": "projects/actions-rwag/agent/sessions/ABwppHEUBtwbVHv-ECaw2yqSzZwdKjejoN3HrlpD8e0anrJytaT9jX8_zRMrW1-lJtC-W1TUFWKXLqLh/contexts/google_assistant_input_type_keyboard", "parameters": { "color": "blue", "color.original": "blue" } }, "actions_capability_web_browser": { "name": "projects/actions-rwag/agent/sessions/ABwppHEUBtwbVHv-ECaw2yqSzZwdKjejoN3HrlpD8e0anrJytaT9jX8_zRMrW1-lJtC-W1TUFWKXLqLh/contexts/actions_capability_web_browser", "parameters": { "color": "blue", "color.original": "blue" } }, "actions_capability_media_response_audio": { "name": "projects/actions-rwag/agent/sessions/ABwppHEUBtwbVHv-ECaw2yqSzZwdKjejoN3HrlpD8e0anrJytaT9jX8_zRMrW1-lJtC-W1TUFWKXLqLh/contexts/actions_capability_media_response_audio", "parameters": { "color": "blue", "color.original": "blue" } } }, "output": {} }, "incoming": { "parsed": [ "" ] }, "query": "blue", "data": {} }
4:19:11.346 PM dialogflowFirebaseFulfillment Headers { "host": "us-central1-actions-rwag.cloudfunctions.net", "user-agent": "Apache-HttpClient/4.5.4 (Java/1.8.0_181)", "transfer-encoding": "chunked", "accept": "text/plain, */*", "accept-charset": "big5, big5-hkscs, cesu-8, euc-jp, euc-kr, gb18030, gb2312, gbk, ibm-thai, ibm00858, ibm01140, ibm01141, ibm01142, ibm01143, ibm01144, ibm01145, ibm01146, ibm01147, ibm01148, ibm01149, ibm037, ibm1026, ibm1047, ibm273, ibm277, ibm278, ibm280, ibm284, ibm285, ibm290, ibm297, ibm420, ibm424, ibm437, ibm500, ibm775, ibm850, ibm852, ibm855, ibm857, ibm860, ibm861, ibm862, ibm863, ibm864, ibm865, ibm866, ibm868, ibm869, ibm870, ibm871, ibm918, iso-2022-cn, iso-2022-jp, iso-2022-jp-2, iso-2022-kr, iso-8859-1, iso-8859-13, iso-8859-15, iso-8859-2, iso-8859-3, iso-8859-4, iso-8859-5, iso-8859-6, iso-8859-7, iso-8859-8, iso-8859-9, jis_x0201, jis_x0212-1990, koi8-r, koi8-u, shift_jis, tis-620, us-ascii, utf-16, utf-16be, utf-16le, utf-32, utf-32be, utf-32le, utf-8, windows-1250, windows-1251, windows-1252, windows-1253, windows-1254, windows-1255, windows-1256, windows-1257, windows-1258, windows-31j, x-big5-hkscs-2001, x-big5-solaris, x-compound_text, x-euc-jp-linux, x-euc-tw, x-eucjp-open, x-ibm1006, x-ibm1025, x-ibm1046, x-ibm1097, x-ibm1098, x-ibm1112, x-ibm1122, x-ibm1123, x-ibm1124, x-ibm1166, x-ibm1364, x-ibm1381, x-ibm1383, x-ibm300, x-ibm33722, x-ibm737, x-ibm833, x-ibm834, x-ibm856, x-ibm874, x-ibm875, x-ibm921, x-ibm922, x-ibm930, x-ibm933, x-ibm935, x-ibm937, x-ibm939, x-ibm942, x-ibm942c, x-ibm943, x-ibm943c, x-ibm948, x-ibm949, x-ibm949c, x-ibm950, x-ibm964, x-ibm970, x-iscii91, x-iso-2022-cn-cns, x-iso-2022-cn-gb, x-iso-8859-11, x-jis0208, x-jisautodetect, x-johab, x-macarabic, x-maccentraleurope, x-maccroatian, x-maccyrillic, x-macdingbat, x-macgreek, x-machebrew, x-maciceland, x-macroman, x-macromania, x-macsymbol, x-macthai, x-macturkish, x-macukraine, x-ms932_0213, x-ms950-hkscs, x-ms950-hkscs-xp, x-mswin-936, x-pck, x-sjis_0213, x-utf-16le-bom, x-utf-32be-bom, x-utf-32le-bom, x-windows-50220, x-windows-50221, x-windows-874, x-windows-949, x-windows-950, x-windows-iso2022jp", "content-type": "application/json; charset=UTF-8", "function-execution-id": "gjnwrdpyi1ax", "x-appengine-api-ticket": "e212b331d87bdb3c", "x-appengine-city": "?", "x-appengine-citylatlong": "0.000000,0.000000", "x-appengine-country": "US", "x-appengine-default-version-hostname": "l9ec7ba250478215b-tp.appspot.com", "x-appengine-https": "on", "x-appengine-region": "?", "x-appengine-request-log-id": "5bac13ef00ff00ffe3280c8cb3550001737e6c396563376261323530343738323135622d7470000139303866373866633530636138623435363966303164656633393333393136383a3233000100", "x-appengine-user-ip": "35.239.85.110", "x-cloud-trace-context": "0109e1b3b7dc8fbbefd2664dbcbd5d0a/2770932151653705781;o=1", "x-forwarded-for": "35.239.85.110, 35.239.85.110", "x-forwarded-proto": "https", "accept-encoding": "gzip" }
4:19:11.339 PM dialogflowFirebaseFulfillment Request { "responseId": "c7b55f8a-502d-431a-8056-258dec82268f", "queryResult": { "queryText": "blue", "parameters": { "color": "blue" }, "allRequiredParamsPresent": true, "fulfillmentMessages": [ { "text": { "text": [ "" ] } } ], "outputContexts": [ { "name": "projects/actions-rwag/agent/sessions/ABwppHEUBtwbVHv-ECaw2yqSzZwdKjejoN3HrlpD8e0anrJytaT9jX8_zRMrW1-lJtC-W1TUFWKXLqLh/contexts/actions_capability_screen_output", "parameters": { "color": "blue", "color.original": "blue" } }, { "name": "projects/actions-rwag/agent/sessions/ABwppHEUBtwbVHv-ECaw2yqSzZwdKjejoN3HrlpD8e0anrJytaT9jX8_zRMrW1-lJtC-W1TUFWKXLqLh/contexts/actions_capability_audio_output", "parameters": { "color": "blue", "color.original": "blue" } }, { "name": "projects/actions-rwag/agent/sessions/ABwppHEUBtwbVHv-ECaw2yqSzZwdKjejoN3HrlpD8e0anrJytaT9jX8_zRMrW1-lJtC-W1TUFWKXLqLh/contexts/google_assistant_input_type_keyboard", "parameters": { "color": "blue", "color.original": "blue" } }, { "name": "projects/actions-rwag/agent/sessions/ABwppHEUBtwbVHv-ECaw2yqSzZwdKjejoN3HrlpD8e0anrJytaT9jX8_zRMrW1-lJtC-W1TUFWKXLqLh/contexts/actions_capability_web_browser", "parameters": { "color": "blue", "color.original": "blue" } }, { "name": "projects/actions-rwag/agent/sessions/ABwppHEUBtwbVHv-ECaw2yqSzZwdKjejoN3HrlpD8e0anrJytaT9jX8_zRMrW1-lJtC-W1TUFWKXLqLh/contexts/actions_capability_media_response_audio", "parameters": { "color": "blue", "color.original": "blue" } } ], "intent": { "name": "projects/actions-rwag/agent/intents/8524ede6-72a2-467b-9b34-67a8f1d3a121", "displayName": "favorite color" }, "intentDetectionConfidence": 1, "languageCode": "en-us" }, "originalDetectIntentRequest": { "source": "google", "version": "2", "payload": { "isInSandbox": true, "surface": { "capabilities": [ { "name": "actions.capability.WEB_BROWSER" }, { "name": "actions.capability.MEDIA_RESPONSE_AUDIO" }, { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.AUDIO_OUTPUT" } ] }, "requestType": "SIMULATOR", "inputs": [ { "rawInputs": [ { "query": "blue", "inputType": "KEYBOARD" } ], "arguments": [ { "rawText": "blue", "textValue": "blue", "name": "text" } ], "intent": "actions.intent.TEXT" } ], "user": { "userStorage": "{\"data\":{}}", "lastSeen": "2018-09-26T23:19:06Z", "locale": "en-US", "userId": "ABwppHHp5yhn_VrB_SIGG93tCzMx9o0A_W9bIDlbCClkqcV85LrVbJ42vLQ7hWXfe3UOd7pASDIm6v_q" }, "conversation": { "conversationId": "ABwppHEUBtwbVHv-ECaw2yqSzZwdKjejoN3HrlpD8e0anrJytaT9jX8_zRMrW1-lJtC-W1TUFWKXLqLh", "type": "ACTIVE", "conversationToken": "[]" }, "availableSurfaces": [ { "capabilities": [ { "name": "actions.capability.WEB_BROWSER" }, { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.AUDIO_OUTPUT" } ] } ] } }, "session": "projects/actions-rwag/agent/sessions/ABwppHEUBtwbVHv-ECaw2yqSzZwdKjejoN3HrlpD8e0anrJytaT9jX8_zRMrW1-lJtC-W1TUFWKXLqLh" }
4:19:11.063 PM dialogflowFirebaseFulfillment Function execution started
I think I've discovered why I was running into this problem, and why I couldn't explain it based on research into Actions on Google or Node.js. It looks like the page on my server that I was requesting returns a 301 "Permanently Moved" response. When I request the page through a web browser, it ignores(?) this response and serves the page anyway, but when I make the request in my AoG intent fulfillment, it silently recognizes the 301 and doesn't ever hit the PHP on the server. Anyway, it appears this is a problem with my server configuration and not my AoG code.
Hot tip to new AoG programmers: console.log() commands in the fulfillment will appear in the Firebase Cloud Functions log, which is what eventually allowed me to see the 301 code being returned. Thanks to anyone how tried to puzzle this out with me!
Related
Swagger UI only produces raw HTML instead of landing page
I'll try to provide as much information as I think might be relevant. I'm using NodeJS, MongoDB, .rest, and Render, though in this case I'm just trying to get things working locally first. Here are some of the files. //swagger.js const swaggerAutogen = require('swagger-autogen')(); const doc = { info: { title: 'My API', description: 'Welcome to my fumbling mess', }, host: 'localhost:3000', schemes: ['http'], }; const outputFile = './swagger-output.json'; const endpointsFiles = ['routes/index.js']; swaggerAutogen(outputFile, endpointsFiles, doc); //routes/index.js const routes = require('express').Router(); routes.use('/characters', require('./characters')); routes.use('/', require('./swagger-route')); module.exports = routes; //routes/swagger-route.js const router = require('express').Router(); const swaggerUi = require('swagger-ui-express'); const swaggerDocument = require('../swagger-output.json'); router.use('/api-docs', swaggerUi.serve); router.use('/api-docs', swaggerUi.setup(swaggerDocument)); module.exports = router; //swagger.output.json { "swagger": "2.0", "info": { "title": "My API", "description": "Welcome to my fumbling mess", "version": "1.0.0" }, "host": "localhost:3000", "basePath": "/", "schemes": [ "http" ], "paths": { "/characters/": { "get": { "description": "", "produces": [ "application/json" ], "parameters": [], "responses": { "200": { "description": "OK" }, "500": { "description": "Internal Server Error" } } }, "post": { "description": "", "parameters": [ { "name": "body", "in": "body", "schema": { "type": "object", "properties": { "characterName": { "example": "any" }, "playerName": { "example": "any" }, "race": { "example": "any" }, "class": { "example": "any" }, "level": { "example": "any" }, "alignment": { "example": "any" }, "stats": { "example": "any" } } } } ], "responses": { "201": { "description": "Created" }, "400": { "description": "Bad Request" } } } }, "/characters/{id}": { "get": { "description": "", "produces": [ "application/json" ], "parameters": [ { "name": "id", "in": "path", "required": true, "type": "string" } ], "responses": { "200": { "description": "OK" }, "500": { "description": "Internal Server Error" } } }, "put": { "description": "", "parameters": [ { "name": "id", "in": "path", "required": true, "type": "string" }, { "name": "body", "in": "body", "schema": { "type": "object", "properties": { "characterName": { "example": "any" }, "playerName": { "example": "any" }, "race": { "example": "any" }, "class": { "example": "any" }, "level": { "example": "any" }, "alignment": { "example": "any" }, "stats": { "example": "any" } } } } ], "responses": { "204": { "description": "No Content" }, "404": { "description": "Not Found" }, "500": { "description": "Internal Server Error" } } }, "delete": { "description": "", "parameters": [ { "name": "id", "in": "path", "required": true, "type": "string" } ], "responses": { "200": { "description": "OK" }, "404": { "description": "Not Found" }, "500": { "description": "Internal Server Error" } } } } } } And finally, running http://localhost:3000/api-docs/ doesn't result in the actual frontend of the Swagger UI like it should. Instead I get this is raw html in the attached image. Any ideas of what I could be doing wrong? I tried in swagger-route.js to change the 5th line from router.get() to router.use() I tried forgetting about localhost and changing the host paths to my Render web service but that just caused the same thing to happen on Render.
Strapi: trouble populating multi-valued attribute for nested relation
I have a collection called dish-category which contains many dishes, and a dish collection that contains many dish-options (another collection). the list of dishes from each dish-category is available in the API but the nested collection of dish options from each dish is not available on strapi. the following are the settings for my models: dish-category.settings.json: { "kind": "collectionType", "collectionName": "dish_categories", "info": { "name": "DishCategory", "description": "" }, "options": { "increments": true, "timestamps": true, "draftAndPublish": true }, "pluginOptions": {}, "attributes": { "Name": { "type": "string" }, "Description": { "type": "text" }, "dishes": { "collection": "dish", "via": "dish_category" } } } dish.settings.json: { "kind": "collectionType", "collectionName": "dishes", "info": { "name": "Dish", "description": "" }, "options": { "increments": true, "timestamps": true, "draftAndPublish": true }, "pluginOptions": {}, "attributes": { "Name": { "type": "string" }, "Description": { "type": "text" }, "Total": { "type": "decimal", "min": 0, "required": false, "default": 0 }, "dish_categories": { "collection": "dish-category" }, "dish_options": { "collection": "dish-option", "via": "dish" }, "dish_category": { "via": "dishes", "model": "dish-category" } } } dish-option.settings.json: { "kind": "collectionType", "collectionName": "dish_options", "info": { "name": "DishOption", "description": "" }, "options": { "increments": true, "timestamps": true, "draftAndPublish": true }, "pluginOptions": {}, "attributes": { "Name": { "type": "string" }, "Price": { "type": "decimal", "min": 0, "default": 0 }, "dish": { "via": "dish_options", "model": "dish" } } } on the dish-category/controllers/dish-category.js file I tried populating the attribute: 'use strict'; /** * Read the documentation (https://strapi.io/documentation/developer-docs/latest/development/backend-customization.html#core-controllers) * to customize this controller */ module.exports = { async find(params, populate){ return strapi.query('dish-category').find(params, ["dishes","dish.dish_options"]); } }; I am having trouble displaying nested relations with multiple values, I have tried looking up solutions online, I came across this thread https://forum.strapi.io/t/simple-nested-array-issue/1045/4 but the solution doesn't work for me and it seems like the link to the example is no longer available.
For Stripe Connected Accounts, which part of the account.updated webhook object indicates that the account is enabled?
I have an endpoint that is receiving events from Connected Stripe accounts. The webhook listens for the account.updated event type. It works as expected. However, when I look at the object sent to my endpoint, I'm not sure what would indicate that the account is in "enabled" status. I ask because if the Connected account was successfully set up, I would like to then give the customer the ability to access their Stripe dashboard. If it's not, then I would want for them to be able to finish the account setup process. Any insight would be appreciated. This is what I get from the Stripe webhook: { "id": "EXAMPLEID", "object": "event", "account": "ACCOUNT", "api_version": "2020-03-02", "created": 1608614938, "data": { "object": { "id": "ACCOUNTNUMBER", "object": "account", "business_profile": { "mcc": null, "name": null, "support_address": null, "support_email": null, "support_phone": null, "support_url": null, "url": null }, "capabilities": { "transfers": "active" }, "charges_enabled": true, "country": "US", "default_currency": "usd", "details_submitted": true, "email": null, "payouts_enabled": true, "settings": { "bacs_debit_payments": { }, "branding": { "icon": null, "logo": null, "primary_color": null, "secondary_color": null }, "card_payments": { "statement_descriptor_prefix": null, "decline_on": { "avs_failure": false, "cvc_failure": false } }, "dashboard": { "display_name": "Books For Everyone", "timezone": "Etc/UTC" }, "payments": { "statement_descriptor": null, "statement_descriptor_kana": null, "statement_descriptor_kanji": null }, "sepa_debit_payments": { }, "payouts": { "debit_negative_balances": true, "schedule": { "delay_days": 2, "interval": "daily" }, "statement_descriptor": null } }, "type": "express", "created": 1608614884, "external_accounts": { "object": "list", "data": [ { "id": "ID_NUMBER_HERE", "object": "bank_account", "account": "ACCOUNT_NUMBER_HERE", "account_holder_name": null, "account_holder_type": null, "available_payout_methods": [ "standard" ], "bank_name": "STRIPE TEST BANK", "country": "US", "currency": "usd", "default_for_currency": true, "fingerprint": "x9ELfUw7u81waQkl", "last4": "6789", "metadata": { }, "routing_number": "110000000", "status": "new" } ], "has_more": false, "total_count": 1, "url": "/v1/accounts/ACCOUNT_NUMBER/external_accounts" }, "login_links": { "object": "list", "total_count": 0, "has_more": false, "url": "/v1/accounts/ACCOUNT_NUMBER/login_links", "data": [ ] }, "metadata": { }, "requirements": { "current_deadline": null, "currently_due": [ ], "disabled_reason": null, "errors": [ ], "eventually_due": [ "individual.dob.day", "individual.dob.month", "individual.dob.year", "individual.ssn_last_4" ], "past_due": [ ], "pending_verification": [ ] }, "tos_acceptance": { "date": 1608614937 } }, "previous_attributes": { "capabilities": { "transfers": "inactive" }, "charges_enabled": false, "details_submitted": false, "payouts_enabled": false, "requirements": { "currently_due": [ "tos_acceptance.date", "tos_acceptance.ip" ], "disabled_reason": "requirements.past_due", "eventually_due": [ "individual.dob.day", "individual.dob.month", "individual.dob.year", "individual.ssn_last_4", "tos_acceptance.date", "tos_acceptance.ip" ], "past_due": [ "tos_acceptance.date", "tos_acceptance.ip" ] }, "tos_acceptance": { "date": null } } }, "livemode": false, "pending_webhooks": 1, "request": { "id": "ID_NUMBER_HERE", "idempotency_key": null }, "type": "account.updated" }
Because there are now multiple things an account might be used for, there isn't necessarily one single attribute to check for being "enabled" overall. Mostly you'll want to look at the capabilities (docs, API reference) such as in your data where you see transfers: 'active', which indicates that account is currently enabled for transfers. You'll also want to keep an eye on the requirements hash (docs, API ref), which is how Stripe will inform you that additional information is needed now (or eventually).
Why is this forEach function repeating last value in all elements?
Look at this code: var machines = [{ "name": "inclinedPlane", "images": { "draggable": { "src": "##instanceAssets/assets/images/mc_inclinedPlane.png", "sound": "##instanceAssets/assets/audios/inclinedPlane.mp3" }, "drop": { "default": "##instanceAssets/assets/images/inclinedPlaneSong.png", "onDrop": "##instanceAssets/assets/images/inclinedPlaneSongFilled.png" } } }, { "name": "pulley", "images": { "draggable": { "src": "##instanceAssets/assets/images/mc_pulley.png", "sound": "##instanceAssets/assets/audios/pulley.mp3" }, "drop": { "default": "##instanceAssets/assets/images/pulleySong.png", "onDrop": "##instanceAssets/assets/images/pulleySongFilled.png" } } }, { "name": "lever", "images": { "draggable": { "src": "##instanceAssets/assets/images/mc_lever.png", "sound": "##instanceAssets/assets/audios/lever.mp3" }, "drop": { "default": "##instanceAssets/assets/images/leverSong.png", "onDrop": "##instanceAssets/assets/images/leverSongFilled.png" } } }]; var drops = { "component": "DropContainer", "parent": "main", "style": { "type": "image", "scale": { "x": 1, "y": 1 } } }; I want to assign the the default value of each machine drop image to the src attribute of the merged object's style. machines.forEach((machine) => { const config = Object.assign(machine.images.drop, drops); config.style.src = machine.images.drop.default; console.log(config); }); But for some reason, thesrc value on each object's style is always being the last one for all objects. I can't see why is this happening and I've spent a lot of time on this with no results. Can you see what's going on here?
You need to put the drops object inside of function forEach. The problem you're facing is the reference of the same object drops in every assign you're executing. Set the default value as follow: config.style.src = machine.images.drop.default; var machines = [{ "name": "inclinedPlane", "images": { "draggable": { "src": "##instanceAssets/assets/images/mc_inclinedPlane.png", "sound": "##instanceAssets/assets/audios/inclinedPlane.mp3" }, "drop": { "default": "##instanceAssets/assets/images/inclinedPlaneSong.png", "onDrop": "##instanceAssets/assets/images/inclinedPlaneSongFilled.png" } } }, { "name": "pulley", "images": { "draggable": { "src": "##instanceAssets/assets/images/mc_pulley.png", "sound": "##instanceAssets/assets/audios/pulley.mp3" }, "drop": { "default": "##instanceAssets/assets/images/pulleySong.png", "onDrop": "##instanceAssets/assets/images/pulleySongFilled.png" } } }, { "name": "lever", "images": { "draggable": { "src": "##instanceAssets/assets/images/mc_lever.png", "sound": "##instanceAssets/assets/audios/lever.mp3" }, "drop": { "default": "##instanceAssets/assets/images/leverSong.png", "onDrop": "##instanceAssets/assets/images/leverSongFilled.png" } } }]; machines.forEach((machine) => { var drops = { "component": "DropContainer", "parent": "main", "style": { "type": "image", "scale": { "x": 1, "y": 1 } } }; const config = Object.assign(machine.images.drop, drops); config.style.src = machine.images.drop.default; }); console.log(JSON.stringify(machines, null, 2)) .as-console-wrapper { max-height: 100% !important; top: 0; }
Here is the output after this simple change: You already have the default property on the config object (in the root). You obtained it when you created your "merged" object. So... Change config.style.src = machine.images.drop; To config.style.src = config.default; And that produces this output: config.style.src: ##instanceAssets/assets/images/inclinedPlaneSong.png config.style.src: ##instanceAssets/assets/images/pulleySong.png config.style.src: ##instanceAssets/assets/images/leverSong.png ======================================== var machines = [{ "name": "inclinedPlane", "images": { "draggable": { "src": "##instanceAssets/assets/images/mc_inclinedPlane.png", "sound": "##instanceAssets/assets/audios/inclinedPlane.mp3" }, "drop": { "default": "##instanceAssets/assets/images/inclinedPlaneSong.png", "onDrop": "##instanceAssets/assets/images/inclinedPlaneSongFilled.png" } } }, { "name": "pulley", "images": { "draggable": { "src": "##instanceAssets/assets/images/mc_pulley.png", "sound": "##instanceAssets/assets/audios/pulley.mp3" }, "drop": { "default": "##instanceAssets/assets/images/pulleySong.png", "onDrop": "##instanceAssets/assets/images/pulleySongFilled.png" } } }, { "name": "lever", "images": { "draggable": { "src": "##instanceAssets/assets/images/mc_lever.png", "sound": "##instanceAssets/assets/audios/lever.mp3" }, "drop": { "default": "##instanceAssets/assets/images/leverSong.png", "onDrop": "##instanceAssets/assets/images/leverSongFilled.png" } } }]; var drops = { "component": "DropContainer", "parent": "main", "style": { "type": "image", "scale": { "x": 1, "y": 1 } } }; machines.forEach((machine) => { const config = Object.assign(machine.images.drop, drops); config.style.src = config.default; console.log('config.style.src: ' + config.style.src); });
Import Java Script object using VBA
I am trying to scrape output from a JavaScript command using VBA. Unfortunately I am a bit lost with how. I have tried .getElementsByTagName("script")(4).innertext, but all I get back is [object] See the HTML below. I am trying to extract on the data array's. Any help will be appreciated Cheers <script type="text/javascript"> var _chartit_hco_array = [ { "series": [ { "stacking": false, "data": [ 4006, 34940.1034, 61062.5161, 95107.6333, 167971.8, 218549.129, 272389.2143, 288584.7097, 317959.5 ], "type": "column", "name": "Dau" } ], "yAxis": [ { "title": { "text": "Daily Active Users (DAU)" } } ], "chart": { "renderTo": "dauchart_container" }, "xAxis": [ { "categories": [ "May<br>2013", "Jun<br>2013", "Jul<br>2013", "Aug<br>2013", "Sep<br>2013", "Oct<br>2013", "Nov<br>2013", "Dec<br>2013", "Jan<br>2014" ], "title": { "text": "Date" } } ], "title": { "text": "Daily Active Users (Monthly avg.)" } }, { "series": [ { "stacking": false, "data": [ 12456.96, 204106.3103, 320728.5161, 442251.9333, 646994.0333, 1017031.3226, 1232705.2857, 1377097.3871, 1432762.5 ], "type": "column", "name": "Mau", "label": { "text": "Light breeze", "style": { "color": "#606060" } } } ], "yAxis": [ { "title": { "text": "Monthly Active Users (MAU)" } } ], "chart": { "renderTo": "mauchart_container" }, "xAxis": [ { "categories": [ "May<br>2013", "Jun<br>2013", "Jul<br>2013", "Aug<br>2013", "Sep<br>2013", "Oct<br>2013", "Nov<br>2013", "Dec<br>2013", "Jan<br>2014" ], "title": { "text": "Date" } } ], "title": { "text": "Monthly Active Users (Monthly avg.)" } }, { "series": [ { "stacking": false, "data": [ 36.904, 18.963103, 18.939677, 21.466333, 25.936, 21.515806, 22.113929, 20.959032, 22.19 ], "type": "column", "name": "Dau2Mau Percent" } ], "yAxis": [ { "title": { "text": "Daily / Monthly Active Users (DAU/MAU)" } } ], "chart": { "renderTo": "dau2mauchart_container" }, "xAxis": [ { "categories": [ "May<br>2013", "Jun<br>2013", "Jul<br>2013", "Aug<br>2013", "Sep<br>2013", "Oct<br>2013", "Nov<br>2013", "Dec<br>2013", "Jan<br>2014" ], "title": { "text": "Date" } } ], "title": { "text": "DAU as percentage of MAU (Monthly avg.)" } }, { "series": [ { "stacking": false, "data": [ 11057.24, 104310.5862, 153653.3226, 222996.8667, 392113.7, 546472.0645, 674174.0714, 710372.6774, 771079.5 ], "type": "column", "name": "Wau" } ], "yAxis": [ { "title": { "text": "Weekly Active Users (WAU)" } } ], "chart": { "renderTo": "wauchart_container" }, "xAxis": [ { "categories": [ "May<br>2013", "Jun<br>2013", "Jul<br>2013", "Aug<br>2013", "Sep<br>2013", "Oct<br>2013", "Nov<br>2013", "Dec<br>2013", "Jan<br>2014" ], "title": { "text": "Date" } } ], "title": { "text": "Weekly Active Users (Monthly avg.)" } } ];</script>
You were almost right, you have to do: document.getElementsByTagName("script")(4).innerText; //Check the uppercase T in innerText (If it returns empty string, it means the script is from other domain, if that's the case you cannot get it). Cheers