I'm attaching user info (got by authorization header) with each request (post/put/get/delete) to request headers
...
req.headers.user = {
phone: "+37066666666",
id: "bda5a3c0-2e95-4d6d-bf1f-6c1c8f1edcaa"
};
...
and I have POST request sent by POSTMAN (for example) where I'm sending this body as JSON object:
{
"title": "test",
"users": [
{
"phone": "+37066666666"
}
]
}
where later my code checks if there are owner in this users array and it should append owner if not. but I can't do that since user object that was set in headers have different phone number than phone number of the first user in the users object. Even the number is the same.
So I printed the number stored in headers and the one sent with POST request and this is what I saw:
the number stored in headers after utf=8 decode method: \x2B\x33\x37\x30\x36\x35\x31\x35\x36\x35\x39\x30\xE2\x80\xAC\xE2\x80\xAC\xE2\x80\xAC
and the number sent with POST request:
\x2B\x33\x37\x30\x36\x35\x31\x35\x36\x35\x39\x30
so how this can be fixed? apparently my method to find user doesn't work since the numbers "are not the same"
req.body.users.find(v => v.phone === req.headers.user.phone)
this method will return "undefined" even the printed v.phone and req.headers.user.phone values are the same (on console).
the problem was my macbook "paste" function. it was pasting invisible characters:
"users": [
{
"phone": "+370...<202c><202c>",
...
}
Related
I am having a nodejs code trigerring sendgrid email to 1000+ users. When the number users is less (100-200)this works fine. But when there are 1000+ users it fails at a point and the rest of the mails are not triggered. When i check the app service it is shown as SNAT port exhaustion.
userList.forEach(async(Element) => {
console.log(Element.userId);
let textContentUser="";
let emailContentUser="";
textContentUser=textContent;
var userData=await db.collection('masterUserDetails').find({"userId":Element.userId}).toArray();
if(userData.length>0)
{
textContentUser=textContentUser.split("{{FirstName}}").join(userData[0]["givenName"]);
textContentUser=textContentUser.split("{{FullName}}").join(userData[0]["preferredName"]);
var leadReviewerData=await db.collection('masterUserDetails').find({"userId":userData[0]["counselorEmail"]}).toArray();
if(leadReviewerData.length==0)
{
textContentUser=textContentUser.split("{{LeadReviewerFullName}}").join(userData[0]["counselorName"]);
textContentUser=textContentUser.split("{{LeadReviewerFirstName}}").join(userData[0]["counselorName"]);
}
else
{
textContentUser=textContentUser.split("{{LeadReviewerFullName}}").join(leadReviewerData[0]["preferredName"]);
textContentUser=textContentUser.split("{{LeadReviewerFirstName}}").join(leadReviewerData[0]["givenName"]);
}
}
console.log("final Text cintent: ",textContentUser);
emailContentUser=emailContent;
emailContentUser=emailContentUser.replace("***content***",textContentUser);
//console.log("final email cintent: ",emailContentUser);
const msg = {
to: Element.userId, // Change to your recipient
bcc:"support_test#abc.com",
from: {
"email": "support#abc.com",
"name": "MY APP"
}, // Change to your verified sender
subject: emailSubject,
html: emailContentUser,
attachments: [
{
filename:"image002.gif",
content: img2,
content_id:"image002",
disposition:"inline"
},
{
filename:"image004.gif",
content: img4,
content_id:"image004",
disposition:"inline"
}],
reply_to: {
"email": "support.test#abc.com",
"name": "My APP Support"
},
send_at: sendAt
}
console.log("sending mail")
sgMail
.send(msg)
.then((response) => {
console.log("Success--------"+response[0].statusCode)
//console.log(response[0].headers)
})
.catch((error) => {
// console.log("error");
console.log("Error--------"+JSON.stringify(error))
})
});
This works in local. works when deployed in azure with lesser users also.
As others have noted, you're running out of SNAT ports to make the HTTP request to the SendGrid API.
I would recommend avoiding making an HTTP request for every email you want to send and instead use the built-in APIs to send multiple emails using one HTTP request.
To do so, add a personalizations property to your msg with an array. Add objects to the array to override the msg properties for that specific personalization, properties like subject, from, to, etc. as documented here. You can add a max of 1000 items to the personalizations array. So if you want to send more than 1000 emails, you'll need to create a separate msg for every 1000 emails, but now you only send a single HTTP request for every 1000 emails, so you shouldn't run into SNAT port errors as quickly.
Now, if you're using a single email body template but want to personalize the email, you can use Substitution Tags in your template and add a substitutions property to your personalization objects with an object holding the data you want to substitute.
Note: The total collective size of your substitutions may not exceed 10,000 bytes per personalization object.
The default substitution wrapper is "{{" and "}}" for the node.js library. Here's an example how using one msg, you can send multiple emails using personalizations and substitutions:
const sgMail = require('#sendgrid/mail');
sgMail.setApiKey(process.env.SENDGRID_API_KEY);
const recipients = [
{
emailAddress: "recipient1#email.address",
preferredName: "Jonny",
counselorName: "Smith"
},
{
emailAddress: "recipient2#email.address",
preferredName: "Jay",
counselorName: "Smith"
}
];
const msg = {
// this will create an array of objects with `to` and `substitutions ` properties
personalizations: recipients.map(r => {
return {
to: r.emailAddress,
substitutions: {
preferredName: r.preferredName,
counselorName: r.counselorName
}
}
}),
from: 'your#sendgrid.sender',
subject: 'Ahoy!',
html: `<p>Ahoy {{preferredName}}!</p>
<p>It is a pleasure to meet you.</p>
<p>Best, {{counselorName}}</p>`
};
sgMail.send(msg).then(() => {
console.log('emails sent successfully!');
}).catch(error => {
console.log(error);
});
Pay attention to the html template containing substitution tags like {{preferredName}} and {{counselorName}}. These tag names have to match with the keys of the object in the substitutions property.
Warning: Substitution tags will not automatically HTML encode user input, so you have to HTML encode it yourself to prevent HTML injection attacks. You can learn more about HTML injection attacks here.
If you don't need to store the email body template in your code, you can use Dynamic Email Template as shown in this sample. You can create Dynamic Email Templates in the SendGrid app and use handlebar templating to add template data into your emails.
Updating the previous example with Dynamic Email Templates would look like this:
const msg = {
// this will create an array of objects with `to` and `dynamicTemplateData` properties
personalizations: recipients.map(r => {
return {
to: r.emailAddress,
dynamicTemplateData: {
preferredName: r.preferredName,
counselorName: r.counselorName
}
}
}),
from: 'your#sendgrid.sender',
templateId: 'd-[REPLACE_WITH_YOUR_TEMPLATE_ID]'
};
sgMail.send(msg).then(() => {
console.log('emails sent successfully!');
}).catch(error => {
console.log(error);
});
The subject and substitutions properties have been removed. The templateId and dynamicTemplateData have been added.
Note: Dynamic Email Templates use handlebar templating which will HTML encode user input, protecting you from HTML injection.
Last suggestion: Twilio recommends schedule your bulk emails by using the sendAt property instead of sending them right now.
Quoting from the SendGrid docs:
This technique allows for a more efficient way to distribute large
email requests and can improve overall mail delivery time performance.
This functionality:
Improves efficiency of processing and distributing large volumes of email.
Reduces email pre-processing time.
Enables you to time email arrival to increase open rates.
Is available for free to all SendGrid customers.
Hello I'm trying to access to an especific key from a JSON. I'm using node.js and angular 7
The JSON I got is stringfy and it comes from an API.
This is the JSON I got
"search": {
"entry": [
{
"dn": "uid=080030781,c=mx,ou=s,o=i.com",
"attribute": [
{ "name": "mail", "value": ["CAMILA.CAMPOS.TELLEZ#mail.com", "MX08#mail.com"] }]
}
],
"return": {
"code": 0,
"message": "Success",
"count": 1
}
}
}
I need to access to the key "value", because I need to get the value "camila.campos.tellez#mail.com".
I get the JSON from an API declarated in a node.js file called app.js, then I catch the response from it using this service.ts file
getApproverMail(name) {
console.log('entered to rootservice');
return this.http.get(this.baseUrl + '/costing/operations?name=' + name);
}
Finally I can access to this through a component.ts fil with this code
findApproverMail() {
this.rootService.getApproverMail(this.aproverName).subscribe((res) => {
this.email = res;
console.log('Test: ' + res);
});
}
And the browser console prints the JSON I have show you. But how can I access only to the mail's value?
P.D I need only the mail because after I got it the web site needs to send an email to that direction
JSON stands for JavaScript Object Notation. Any valid JSON is an object in JavaScript (and TypeScript). You can use dot notation to navigate into the object:
findApproverMail() {
this.rootService.getApproverMail(this.aproverName).subscribe((res) => {
this.email = res.search.entry[0].attribute[0].value[0];
console.log('Test: ' + res);
});
}
I would recommend defining an interface in the shape of what you expect from the service. It's cleaner than just indexing around an any typed object.
Also note that I hard code 0 indexes because that answers your question. You might consider a more dynamic / flexible way to get the address or elements you need.
I need to retrieve the inventory summary for all Stock Items so that I can update an external site's inventory according to the "Available For Shipment" field on the inventory summary. I have attempted running the inventory summary via the rest API using the following method after logging in:
URL: https://mycompany.acumatica.com/entity/Default/6.00.001/InventorySummaryInquiry
Method: PUT
Request Body:
{
"InventoryID": "CW-500-MC-30"
}
However I receive this response:
{
"message": "The request is invalid.",
"modelState": {
"": [
"Error reading JObject from JsonReader. Current JsonReader item is not an object: String. Path 'InventoryID', line 2, position 30."
]
}
}
If there is a way to run the inquiry and have it return ALL stock items in an array, that would be ideal.
If that's not possible, what do I need to change to get the individual stock item inventory summary to work?
UPDATE:
After modifying my request body as #samol518 suggested, the request worked, but returned a very limited set of data (below). I'm looking to get to the "quantity available for shipment". Do I need to provide additional parameters to get more data returned?
{
"id": "bf8e0bbc-63dc-4491-802d-090367af203a",
"rowNumber": 1,
"note": null,
"ExpandByLotSerialNumber": {},
"InventoryID": {
"value": "CW-500-MC-30"
},
"LocationID": {},
"WarehouseID": {},
"custom": {},
"files": []
}
If I am not mistaken the correct structure for the Request Body should resemble the following :
Request Body :
{
"InventoryID": {"value": "CW-500-MC-30"}
}
Though if you want to retrieve all Stock Item, you could try and customize the inquiry in order to do so.
Update:
in order to retrieve all record, you might notice that the result fields are in a sub entity in the endpoint definition on the Web Service Endpoint screen (SM207060).
in order to return the data for these detail type sub entities, you must add the expand key word to your URL in the following format.
$expand=results
So your final URL should look like :
https://mycompany.acumatica.com/entity/Default/6.00.001/InventorySummaryInquiry?$expand=Results
In telegram API documentation I see: "You can either pass a file_id as String to resend a photo that is already on the Telegram servers", but I can't find ways to get file_id of uploaded file. How can I get it?
Its depended to your content_types ,for example:
Video:
message.video.file_id
Audio:
message.audio.file_id
Photo:
message.photo[2].file_id
For more see this link.
This is the easiest way I've found to do it.
Upload your file to any chat and forward the message to #RawDataBot. It will return something like this:
{
"update_id": 754677603,
"message": {
"message_id": 403656,
"from": {
"id": xxx,
"is_bot": false,
"first_name": "xxx",
"username": "xxx",
"language_code": "en"
},
"chat": {
"id": xxx,
"first_name": "xxx",
"username": "xxx",
"type": "private"
},
"date": 1589342513,
"forward_from": {
"id": xxx,
"is_bot": false,
"first_name": "xxx",
"username": "xxx",
"language_code": "en"
},
"forward_date": 1589342184,
"document": {
"file_name": "filename.pdf",
"mime_type": "application/pdf",
"file_id": "This_Is_The_Thing_You_Need",
"file_unique_id": "notthis",
"file_size": 123605
}
}
}
What you need is the string under file_id. Once you have copied that, you can simply the following code to send the message.
context.bot.sendDocument(chat_id=update.effective_chat.id,
document = "Your_FILE_ID_HERE")
Depending on the method (File type) which you chose to send a file, after sending a file to Telegram a response is returned. For example if you send a MP3 file to Telegram using sendAudio method, Telegram returns an Audio object which contains the file ID.
Source: https://core.telegram.org/bots/api#audio
In addition to the answers above, you can log Updates that comes to your bot, Either from https://api.telegram.org/bot'.BOT_TOKEN.'/getUpdates or throw updates that come in your application. there you will find a Json property like below:
{
"update_id" = 1111111,
"message" =
{
"message_id" = 1111111,
"from" =
{
"id" = 111111,
...
}
"chat" =
{
"id" = 111111,
...
}
"date" = 111111,
"photo" =
{
{
"file_id" = HERE IS YOU FILE ID 1,
"file_size" => XXXX,
"width" => XX,
"height" => XX,
}
}
}
}
Say you receive a Message with an array of PhotoSize
https://core.telegram.org/bots/api#photosize
As you can see, there's a file_id, you can use this to send a photo through sendPhoto.
If we assume Update is an object, with in it a Message object, which in turn provides a Chat object with in it a id of the chat where the initial message came from and an array of PhotoSize (excuse me for using PHP here, but that's my main language...)
$update->message->photo is how you can access the array.
Use some kind of For loop to iterate over the items, or just access the first one if the array isn't bigger than 1.
After that, you can use the result(s) to extract the file_id and send it as a string via sendPhoto's photo parameter and the Chat ID via the chat_id parameter.
I hope this helped!
P.S. Here is a diagram of my current implementation of the API, i hope it brings some clarity to you!
if you use PHP:
you can write this line for full size:
$file_id = $updates['message']['photo'][1]['file_id'];
and this line for thumb:
$file_id = $updates['message']['photo'][0]['file_id'];
According to the latest docs (v20.0a6) plenty of classes have been changed. I have found that the easiest way to get started with files is using the effective_attachment property.
async def handle_file(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
media_item = await context.bot.get_file(update.message.effective_attachment[0].file_id)
media_url = media_item.file_path
For declaring the handler there have also been changes to filters, here is a simple way to declare it:
application.add_handler(MessageHandler(filters.ATTACHMENT, handle_file))
I'm working on a project that involves making multiple HTTP GET requests to different APIs, each requiring information from the last. I'm trying to avoid nested-callaback-and-counter-hell, and have been trying to get it working with the async module.
This is what I need to do: I have an array of 1..n course identifiers (['2014/summer/iat/100/d100', '2014/spring/bisc/372/d100']). For each course in the array, I need to fetch its course outline via a HTTP GET.
The resulting outline looks something like this:
{
"info": {
"nodePath": "2014/spring/bisc/372/d100",
"number": "372",
"section": "D100",
"title": "Special Topics in Biology",
"term": "Spring 2014",
"description": "Selected topics in areas not currently offered...",
"name": "BISC 372 D100",
"dept": "BISC",
},
"instructor": [
{
"lastName": "Smith",
"commonName": "Frank",
"phone": "1 555 555-1234",
"email": "franksmith#school.edu",
"name": "Frank Smith",
"roleCode": "PI"
},
{
"lastName": "Doe",
"commonName": "John",
"phone": "1 555 555-9876",
"email": "johndoe#school.edu",
"name": "John Doe",
"roleCode": "PI"
}
]
}
(a bunch of non-relevant fields omitted)
Each outline object may contain an instructor property which is an array of 0..n instructor objects for the course. For each member of the instructor array, I need to then call another API to get additional data. When that call returns, I need to insert it into the right instructor object.
Finally, when everything is done, the data gets passed to a template for express to render and return to the client.
I've tried getting this working using async and had some success with async.waterfall when doing a proof-of-concept with only getting one of the instructor profiles (e.g. not looping over the array, just getting instructor[0]). The async module's docs are comprehensive, but pretty dense and I'm having a hard time determining what I actually need to do. I had a Frankenstein combination of various nested async calls which still didn't work.
I don't really care how I accomplish the task - flow-control, promises, magic pixie dust, whatever. Any hints greatly appreciated.
Using Q for promises, you can probably do something like this:
return Q
.all(course_ids.map(function(course) {
return HTTP.GET(course); // Assuming this returns a promise
}))
.then(function(course_data) {
var instructors = [];
course_data.forEach(function(course) {
var p = Q
.all(course.instructor.map(function(instructor) {
return HTTP.GET(instructor.id);
}))
.then(function(instructors) {
course.instructors_data = instructors;
return course;
});
promises.push(p);
});
return Q.all(promises);
});
Will resolve with an array containing the courses, each of which contains
an array of instructor data in its instructors_data value.
You could use async.each(), which would do the API requests in parallel (assuming there is no concurrent API request limits on the server side, if that is the case, use async.eachLimit() instead):
async.each(instructors, function(instructor, callback) {
// call API here, store result on `instructor`,
// and call `callback` when done
}, function(err){
if (err)
console.log('An error occurred while processing instructors');
else
console.log('All instructors have been processed successfully');
});