Pass subject, content, etc with node.js - circuit-sdk

How can I pass subject content in the node.js using add.textitem node?
I have tried the code below but the bot only sends the content, I never get subject, parentItemId, etc..
var content = {
subject: 'test',
content: msg.payload,
}
msg.payload = content;
return msg;
Debugging
04/09/2019 17:42:58node: 8de0d86f.987558
msg.payload : Object
object
subject: "test"
content: "All arrays Chuck Norris declares are of infinite size, because Chuck Norris knows no bounds."
contentType: "Circuit.Enums.TextItemContentType.RICH"
But in Circuit, only get content.

The content of the text item needs to be passed as the msg.payload.content. Here you are trying to pass the object as the payload itself. See the code below for how to use pass the subject and content.
msg.payload = {
content: {
content: 'content',
subject: 'subject'
}
}
return msg;

Related

Google Apps Script/URLFetchApp and using returned data

I am very new to this, so please bear with me-- I have currently have an operational google apps script on the backend of a google sheet that is generated from Google Form answers. I am essentially setting up a ticket form in google forms that will trigger the data in the corresponding sheet to be sent via api call to our ticketing system. It works great, but I am trying to optimize it currently. The goal is to take the json response I get using:
Logger.log(response.getContentText());
which provides me the following info:
Aug 9, 2020, 11:44:40 AM Info {"_url":"https://testticketingsystem.com/REST/2.0/ticket/123456","type":"ticket","id":"123456"}
and send another API call to send data to that new ticket.
Here's a code snippet:
var payload = {
"Subject": String(su),
"Content": String(as),
"Requestor": String(em),
"Queue": String(qu),
"CustomFields": {"CustomField1": String(vn), "CustomField2": String(vb), "CustomField3":
String(vg), "CustomField4": String(av), "CustomField5": String(ov), "CustomField6":
String(sd)}
}
var options = {
'method': 'post',
"contentType" : "application/json",
'payload': JSON.stringify(payload),
'muteHttpExceptions': true
}
var url = "https://testticketingsystem.com/REST/2.0/ticket?token=****************";
var response = UrlFetchApp.fetch(url,options);
Logger.log(response.getContentText());
} catch (error) {
Logger.log(error.toString());
}
}
After the ticket is created, how do I script the use of that ID number as a variable into my next api call?
Thank you!
UrlFetchApp.fetch returns a HTTPResponse, and if you expect JSON then you should be able to just use JSON.parse() to create an object from the text. (The JSON object is a standard JavaScript global object like Math; it is not Google Apps Script specific.)
If all goes well, you should just be able to use
var response = UrlFetchApp.fetch(url,options);
var data = JSON.parse(response.getContentText());
var id = data.id;
and then use that id for your next fetch().
Notes
If your literal response is indeed
Aug 9, 2020, 11:44:40 AM Info {"_url":"https://testticketingsystem.com/REST/2.0/ticket/123456","type":"ticket","id":"123456"}
you will run into trouble as everything until the { is invalid JSON (use a linter if you need to check yourself). But I'm assuming that was added by the console when you logged JSON, and not in the actual response itself.
JSON.parse() throws an error with invalid JSON, so you can use try/catch if needed.
You can also check the headers before you try to JSON.parse().
Here's an example that checks and handles issues, should they arise.
var type = response.getHeaders()["Content-Type"];
var text = response.getContentText();
if (type === "application/json") {
try {
var data = JSON.parse(text);
} catch (error) {
return Logger.log("Invalid JSON: " + response.getContentText(text));
}
} else {
return Logger.log("expected JSON, but got response of type: " + type);
}
// if we get to this line, data is an object we can use

NestJS serialization from snake_case to camelCase

I want to achieve automatic serialization/deserialization of JSON request/response body for NestJS controllers, to be precise, automatically convert snake_case request body JSON keys to camelCase received at my controller handler and vice versa.
What I found is to use class-transformer's #Expose({ name: 'selling_price' }), as on the example below (I'm using MikroORM):
// recipe.entity.ts
#Entity()
export class Recipe extends BaseEntity {
#Property()
name: string;
#Expose({ name: 'selling_price' })
#Property()
sellingPrice: number;
}
// recipe.controller.ts
#Controller('recipes')
export class RecipeController {
constructor(private readonly service: RecipeService) {}
#Post()
async createOne(#Body() data: Recipe): Promise<Recipe> {
console.log(data);
return this.service.createOne(data);
}
}
// example request body
{
"name": "Recipe 1",
"selling_price": 50000
}
// log on the RecipeController.createOne handler method
{ name: 'Recipe 1',
selling_price: 50000 }
// what I wanted on the log
{ name: 'Recipe 1',
sellingPrice: 50000 }
There can be seen that the #Expose annotation works perfectly, but going further I want to be able to convert it as the attribute's name on the entity: sellingPrice, so I can directly pass the parsed request body to my service and to my repository method this.recipeRepository.create(data). Current condition is the sellingPrice field would be null because there exists the selling_price field instead. If I don't use #Expose, the request JSON would need to be written on camelCase and that's not what I prefer.
I can do DTOs and constructors and assigning fields, but I think that's rather repetitive and I'll have a lot of fields to convert due to my naming preference: snake_case on JSON and database columns and camelCase on all of the JS/TS parts.
Is there a way I can do the trick cleanly? Maybe there's a solution already. Perhaps a global interceptor to convert all snake_case to camel_case but I'm not really sure how to implement one either.
Thanks!
You could use mapResult() method from the ORM, that is responsible for mapping raw db results (so snake_case for you) to entity property names (so camelCase for you):
const meta = em.getMetadata().get('Recipe');
const data = {
name: 'Recipe 1',
selling_price: 50000,
};
const res = em.getDriver().mapResult(data, meta);
console.log(res); // dumps `{ name: 'Recipe 1', sellingPrice: 50000 }`
This method operates based on the entity metadata, changing keys from fieldName (which defaults to the value based on selected naming strategy).

Ember data 1.0 Application -en AdapterSerializer not working?

My question is in line with this one: Ember data 1.0.0: confused with per-type adapters and serializers
Problem is that I cannot initialize RESTSerializer per type because I need to set ActiveModelSerializer :
App.FooSerializer = DS.ActiveModelSerializer.extend({attrs: {}});
to set relationships as embedded.
So I want to set 1 serializer for all models. I tried to set ApplicationSerializer, but this did not call any hooks when getting response from server (And I'm sure my server gives correct response):
App.ApplicationSerializer = DS.RESTSerializer.extend({
extractSingle: function(store, type, payload, id, requestType) {
return this._super(store, type, payload, id, requestType);
},
extractArray: function(store, type, payload, id, requestType) {
return this._super(store, type, payload, id, requestType);
},
normalize: function(type, property, hash) {
return this._super(type, property, hash);
}
});
Setting my adapter doesn't seem to work:
var adapter = require('init/adapter');
App.ApplicationAdapter = adapter.extend({
defaultSerializer: myAdapter //I QUESS THIS IS WRONG?
});
Did I make a syntax error? Any other suggestions?
EDIT:
Ok, I found my mistake but not a great solution. Seems that my FooSerializer overrides the general ApplicationSerializer..
Is there a way where I can set both? :/
You can't use both per say, but you can have your FooSerializer extend your ApplicationSerializer and then override the methods that you'd like to use differently.
App.FooSerializer = App.ApplicationSerializer.extend({
extractArray: function(store, type, payload, id, requestType) {
// alert each record to annoy the user
return this._super(store, type, payload, id, requestType);
},
});

Where does the response get stored after a Dojo JSONP request?

JavaScript
For example, I have the following JavaScript code (Dojo 1.6 is already loaded):
dojo.require("dojo.io.script")
// PART I
var jsonpArgs = {
url: "http://myapp.appspot.com/query",
content: {
id: "1234",
name: "Juan",
start_date: "2000-01-01",
callback: "recover"
}
};
// PART II
dojo.io.script.get(jsonpArgs).then(function(data) {
console.log(data);
});
// PART III
function recover(data) {
console.log(data);
}
Direct query from browser
I understand that my server will receive the query as though I typed the following into the address bar:
http://myapp.appspot.com/query?id=1234&name=Juan&start_date=2000-01-01&callback=recover
Expected response
If I directly queried my server using the browser address bar, I'll receive, in MIME type application/json and plaintext rendered in browser, something like this:
recover(
{
id: 1234,
name: Juan,
data: [
["2000-01-01", 1234],
["2000-01-02", 5678]
]
}
);
Problem
Now, looking back at Part II of the JavaScript, I'd execute the JSONP request with dojo.io.script.get(jsonpArgs). This returns a Deferred object, which I can take advantage of by chaining .then after it. Note that I defined the handler for the .then event to output that captured data to the console.
However, all I get in the console is an Event. I tried to search its data tree, but I could not find the data I expected.
Question
Where is the response for a JSONP request stored? How do I find it?
My server (which I control) only outputs a plaintext rendering of the data requested, wrapped in the callback function (here specified as recover), and specifies a application/json MIME type. Is there anything else I need to set up on my server, so that the response data is captured by the Deferred object?
Attempted solution
I can actually recover the response by defining the callback function (in this case recover in Part III of the JavaScript). However, in the Dojo tutorials, they just recovered the data using the Deferred (and .then) framework. How do I do it using Dojo Deferreds?
Update (using the Twitter example from Dojo tutorial)
Take for example this script from the Dojo tutorial, Getting Jiggy With JSONP. I edited it to log data to the console.
dojo.require("dojo.io.script");
dojo.io.script.get({
url: "http://search.twitter.com/search.json",
callbackParamName: "callback",
content: {q: "#dojo"}
}).then(function(data){
//we're only interested in data.results, so strip it off and return it
console.log(data); // I get an Object, not an Event, but no Twitter data when browsing the results property
console.log(data.results) // I get an array of Objects
return data.results;
});
For console.log(data), I get an Object, not an Event as illustrated by my case. Since the example implies that the data resides in data.results, I also try to browse this tree, but I don't see my expected data from Twitter. I'm at a loss.
For console.log(data.results), I get an array of Objects. If I query Twitter directly, this is what I'd get in plaintext. Each Object contains the usual tweet meta-data like username, time, user portrait, and the tweet itself. Easy enough.
This one hits me right on the head. The handler for the .then chain, an anonymous function, receives only one argument data. But why is it that the results property in console.log(data) and the returned object I get from console.log(data.results) are different?
I got it.
Manual callback implementation
function recover(data) {
console.log(data);
}
var jsonpArgs = {
url: "http://myapp.appspot.com/query",
content: {
id: "1234",
name: "Juan",
start_date: "2000-01-01",
callback: "recover"
};
dojo.io.script.get(jsonpArgs);
This is the request that my server will receive:
http://myapp.appspot.com/query?id=1234&name=Juan&start_date=2000-01-01&callback=recover
In this case, I'll expect the following output from my server:
recover({
id: 1234,
name: Juan,
data: [
["2000-01-01", 1234],
["2000-01-02", 5678]
]
});
Three things to note:
Server will expect callback in the query URL string. callback is implemented as a property of jsonpArgs.
Because I specified callback=recover, my server will attach recover( + the_data_I_need + ), returns the whole string to the browser, and browser will execute recover(the_data_I_need). This means...
That I'll have to define, for example, function recover(one_argument_only) {doAnythingYouWantWith(one_argument_only)}
The problem with this approach is that I cannot take advantage of Deferred chaining using .then. For example:
dojo.io.script.get(jsonpArgs).then(function(response_from_server) {
console.log(response_from_server);
})
This will give me an Event, with no trace of the expected response at all.
Taking advantage of Dojo's implementation of JSONP requests
var jsonpArgs = {
url: "http://myapp.appspot.com/query",
callbackParamName: "callback",
content: {
id: "1234",
name: "Juan",
start_date: "2000-01-01"
};
dojo.io.script.get(jsonpArgs);
This is the request that my server will receive:
http://myapp.appspot.com/query?id=1234&name=Juan&start_date=2000-01-01&callback=some_function_name_generated_by_dojo
In this case, I'll expect the following output from my server:
some_function_name_generated_by_dojo({
id: 1234,
name: Juan,
data: [
["2000-01-01", 1234],
["2000-01-02", 5678]
]
});
Things to note:
Note the property of jsonpArgs, callbackParamName. The value of this property must be the name of the variable (in the query URL string) expected by the server. If my server expects callbackfoo, then callbackParamName: "callbackfoo". In my case, my server expects the name callback, therefore callbackParamName: "callback".
In the previous example, I specified in the query URL callback=recover and proceeded to implement function recover(...) {...}. This time, I do not need to worry about it. Dojo will insert its own preferred function callback=some_function_name_generated_by_dojo.
I imagine some_function_name_generated_by_dojo to be defined as:
Definition:
function some_function_name_generated_by_dojo(response_from_server) {
return response_from_server;
}
Of course the definition is not that simple, but the advantage of this approach is that I can take advantage of Dojo's Deferred framework. See the code below, which is identical to the previous example:
dojo.io.script.get(jsonpArgs).then(function(response_from_server) {
console.log(response_from_server);
})
This will give me the exact data I need:
{
id: 1234,
name: Juan,
data: [
["2000-01-01", 1234],
["2000-01-02", 5678]
]
}

KRL: Getting the "location" header from an http:post()

I'm sending an HTTP POST request to a URL. It sends back a piece of information I need in the location header of the response. How do I get that header? I've tried the following code and it doesn't seem to work:
In the action block of the rule that uses the http:post() action:
http:post("https://cas.byu.edu/cas/v1/tickets/")
with params = {"username": netid, "password": password}
and autoraise = "gottgt"
and response_headers = ["location"];
The rule that handles the http event:
rule got_tgt {
select when http post label "gottgt"
pre {
content = event:param("content");
location = event:param("location");
}
{
notify("CAS Login", "Got back the POST response (#{location}): #{content}") with sticky=true;
}
}
However, the location variable is always blank. How do I tell KRL that I want the location header, and how do I get it from the response?
While I can't test your specific endpoint, I've built a sample app that you will find useful in debugging this issue.
Note that I'm both autoraising the response, and using the setting syntax to raise the events. You wouldn't normally do both, but it hilights a difference. When explicitly raising the result, you get the entire response. You can see in my example that the server header is returned, and shown also in the autoraised rule.
Your code looks right, but I'd do an explicit raise and inspect the response as I show here, and that will help you know exactly what is available to you.
Run this app here: http://ktest.heroku.com/a8x183
and code here:
ruleset a8x183 {
meta {
name "Testing Response Headers"
description <<
>>
author "Sam Curren"
logging off
}
dispatch {
// domain "example.com"
}
global {
bodylog = defaction(title, msg){
{
append("body", "<h1>#{title}</h1>");
append("body", "<div>#{msg}</div>");
}
};
}
rule first_rule {
select when pageview ".*" setting ()
pre {
}
http:post("http://httpbin.org/post") setting (res)
with params = {"username":"yahuda","password":"metalcages"}
and autoraise = "kickstand"
and response_headers = ["server"];
fired {
raise explicit event "moon" with res = res;
}
}
rule exp {
select when explicit moon
pre {
res = event:param("res");
res_s = res.encode();
}
bodylog("explicit raise: full response", res_s);
}
rule response {
select when http post label "kickstand"
pre {
server_header = event:param("server");
content = event:param("content");
}
{
bodylog("autoraise: content", content);
bodylog("autoraise: server_header", server_header);
}
}
}