I'm trying to get a list of emails that contain attachments,
I'm getting a list of messages, each message contains 2 properties - id and threadID - I assumed that since the messages do not hold an AttachmentID property, they do not have one either.
I didn't find a way to retrieve only messages with attachments.
This is the code:
function execute() {
return gapi.client.gmail.users.messages.list({
"userId": "myid#gmail.com",
"includeSpamTrash": false,
"maxResults": 100,
}).then(function (response) {
// Handle the results here (response.result has the parsed body).
console.log("Response", response);
},
function (err) { console.error("Execute error", err); });
}
function execute() {
return gapi.client.gmail.users.messages.list({
"userId": "myid#gmail.com",
"q": "has:attachment", // This right here
"includeSpamTrash": false,
"maxResults": 100,
})
.then(
function (response) {
// Handle the results here (response.result has the parsed body).
console.log("Response", response);
},
function (err) {
console.error("Execute error", err)
}
)
}
The "q" parameter has a horde of options you can use to filter the output. This also works in the Gmail UI.
To retrieve only the messages that contains an attachment, you should use the method users.messages.list while including a q parameter to show only messages with attachments. That q parameter can be set up with the string has:attachment. On JavaScript that requests looks like the following:
function execute() {
return gapi.client.gmail.users.messages.list({
"userId": "{ YOUR USERID HERE }",
"q": "has:attachment"
})
.then(function(response) {
console.log("Response", response);
},
function(err) { console.error("Execute error", err); });
}
Please remember to update the userId parameter to match your own scenario.
UPDATE
By reading your new comment I understand that your end goal is to retrieve the attachmentId field. You can do so very easily just by expanding the above request. You only have to keep in mind that the above function returns a message id that can be used to retrieve a Message object containing a MessagePart inside the payload field. That same MessagePart object contains a MessagePartBody object inside the body field. Finally, that MessagePartBody contains the attachmentId field.
To make it clearer I will describe the process step by step:
You run the above users.messages.list function and get multiple id in return.
For each id, you run a users.messages.get function to get a Message object. That function can be similar to this example:
function execute() {
return gapi.client.gmail.users.messages.get({
"userId": "{ YOUR USERID HERE }",
"id": "{ THE MESSAGE ID HERE }"
})
.then(function(response) {
console.log("Response", response);
},
function(err) { console.error("Execute error", err); });
}
The step above will return a Message object with multiple MessagePart inside. Since you are only interested in the attachments MessagePart then you need to interact every one of them checking that the filename field isn't empty (because only attachments MessagePart have a populated filename field). Please bear in mind that there is one MessagePart per every attachment in the email.
Now you have identified which MessagePart contains info about the attachment. Finally, you only need to check the body property of that MessagePart, and read the attachmentId field inside.
Related
I'm doing a basic 'Visitor Book' function.
Users can submit a little form (with three inputs : name, msg and emoji).
I grab it with req.body in my router component. I'm using nodejs, with express and bodyparser.
I only want to store this data in a JSON, don't want any database involved here.
I'm in trouble with the writeFile method, using 'fs' module.
It work but it push the new data outside the single-array of my JSON file.
Do you know if I can push in inside the array ? Like a .push method, but with writeFile/appendFile/wathever that works good with json files.
Here is my code :
app.post (router) :
app.post('/visitorBook', async (req, res) => {
let formData = {
name: req.body.name,
msg: req.body.msg,
emoji: req.body.emoji
}
try {
console.log(req.body)
let data = JSON.stringify(formData, null, 2);
fs.writeFile("./views/scripts/dataVisitorBook.json", data, { { // dataVisitorBook.json is the storage file
flag:'a' // this flag specify 'please append it' over 'please override file'
}
}, (err) => {
console.log('error :', err)
});
res.redirect('/contact')
} catch (error) {
console.error('/visitorBook route error : ', error)
}
})
My JSON :
[
{
"name": "test1",
"msg": "test1",
"emoji": "<i class='fas fa-hippo fa-3x'></i>"
},
{
"name": "test2",
"msg": "test2",
"emoji": "<i class='fas fa-hippo fa-3x'></i>"
}
]
{
"name": "sd",
"msg": "sd",
"emoji": "<i class='fas fa-kiwi-bird fa-3x'></i>"
}
So the last one with "sd" in name and msg is the pushed one. The 2 other are manually written by me, for readFile tests.
I hope I provided all the information needed. Not used to post here...
Thanks you.
If you read from the existing file and parse it with JSON.parse, you will be able to actually use Array.push on it. And then you can write the stringified result back into the file:
fs.readFile("./views/scripts/dataVisitorBook.json", function (err, data) {
if (err) throw err;
let data = JSON.parse(data.toString('utf8'));
data = JSON.stringify(data, null, 2);
fs.writeFile("./views/scripts/dataVisitorBook.json", data, { { // dataVisitorBook.json is the storage file
flag:'a' // this flag specify 'please append it' over 'please override file'
}
}, (err) => {
console.log('error :', err)
});
})
It might not be optimal though as it is likely to take more time as the file grows bigger.
I appreciate your simple try But using some standards can be much better to you
There are some Standard JSON DBs for Node like :
Simple JSON DB
Node JSON DB
Also, you can try SQLite
I also try with a simple JSON file of use as DB. I faced lots of work and I have managed it too. So my advice is to use some standard libraries
Apart from it, you have to get the file data Parse it as JSON (Decoding) make changes and again serialize it and write into a file (Encoding).
[SOLVED]
Thanks to #Divarrek , I've archieved to make it work.
So :
Read the file with fs.readFileSync.
Then, I store this rawdata in a variable, while parsing it to JSON.
THen, I push it in the 'jsonBook' variable which is the json file temporarly made into a simple object-variable.
Then I write in the file with writeFile, passing the data as variable 'parsed', which contain a JSON.stringified version of my 'jsonBook'
app.post("/visitorBook", async (req, res) => {
let formData = {
name: req.body.name,
msg: req.body.msg,
emoji: req.body.emoji,
};
try {
let rawdata = fs.readFileSync("./views/scripts/dataVisitorBook.json");
var jsonBook = JSON.parse(rawdata);
let formDataParsed = JSON.stringify(formData, null, 2);
jsonBook.push(formData);
let parsed = JSON.stringify(jsonBook, null, 2);
fs.writeFile("./views/scripts/dataVisitorBook.json", parsed, (err) => {
if (err) throw err;
console.log("saved");
});
res.redirect("/contact");
} catch (error) {
console.error("/visitorBook route error : ", error);
}
});
I hope I was clear. Maybe I did some explanation error, I'm trying my best.
I am trying to develop a bot for FB Messenger and I'm always getting stuck with their documentation. Currently, I tried to add a Greeting Text and a Get_Started button in JavaScript, so I will be able to modify it easily. It seems like most of their documentation is in PHP or they just telling you to add it by sending a POST request using CURL, which worked for me, but again, it's not so modular.
I can't find proper documentation in JavaScript. and the only one is this:
https://www.techiediaries.com/build-messenger-bot-nodejs/
But I can't find the place where you actually call the greeting or get started functions.
there is also this https://github.com/fbsamples/original-coast-clothing
but I still can't find where they trigger the Greetings and the Get_Started postbacks. Only the json file where they store it /locales/en_US.json "profile".
My code currently has
// Accepts POST requests at /webhook endpoint
app.post('/webhook', (req, res) => {
// Parse the request body from the POST
let body = req.body;
// Check the webhook event is from a Page subscription
if (body.object === 'page') {
// Iterate over each entry - there may be multiple if batched
body.entry.forEach(function(entry) {
// Get the webhook event. entry.messaging is an array, but
// will only ever contain one event, so we get index 0
let webhook_event = entry.messaging[0];
console.log(webhook_event);
// Get the sender PSID
let sender_psid = webhook_event.sender.id;
console.log('Sender PSID: ' + sender_psid);
// Check if the event is a message or postback and
// pass the event to the appropriate handler function
if (webhook_event.message) {
handleMessage(sender_psid, webhook_event.message);
} else if (webhook_event.postback) {
handlePostback(sender_psid, webhook_event.postback);
}
});
// Return a '200 OK' response to all events
res.status(200).send('EVENT_RECEIVED');
} else {
// Return a '404 Not Found' if event is not from a page subscription
res.sendStatus(404);
}
});
function setupGreetingText(res){
var messageData = {
"greeting":[
{
"locale":"default",
"text":"Greeting text for default local !"
}, {
"locale":"en_US",
"text":"Greeting text for en_US local !"
}
]};
request({
"uri": "https://graph.facebook.com/v2.6/me/messages",
"qs": { "access_token": process.env.PAGE_ACCESS_TOKEN },
"method": 'POST',
"headers": {'Content-Type': 'application/json'},
"form": messageData
},
function (error, response, body) {
if (!error && response.statusCode == 200) {
// Print out the response body
res.send(body);
} else {
// TODO: Handle errors
res.send(body);
}
});
}
but I still dont know how to trigger it.
Examples on the documentation look like this. This is how you break it down. Final result can be found below.
curl -X POST -H "Content-Type: application/json" -d '{
"get_started": {"payload": "<postback_payload>"}
}' "https://graph.facebook.com/v2.6/me/messenger_profile?access_token=<PAGE_ACCESS_TOKEN>"
Third word is the type of request you'll send and should be defined inside the method property.
Between the curly braces, is how the content inside the json property should be formatted.
The link on the last line is the link you should provide to the uri property minus the query part ?access_token=<PAGE_ACCESS_TOKEN>
SendAPI's uri is https://graph.facebook.com/v8.0/me/messages (you're using this)
MessengerProfileAPI's uri is https://graph.facebook.com/v2.6/me/messenger_profile (use this instead)
In the end, your request function should look something like this:
request(
{
"uri": "https://graph.facebook.com/v2.6/me/messenger_profile",
"qs": { "access_token": process.env.PAGE_ACCESS_TOKEN },
"method": "POST",
"json": {
"get_started": {"payload": "start"}
},
},
(err) => {
if (!err) {
console.log('request sent!');
} else {
console.error("Unable to send message:" + err);
}
}
);
Even though its been almost 3 months since this question has been asked. I hope this will still come useful.
Was struggling and frustrated as you trying to implement the examples on facebook for developers documentation but I finally got to understand it after some looking and observation at other developers webhook on github.
I am trying to update a Stripe account to add an external account token to be charged later as shown in the example here.
var stripe = require("stripe")("sk_test_xxxxxxxxxxxxx"),
knex = require("knex")(config);
router.post("/paymentcardinfo",middleware.isLoggedIn,function(req,res){
knex("users.stripe").select("stripe_id_key")
.then((stripeID) => {
stripeID = stripeID[0].stripe_id_key;
console.log("My Stripe ID: "stripeID);
console.log("stripeID var type:", typeof stripeID);
stripe.accounts.update({
stripeID,
external_account: req.body.stripeToken,
}, function(err,acct) {
if(err){
console.log(err);
} else {
console.log("SUCCESS ********",acct);
// asynchronously called
}})
})
.catch((e) => {
console.log(e);
res.redirect("/paymentcardinfo")
});
});
Which returns the following
My Stripe ID: acct_xxxxxxxxxxxxx
stripeID var type: string
[Error: Stripe: "id" must be a string, but got: object (on API request to `POST /accounts/{id}`)]
where acct_xxxxxxxxxxx is the user's stored account ID. Based on the first console.log value, it would appear that stripeID is a string and not an object, which makes me unsure of how to proceed with this error.
Although the documentation specifies
stripe.accounts.update({
{CONNECTED_STRIPE_ACCOUNT_ID},
metadata: {internal_id: 42},
}).then(function(acct) {
// asynchronously called
});`
The following worked for me
stripe.accounts.update(
CONNECTED_STRIPE_ACCOUNT_ID,
{
metadata: {internal_id:42},
}
).then((account) => {
// response to successful action
I have a sample code that goes like this:
Client Helper:
getUsername: function (userId) {
Meteor.call("getUsername", userId, function (err, result) {
if(!err) {
Session.set("setUsername", result);
else {
console.log(err);
}
});
return Session.get("setUsername");
}
Server
Meteor.methods({
"getUsername": function (userId) {
var x = Meteor.users.find({_id: userId}, {fields: {username:1}}).fetch()[0];
return x.username;
}
});
The result of this code is an infinite loop of username passing to the client. Is there a way to stop the loop and pass only the data that is needed on the client? I believe the reactivity is causing the data to loop infinitely and I am not sure how to stop it. I tried using "reactive":false on my query in the server but it does not work.
If you want to access username everywhere in client templates (so thats why you put it into session), I would not set it in template helper. I would set it on startup and get username from session in template helpers (without calling server method)
If you need username just in one template, so you want to return its value from your template helper, do not put it into session, just return it in your server method callback.
Based on your sample code, I assume, you have a set of posts and you are retrieving user name based on user id for each post. Then instead of doing it this way, you should use publish composite package to publish related users as well.
Meteor.publishComposite('getPosts', function (postIds) {
return [{
find: function() {
return Posts.find({ _id: { $in: postIds }});
// you can also do -> return Posts.find();
// or -> return Posts.find({ /* or what ever your selector is to get the posts you need*/ });
},
children: [{
find: function(post) {
return Meteor.users.find({
id: post.userId //or the correct field in your post document to get user id
}, {
fields: {
"profile": 1
}
});
}
}}
}]
});
This way your publication will take care of publishing related users along with posts. You don't need to use methods and call them each time.
Just hit an insanely frustrating roadblock in prototyping. I need to update and increment values an array inside of a collection. To do this, I'm accessing the collection using the MongoDB syntax like so:
Players.update({_id: Session.get('p1_id'), 'opponents.$.id' : Session.get('p2_id')},
{$inc: {
'games_played' : 1
}}
);
When this runs I get an error saying: Uncaught Error: Not permitted. Untrusted code may only update documents by ID. [403]
Now, I searched the hell out of this and I know that it came down in an update and why they only allow update by id's. But my problem is that I can't seem to find a way around it. I tried forcing it by adding this to if (Meteor.isServer):
Players.allow({
insert: function(userId, doc, fields, modifier){
return true;
},
update: function(userId, doc, fields, modifier){
return true;
},
remove: function(userId, doc, fields, modifier){
return true;
}
});
Nothing seems to work, and all the examples I find talk about using a Meteor method (not really sure what that is) or are doing userId validation (I dont have any users and don't want to add them right now). I'm just prototyping/sketching and I'm not concerned about security. How can I proceed here?
Here's how you can make this into a method:
Meteor.methods({
incrementGames: function (player1Id, player2Id) {
check(player1Id, Meteor.Collection.ObjectID);
check(player2Id, Meteor.Collection.ObjectID);
Players.update({
_id: player1Id,
'opponents.$.id': player2Id
}, {
$inc: {
'games_played' : 1
}
}, function(error, affectedDocs) {
if (error) {
throw new Meteor.Error(500, error.message);
} else {
return "Update Successful";
}
});
}
});
And on your client:
Meteor.call("incrementGames", Session.get('p1_id'), Session.get('p2_id'), function(error, affectedDocs) {
if (error) {
console.log(error.message);
} else {
// Do whatever
}
});
You just got the update wrong. The first parameter of the update method should be the id. the second parameter is an object containing the modifiers.
Players.update(playerId, {$inc:{games_played:1}});
Optionally you can add a callback containing error as the first parameter and response as the second parameter.