Parsing objects of a JSON for input validation - json

I want to use a database of valid ICAO and IATA airport codes for a discord bot input in typescript. However, I am not quite sure how to call the "icao" and "iata" contstructor of all objects, as each one is defined differently and there are thousands: e.g.:
"00AK": {
"icao": "00AK",
"iata": "",
"name": "Lowell Field",
"city": "Anchor Point",
"state": "Alaska",
"country": "US",
"elevation": 450,
"lat": 59.94919968,
"lon": -151.695999146,
"tz": "America\/Anchorage"
},
"00AL": {
"icao": "00AL",
"iata": "",
"name": "Epps Airpark",
"city": "Harvest",
"state": "Alabama",
"country": "US",
"elevation": 820,
"lat": 34.8647994995,
"lon": -86.7703018188,
"tz": "America\/Chicago"
},
The bot uses the following to provide the METAR of a specific airport:
name: 'metar',
description: 'Provides the METAR report of the requested airport',
category: CommandCategory.UTILS,
executor: async (msg) => {
const splitUp = msg.content.replace(/\.metar\s+/, ' ').split(' ');
if (splitUp.length <= 1) {
await msg.reply('please provide an ICAO airport code.');
return Promise.resolve();
}
const icaoArg = splitUp[1];
if (icaoArg.length !== 4) {
await msg.reply('please provide an ICAO airport code.');
return Promise.resolve();
}
request({
method: 'GET',
url: `https://avwx.rest/api/metar/${icaoArg}`,
headers: {
Authorization: process.env.METAR_TOKEN },
}, async (error, response, body) => {
const metarReport = JSON.parse(body);å
const metarEmbed = makeEmbed({
title: `METAR Report | ${metarReport.station}`,
description: makeLines([
'**Raw Report**',
metarReport.raw,
,
'**Basic Report:**',
`**Time Observed:** ${metarReport.time.dt}`,
`**Station:** ${metarReport.station}`,
`**Wind:** ${metarReport.wind_direction.repr} at ${metarReport.wind_speed.repr}kts`,
`**Visibility:** ${metarReport.visibility.repr}${metarReport.units.visibility}`,
`**Temperature:** ${metarReport.temperature.repr}C`,
`**Dew Point:** ${metarReport.dewpoint.repr}C`,
`**Altimeter:** ${metarReport.altimeter.value.toString()} ${metarReport.units.altimeter}`,
]),
fields: [
{
name: 'Unsure of how to read the raw report?',
value: 'Type \'**.metarhow**\' to learn how to read raw METARs',
inline: false
},
],
footer: { text: 'This METAR report may not accurately reflect the weather in the simulator. However, it will always be similar to the current conditions present in the sim.' },
});
await msg.channel.send({ embeds: [metarEmbed] });
});
},
};
Currently, if a user provides an ICAO that's not valid the bot crashes, or if they provide a valid IATA, the discord api throws the user an error to provide a valid ICAO code. How would I go about cross referencing the user argument with the JSON so the bot does not crash when inputting an invalid ICAO? Thanks

Related

Cypress login to REST endpoint is unauthorized, Postman works - upload of JSON file

We have a REST service with an incoming REST endpoint that accepts data. It has no web interface (Swagger or so), only the API. With Postman I can POST a JSON file (response code is 202) to it and then read the uploaded data from another endpoint.
When I want to log in to the same endpoint with Cypress to upload a JSON file from the fixtures folder (with the same body as in the Postman request), then I get response code 401 instead – Unauthorized. I have the feeling that the cypress request is wrong because the logfile of the service does not write a message when I use the cypress POST but it does when I use the Postman POST.
First question: What could I be doing wrong in the cypress request?
Second question: Once the authentication works, how can I POST/upload/push the content of the JSON file to that endpoint? Because I have no webpage to interact with, I cannot use click button functions. The documentation mainly deals with interpreting a JSON response but not with sending it.
My cypress code:
it('logs in to connector through REST API', () => {
cy.request({
method: 'POST',
url: 'localhost:8095/connector/demands/v1/demandData',
failOnStatusCode:false,
form: true,
body: {
Username: 'user',
Password: 'pass',
}
})
})
import my-request from '../fixtures/my-request.json'
it('loads the JSON file', () => {
cy.fixture('my-request.json')
})
The structure of the JSON file to upload is not too simple, here is a shortened version:
{
"#metadata": {
"context": "{{A}}"
},
"pool": "{{B}}",
"action": "NEW",
"Type": "ANNOUNCEMENT",
"ON": "Order123",
"PON": "PO123",
"SNN": "SN123",
"direction": "OUT",
"mode": 3,
"pack": [
{
"out": {
"outKey": "OUT14",
"outQuantity": "3",
"dimension": {
"length": "303",
"width": "33",
"height": "903",
"unit": "mm"
},
"layers": "3",
"weight": "3000",
"weightUnit": "grm",
"in": [
{
"inKey": "IN12",
"inQuantity": "3",
"article": {
"articleKey": "article3",
"quantity": "300",
"PON": "Art_PO300",
"SNN": "Art_SN300"
}
}
]
},
"p1": "pack3",
"p2": "pack4",
"store": true
},
{
"out": {
"outKey": "OUT23",
"outQuantity": "5",
"dimension": {
"length": "505",
"width": "55",
"height": "905",
"unit": "mm"
},
"layers": "5",
"weight": "5000",
"weightUnit": "grm",
"in": [
{
"inKey": "IN19",
"inQuantity": "5",
"article": {
"articleKey": "article5",
"quantity": "500",
"PON": "Art_PO500",
"SNN": "Art_SN500"
}
}
]
},
"p1": "pack5",
"p2": "pack5",
"store": true
}
]
}
Solution found. "form: true" must not be given because this overrides the content-type.
You can pass the contents of the fixture file(which is json) in the request body like this:
describe('Some Test Suite', function() {
// we can use these values to log in
const username = 'jane.lane'
const password = 'password123'
it('logs in to connector through REST API', () => {
cy.fixture('my-request.json').then(myFixture => {
cy.request({
method: 'POST',
url: 'localhost:8095/connector/demands/v1/demandData',
auth: {
username,
password,
},
failOnStatusCode: false,
form: true,
body: myFixture
})
})
})
})
For HTTP auth you have to use. You can check out this cypress recipe.
auth: {
username,
password,
}

How to validate the contents inside the JSON body

In postman i want to to validate '"name": "Twilio"', which is inside data > twilio > viewable > name
here is the JSON response ive got
{
"success": true,
"timestamp": "2019-08-12T12:31:33+00:00",
"response_code": 200,
"data": {
"twilio": {
"name": "Twilio",
"slug": "twilio",
"image": "https://s3-eu-west-1.amazonaws.com/connector-assets/images/twilio.png",
"description": "Twilio is a cloud communications platform as a service. Integrate your Twilio account to send outgoing SMS from Purple.",
"category": "communication",
"connectedCount": 1,
"allowMultipleAdd": false,
"editable": [],
"viewable": {
"cf-5d51503868af3": {
"name": "Twilio"
}
},
"id": "cf-5d515c2527579",
"overrideAllowed": false
},
"salesforce-mc": {
"name": "Salesforce marketing cloud",
"slug": "salesforce-mc",
"image": "https://s3-eu-west-1.amazonaws.com/connector-assets/images/sf-mc.png",
"description": "Salesforce Marketing Cloud is a provider of digital marketing automation and analytics software and services.",
"category": "marketing-automation",
"connectedCount": 0,
"allowMultipleAdd": true,
"editable": [],
"viewable": [],
"id": "cf-5d515c252bc31",
"overrideAllowed": true
}
}
}
The easiest way is to process the response as JSON, and simply check your hierarchy:
In the tests section, you can add a number of tests:
pm.test("Response should be OK", function () {
pm.response.to.be.ok;
});
// You can actually check for explicit response code if a 200 series is not enough.
pm.test("Status code is 200", function () {
pm.response.to.have.status(200);
});
// Optionally test the returned Content-Type is correct.
pm.test("Content-Type is present", function () {
pm.response.to.have.header("Content-Type");
});
pm.test("Response should be okay to process", function () {
pm.response.to.be.ok;
pm.response.to.not.be.error;
});
pm.test("Body contains JSON data result with Twilio as the viewable name", function () {
const JsonData = pm.response.json();
pm.expect(JsonData.data.twilio.viewable.name).to.equal('Twilio');
});
For safety, you can check that each parent element exists first (validate data is in JsonData) to avoid errors should the payload change or not match what you expect.
EDIT: Your JSON structure:
{
"success": true,
"timestamp": "2019-08-12T12:31:33+00:00",
"response_code": 200,
"data": {
"twilio": {
"name": "Twilio",
"slug": "twilio",
"image": "https://s3-eu-west-1.amazonaws.com/connector-assets/images/twilio.png",
"description": "Twilio is a cloud communications platform as a service. Integrate your Twilio account to send outgoing SMS from Purple.",
"category": "communication",
"connectedCount": 1,
"allowMultipleAdd": false,
"editable": [],
"viewable": {
"cf-5d51503868af3": {
"name": "Twilio"
}
},
"id": "cf-5d515c2527579",
"overrideAllowed": false
},
"salesforce-mc": {
"name": "Salesforce marketing cloud",
"slug": "salesforce-mc",
"image": "https://s3-eu-west-1.amazonaws.com/connector-assets/images/sf-mc.png",
"description": "Salesforce Marketing Cloud is a provider of digital marketing automation and analytics software and services.",
"category": "marketing-automation",
"connectedCount": 0,
"allowMultipleAdd": true,
"editable": [],
"viewable": [],
"id": "cf-5d515c252bc31",
"overrideAllowed": true
}
}
}
Based on this, the text you are looking for is present, but under an ID, not directly available as you indicated. There are two checks that could be done:
1. Use the name in the main block
pm.test("Body contains JSON data result with Twilio as the viewable name", function () {
const JsonData = pm.response.json();
pm.expect(JsonData.data.twilio.name).to.equal('Twilio');
});
The other would be to extract the viewable value ('cf-5d51503868af3') and use this value as a key to do the test. Not sure if this is available to you from your user id or another data source. If not, then you need to extract it from the JsonData.data.twilio.viwable object. There are some more useful examples here in this answer.

InlineQueryResultArticle of answerInlineQuery in Telegram Bot API with Google Apps Script

I'm using google apps script for Telegram Bot API & I'm having problem with InlineQueryResultArticle in answerInlineQuery method.
function answerInlineQuery(iqid, result){
var data = {
method: "post",
payload: {
method: "answerInlineQuery",
inline_query_id: iqid,
results:JSON.stringify(result)
}
}
}
Here is the format of result :-
var result= {
InlineQueryResultArticle:[
{type:'article',id: iqid, title:"RESULT 1", input_message_content:"TEXT 1"},
{type:'article',id: iqid, title:"RESULT 2", input_message_content:"TEXT 2"}
]
};
answerInlineQuery(iqid, result);
I have turned on Inline Mode in #BotFather. My bot is also receiving inline queries and for every request I can see my inline query id properly & I can also see the result receiving as [object Object].
But, the problem is I'm not getting any results.
REF: In answerinlinequery, the results should be a JSON-serialized array of results for the inline query using any of these results.
Can anyone point out where am I going wrong ?
The id field for a InlineQueryResultArticle must be unique for each result. However you are setting the id as iqid for both results.
You should replace them with custom ids.
var result= {
InlineQueryResultArticle:[
{type:'article',id: "1", title:"RESULT 1", input_message_content:"TEXT 1"},
{type:'article',id: "2", title:"RESULT 2", input_message_content:"TEXT 2"}
]
};
After many attempts I found solution:
Here there are an inline answer with three results
****Be careful :change value of document_file_id with a sample file_id from your bot else you will see an error
//your bot token placed here
const token = "";
tgmsg('answerInlineQuery', {
"inline_query_id": update['inline_query']['id'],
"results": JSON.stringify([
//inline result of an article with thumbnail photo
{
"type": "article",
"id": "1",
"title": "chek inline keybord ",
"description": "test ",
"caption": "caption",
"input_message_content": {
"message_text": "you can share inline keyboard to other chat"
},
"thumb_url": "https://avatars2.githubusercontent.com/u/10547598?v=3&s=88"
},
//inline result of an article with inline keyboard
{
id: "nchfjdfgd",
title: 'title',
description: "description",
type: 'article',
input_message_content: {
message_text: "inline is enabled input_message_content: {message_text: message_text}message_text"
},
reply_markup: {
"inline_keyboard": [
[{
"text": "InlineFeatures.",
"callback_data": "inline_plugs_1118095942"
}],
[{
"text": "OtherFeatures.",
"callback_data": "other_plugs_1118095942"
}]
]
}
},
//inline result of a cached telegram document with inline keyboard
{
id: "nchgffjdfgd",
title: 'title',
description: "description",
//change this on with the value of file_id from telegram bot api
document_file_id: "BQACAgQAAxkBAAIBX2CPrD3yFC0X1sI0HFTxgul0GdqhAALjDwACR4pxUKIV48XlktQNHwQ",
type: 'document',
caption: "caption ghh hhdd",
reply_markup: {
"inline_keyboard": [
[{
"text": "InlineFeatures.",
"callback_data": "inline_plugs_1118095942"
}],
[{
"text": "OtherFeatures.",
"callback_data": "other_plugs_1118095942"
}]
]
}
}
])
})
function tgmsg(method, data) {
var options = {
'method': 'post',
'contentType': 'application/json',
'payload': JSON.stringify(data)
};
var responselk = UrlFetchApp.fetch('https://api.telegram.org/bot' + token + '/' + method, options);
}

Parsing json_callback response from server Angular 4

Using Angular 4, I sent a get request to this url https://api.flickr.com/services/feeds/photos_public.gne?jsoncallback=JSON_CALLBACK&format=json&tagmode=all&tags=test
with following code,
this.http.get('https://api.flickr.com/services/feeds/photos_public.gne?jsoncallback=JSON_CALLBACK', {
params: { format: 'json', tagmode: 'all', tags: query }
})
.subscribe(data => {
console.log(data);
});
The response I get is in the following format, wrapped as a method argument.
JSON_CALLBACK({
"title": "Recent Uploads tagged test",
"link": "https:\/\/www.flickr.com\/photos\/tags\/test\/",
"description": "",
"modified": "2018-02-04T14:51:42Z",
"generator": "https:\/\/www.flickr.com",
"items": [
{
"title": "Desktop2018-02-04-14_39_44.jpg",
"link": "https:\/\/www.flickr.com\/photos\/besnaveld\/28298869359\/",
"media": {"m":"https:\/\/farm5.staticflickr.com\/4769\/28298869359_e932760377_m.jpg"},
"date_taken": "2018-02-04T06:51:42-08:00",
"description": " <p><a href=\"https:\/\/www.flickr.com\/people\/besnaveld\/\">besnaveld<\/a> posted a photo:<\/p> <p><a href=\"https:\/\/www.flickr.com\/photos\/besnaveld\/28298869359\/\" title=\"Desktop2018-02-04-14_39_44.jpg\"><img src=\"https:\/\/farm5.staticflickr.com\/4769\/28298869359_e932760377_m.jpg\" width=\"240\" height=\"135\" alt=\"Desktop2018-02-04-14_39_44.jpg\" \/><\/a><\/p> ",
"published": "2018-02-04T14:51:42Z",
"author": "nobody#flickr.com (\"besnaveld\")",
"author_id": "154665852#N05",
"tags": "test booth"
} ]
})
How can I extract the data inside this JSON_CALLBACK function argument?
based on filckr document simply add
nojsoncallback=1 -> {...}
jsoncallback=wooYay -> wooYay({...});
to your request to get it right . then your url should be :
https://api.flickr.com/services/feeds/photos_public.gne?nojsoncallback=1&format=json&tagmode=all&tags=test

MongoDB, NodeJS: updating an embedded document with new members

Using: MongoDB and native nodeJS mongoDB driver.
I'm trying to parse all the data from fb graph api, send it to my API and then save it to my DB.
PUT handling in my server:
//Update user's data
app.put('/api/users/:fbuser_id/:category', function(req, res) {
var body = JSON.stringify(req.body);
var rep = /"data":/;
body = body.replace(rep, '"' + req.params.category + '"' + ':');
req.body = JSON.parse(body);
db.fbusers.update({
id: req.params.fbuser_id
}, {
$set: req.body
}, {
safe: true,
multi: false
},
function(e, result) {
if (e) return next(e)
res.send((result === 1) ? {
msg: 'success'
} : {
msg: 'error'
})
});
});
I'm sending 25 elements at a time, and this code just overrides instead of updating the document.
Data I'm sending to the API:
{
"data": [
{
"category": "App page",
"name": "SoundCloud",
"id": "7919071058",
"created_time": "2013-09-16T18:16:59+0000"
},
{
...and so on
}
]
}
Basically my API changes "data" key from sent json to the category name, f.e.:
PUT to /api/users/000/likes will change the "data" key to "likes":
{
"likes": [
{
"category": "App page",
"name": "SoundCloud",
"id": "7919071058",
"created_time": "2013-09-16T18:16:59+0000"
},
{
...and so on
}
]
}
Then this JSON is put to the db.
Hierarchy in mongodb:
{
"_id": ObjectID("556584c8e908f0042836edce"),
"id": "0000000000000",
"email": "XXXX#gmail.com",
"first_name": "XXXXXXXX",
"gender": "male",
"last_name": "XXXXXXXXXX",
"link": "https://www.facebook.com/app_scoped_user_id/0000000000000/",
"locale": "en_US",
"name": "XXXXXXXXXX XXXXXXXXXX",
"timezone": 3,
"updated_time": "2015-05-26T18:11:59+0000",
"verified": true,
"likes": [
{
"category": "App page",
"name": "SoundCloud",
"id": "7919071058",
"created_time": "2013-09-16T18:16:59+0000"
},
{
"category": "App page",
"name": "SoundCloud",
"id": "7919071058",
"created_time": "2013-09-16T18:16:59+0000"
},
{
....and so on
}
]
}
So the problem is that my api overrides the field (in this case "likes") with newly sent data, instead of appending it to already existing data document.
I am pretty sure that I should be using other parameter than "$put" in the update, however, I have no idea which one and how to pass parameters to it programatically.
Use $push with the $each modifier to append multiple values to the array field.
var newLikes = [
{/* new item here */},
{/* new item here */},
{/* new item here */},
];
db.fbusers.update(
{ _id: req.params.fbuser_id },
{ $push: { likes: { $each: newLikes } } }
);
See also the $addToSet operator, it adds a value to an array unless the value is already present, in which case $addToSet does nothing to that array.