I have an API endpoint that exists, and I know it works correctly (I test frequently, successfully using PostMan). The problem is that when I am posting to it via my chrome extension, I am able to connect, however, no data values are being sent.
Here's my chrome manifest:
{
"background": {
"scripts": ["eventPage.js","jquery-3.3.1.min.js"],
"persistent": false
},
"content_scripts": [
{
"matches": ["https://*.amazon.com/*"],
"js": ["content.js", "jquery-3.3.1.min.js", "inject.js"],
"css": ["content.css"]
}
],
"permissions": [
"tabs",
"storage",
"https://*.amazon.com/*",
"https://*.cloudfunctions.net/*"
] }
Here is the event page that makes the call:
// listen to all messages at runtime
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse){
if (request.todo == 'sendLoad') {
console.log("MADE IT! Request Data", request.data)
// FYI the request.data output is correct; everything is there
// AJAX
$.ajax({
url: "https://prefix.cloudfunctions.net/endpoint",
type: "post",
data: {productName: encodeURIComponent(jQuery.trim(request.data.productName)), productImg: encodeURIComponent(request.data.productImg), productUrl: encodeURIComponent(request.data.productUrl), price: request.data.price, byLineValue: request.data.byLineValue, byLineUrl: encodeURIComponent(request.data.byLineUrl), amazonPath: encodeURIComponent(request.data.amazonPath[2]), uid: request.data.uid, tid: "1"} ,
success: function (response) {
console.log("Send complete: ", response);
},
error: function(jqXHR, textStatus, errorThrown) {
console.log(textStatus, errorThrown);
}
});
};
});
(FYI, I also just tried to send request.data alone and was unsuccessful.)
I also tried to make the call using an xmlhttp request:
xmlhttp=new XMLHttpRequest();
xmlhttp.open("POST","https://prefix.cloudfunctions.net/endpoint",true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send(request.data);
And I also tried using a jQuery post:
$.post("https://prefix.cloudfunctions.net/endpoint",{{productName: encodeURIComponent(jQuery.trim(request.data.productName)), productImg: encodeURIComponent(request.data.productImg), productUrl: encodeURIComponent(request.data.productUrl), price: request.data.price, byLineValue: request.data.byLineValue, byLineUrl: encodeURIComponent(request.data.byLineUrl), amazonPath: encodeURIComponent(request.data.amazonPath[2]), uid: request.data.uid, tid: "1"})
.done(function (data) {
console.log("Send complete: " + data);
})
.fail(function() {
console.log("Error sending data")
})
.always(function() {
console.log("jQuery Post complete")
})
For each of these my API is returning a message that the values do not exist:
Error: Value for argument "data" is not a valid Firestore document. Cannot use "undefined" as a Firestore value (found in field productImg).
at Object.validateUserInput (/srv/node_modules/#google-cloud/firestore/build/src/serializer.js:273:15)
at Object.validateDocumentData (/srv/node_modules/#google-cloud/firestore/build/src/write-batch.js:622:26)
at CollectionReference.add (/srv/node_modules/#google-cloud/firestore/build/src/reference.js:1743:23)
at exports.addToTrunk.functions.https.onRequest (/srv/lib/index.js:27:14)
at cloudFunction (/srv/node_modules/firebase-functions/lib/providers/https.js:57:9)
at /worker/worker.js:783:7
at /worker/worker.js:766:11
at _combinedTickCallback (internal/process/next_tick.js:132:7)
at process._tickDomainCallback (internal/process/next_tick.js:219:9)
As I mentioned earlier, the endpoint works successfully but is not finding the data values that are sent.
UPDATE:
It's looking like the firebase "add" function that's not working correctly. Here is the code in the firebase function:
newTrunk.add({
created_at: created_at,
uid: "CG8B0mdqzMed3PPCiwsKkBtXmiA2", //request.body.uid, //TODO: pull in uid from localstorage
tid: '1', //TODO: provide list of trunks for person to select from when adding via extension
productImg: JSON.stringify(request.body.productImg),
price: JSON.stringify(request.body.price),
productUrl: JSON.stringify(request.body.productUrl),
byLineValue: JSON.stringify(request.body.byLineValue),
byLineUrl: JSON.stringify(request.body.byLineUrl),
amazonPath: JSON.stringify(request.body.amazonPath),
source: JSON.stringify(request.body.source),
productName: JSON.stringify(request.body.productName)
// Tried to stringify and see if it would help ... it didn't
// productImg: request.body.productImg,
// price: request.body.price,
// productUrl: request.body.productUrl,
// byLineValue: request.body.byLineValue,
// byLineUrl: request.body.byLineUrl,
// amazonPath: request.body.amazonPath,
// source: request.body.source,
// productName: request.body.productName
})
.then(function(docRef) {
// console.log("TCL: docRef", docRef)
console.log("New item in trunk added with ID: ", docRef.id)
response.status(200).send("Successful")
})
.catch(function(error) {
console.error("Error adding newTrunk: ", error)
response.status(500).send(error)
});
Related
I'm trying to send some data from a Chrome extension content script to a background script to my local python file. It goes from the content script to the background script fine, but when I try to send it to the python file, I just get "POST http://localhost:5000/bootstrap 400 (BAD REQUEST)." Can't figure out what's going on. I'm new to this. Many thanks!
background.js
// Sending messages from background / event page
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
if (changeInfo.status == 'complete') {
chrome.tabs.query({ active: true }, function(tabs) {
const msg = "Hello from background 🔥";
chrome.tabs.sendMessage(tabs[0].id, { "message": msg });
})
}
});
// Listening to messages page
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
console.log(request);
var articleData = request
// Callback for that request
$.ajax({
type: 'POST',
url: 'http://localhost:5000/bootstrap',
data: articleData,
success: function (newArticle){
alert('success');
}
})
sendResponse({ message: "Background has received that message 🔥" });
});
relevant part of fakenews.py
#app.route('/bootstrap', methods=['GET', 'POST'])
def bootstrap():
posted = 1
print ("bootstrap")
global article
if request.method == 'POST':
if not request.form['title'] or not request.form['url'] or not request.form['image_url'] or not request.form['snippet']:
flash('Please enter all the fields', 'error')
else:
article = Article(request.form['title'], request.form['url'], request.form['image_url'],
request.form['snippet'])
db.session.add(article)
try:
db.session.commit()
except exc.SQLAlchemyError:
flash('Article url already exists, failed to post new article')
posted = 0
#return render_template('/error.html', article_url=article.url)
article_list = Article.query.filter_by(url=article.url)
if posted == 1:
flash('Record was successfully added')
else:
db.session.rollback()
article_list = Article.query.filter_by(url=article.url)
article=article_list[0]
print ("article.id=" + str(article.id))
vote_choices = VoteChoice.getVoteChoiceList()
return render_template('/votefor.html', article_id=article.id,
article_title=article.title,
article_url=article.url, vote_choices=vote_choices
)
relevant part of content.js
chrome.runtime.sendMessage({ message: [title, image, url] }, function(response) {
console.log(response);
});
// Listening to messages in Context Script
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
console.log(request);
// Callback
sendResponse({ message: 'Content script has received that message âš¡' })
})
});
manifest.json
{
"manifest_version": 2,
"name": "OrangeBox",
"version": "1.0",
"permissions": ["http://localhost/" ,"tabs"],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["contentScript.js"]
}
],
"background": { "scripts": ["jquery-3.4.1.js", "background.js"], "persistent": false },
"content_scripts": [
{
"matches": [
"<all_urls>"
],
"js": ["jquery-3.4.1.js", "waitForKeyElements.js", "content.js"]
}
]
}
Problem
In content.js you're sending
message: [title, image, url]
The background.js is just passing this on to fakenews.py, and this is where things break...
fakenews.py is expecting a request object that looks like
{
title: <some time>,
url: <some url>,
image_url: <...>,
snippet: <...>
}
but what it's getting looks like
{
message: [
<some title>,
<some image>,
<some url>
]
}
Fix
The quick fix is changing the content.js line to be
chrome.runtime.sendMessage({"title": title, "image_url": image, "url": url, "snippet": "test"}, function(response) {
Note I'm putting a placeholder for snippet because the backend is expecting a value for it
I am currently trying to get API responses from the two following API's. All of the sample code on their website is in PHP and asks for a token and token SSH, while they only give you an API key. Very lost trying to get requests to pull. The closest I've gotten is an error that says the following:
{status: "error", message: "Unable to read your data; it might not be in json format."}
here is my JS:
jQuery.get({
url: 'https://api.rescuegroups.org/http/v2.json',
type: 'post',
contentType: 'application/json',
data: {
apikey: 'XXXXXXX',
objectType:'animals',
},
dataType: 'json',
success: function (data) {
console.info(data);
}
});
Any help is greatly appreciated. Really want to avoid having to learn PHP as I'm still very new to JS.
the problem is that you are not passing it as json.
this is json format.
let dataObject = {
data: {
apiKey: "xxxx"
}
};
let data = JSON.stringify(dataObject);
{
"data": {
"apikey": "xxx"
}
}
then pass data as your data.
After trying it with Postman the request went through.
Obviously I don't have the api key
{
"status": "error",
"message": "Error with your login credentials",
"messages": {
"generalMessages": [
{
"messageID": "1101",
"messageCriticality": "error",
"messageText": "Error with your login credentials."
}
],
"recordMessages": []
}
}
I'm trying to write an embedded gmail client and have been following through the API documentation on the developer site, but I am unable to get message data in my response. I am able to list labels no problem (using the code from the API docs) so I know it is authenticating ok. I am also able to get message IDs.
When I try to get actual message data, I am running into an issue where the returned Object does not have the data I expect. I check this by logging the messageRequest data to the console because message payload didn't exist when I was initially trying to access it.
function displayInbox() {
var request = gapi.client.gmail.users.messages.list({
'userId': 'me',
'labelIds': 'INBOX',
'maxResults': 10
});
request.execute(function(response) {
$.each(response.messages, function() {
var messageRequest = gapi.client.gmail.users.messages.get({
'userId': 'me',
'id': this.id,
'format': 'full'
});
console.log(JSON.stringify(messageRequest,null,4));
messageRequest.execute(appendPre);
});
});
}
From developer console I get this output:
(index):473 {
"Mq": 1,
"Zq": {
"QT": null,
"k5": {
"path": "/gmail/v1/users/me/messages/15f3a370bc482a7a",
"method": "GET",
"params": {
"format": "full"
},
"headers": {},
"root": "https://www.googleapis.com",
"apiId": "gmail:v1"
},
"Ida": "auto",
"Uja": false,
"Tja": false
}
}
Thanks for any help.
You are currently doing JSON.stringify on the request object. What you are seeing in the console is not the response.
Try and wait for the messageRequest to finish asynchronously, and log the response in the callback instead:
var messageRequest = gapi.client.gmail.users.messages.get({
userId: 'me',
id: this.id,
format: 'full'
});
messageRequest.execute(function(response) {
console.log(response);
});
I'm trying to add a NESTED persistent menu to my chatbot. Facebook has a limit of 3 buttons but you can have a nested button with a maximum of 5 buttons.
This is the error I get when I run my code
response body error
type: 'OAuthException',
Error: { message: '(#100) Invalid keys "call_to_actions" were found in param "call_to_actions[0]".', code: 100}
Here is my code:
function addPersistentMenu(){
request({
url: "https://graph.facebook.com/v2.6/me/thread_settings",
qs: {access_token: token},
method: "POST",
json:{
setting_type : "call_to_actions",
thread_state : "existing_thread",
call_to_actions : [
{
type: "nested",
title: "Menu Item One",
call_to_actions: [
{
type: "postback",
title: "Nested Item One",
payload: "NESTED_ONE"
},
{
type: "postback",
title: "Nested Item Two",
payload: "NESTED_TWO"
}
]
},
{
type: "postback",
title: "Menu Item Two",
payload: "TWO"
},
{
type: "postback",
title: "Menu Item Three",
payload: "THREE"
}
]
}
}, function(error, response, body) {
if(error){
console.log('sending error')
console.log('Error sending messages: ', error)
}else if(response.body.error){
console.log('response body error')
console.log('Error: ', response.body.error)
}
});
}
When I remove the nested button, the persistent menu appears so I'm not sure what the error is. My code is pretty similar to the sample posted by facebook in their persistent menu doc. I'm programing using node.js, hosted on heroku and I modeled my menu function after the code found here.
Question: Has anyone done this using a nodejs webhook using the npm request package to send requests to messenger? How do I add my nested persistent menu and what does this error mean?
Edit:
When I use a direct CURL POST via the terminal using the exact command in the persistent menu documentation, the nested persistent menu is added. I'm not sure what to add to my nodejs webhook version of this request to make it work.
This is the CURL command:
curl -X POST -H "Content-Type: application/json" -d '{
"persistent_menu":[
{
"locale":"default",
"composer_input_disabled":true,
"call_to_actions":[
{
"title":"My Account",
"type":"nested",
"call_to_actions":[
{
"title":"Pay Bill",
"type":"postback",
"payload":"PAYBILL_PAYLOAD"
},
{
"title":"History",
"type":"postback",
"payload":"HISTORY_PAYLOAD"
},
{
"title":"Contact Info",
"type":"postback",
"payload":"CONTACT_INFO_PAYLOAD"
}
]
},
{
"type":"web_url",
"title":"Latest News",
"url":"http://petershats.parseapp.com/hat-news",
"webview_height_ratio":"full"
}
]
},
{
"locale":"zh_CN",
"composer_input_disabled":false
}
]
}' "https://graph.facebook.com/v2.6/me/messenger_profile?access_token=YOUR_ACCESS_TOKEN_HERE"
The Facebook Messenger API has been updated for nested persistent menus. The 'call_to_actions' style appears to still work for a non-nested menu.
A nested menu needs a different API call however. The difference appears to be the URL must be to the 'messenger_profile' rather than 'thread_settings'. A 'get_started' handler is also required for some reason. Finally, the json array is named 'persistent_menu'.
I updated the example bot on gitub. Type 'add menu' and 'remove menu' to see the persistent menu appear/disappear. A page reload or two may be required on some browsers.
Here is some sloppy nodejs code that should do the trick.
function addPersistentMenu(){
request({
url: 'https://graph.facebook.com/v2.6/me/messenger_profile',
qs: { access_token: PAGE_ACCESS_TOKEN },
method: 'POST',
json:{
"get_started":{
"payload":"GET_STARTED_PAYLOAD"
}
}
}, function(error, response, body) {
console.log(response)
if (error) {
console.log('Error sending messages: ', error)
} else if (response.body.error) {
console.log('Error: ', response.body.error)
}
})
request({
url: 'https://graph.facebook.com/v2.6/me/messenger_profile',
qs: { access_token: PAGE_ACCESS_TOKEN },
method: 'POST',
json:{
"persistent_menu":[
{
"locale":"default",
"composer_input_disabled":true,
"call_to_actions":[
{
"title":"My Account",
"type":"nested",
"call_to_actions":[
{
"title":"Pay Bill",
"type":"postback",
"payload":"PAYBILL_PAYLOAD"
},
{
"title":"History",
"type":"postback",
"payload":"HISTORY_PAYLOAD"
},
{
"title":"Contact Info",
"type":"postback",
"payload":"CONTACT_INFO_PAYLOAD"
}
]
},
{
"type":"web_url",
"title":"Latest News",
"url":"http://foxnews.com",
"webview_height_ratio":"full"
}
]
},
{
"locale":"zh_CN",
"composer_input_disabled":false
}
]
}
}, function(error, response, body) {
console.log(response)
if (error) {
console.log('Error sending messages: ', error)
} else if (response.body.error) {
console.log('Error: ', response.body.error)
}
})
}
I am using Facebook JavaScript SDK, this code is for log in and post an object to user's wall, which returns an error,
{"error":{"message":"(#200) You do not have sufficient to permissions to perform this action","type":"OAuthException","code":200}}
FB.login(function(data){
if(data.authResponse){
facebookGetDetails();
}else{
console.log("Login operation aborted");
}
},{scope: 'email,publish_actions,read_stream'});
FB.api(
'/me',
'post',
{
app_id: xxxxxxxxxxxx,
type: "business.business",
url: url,
title: title,
image: picUrl,
contact_data: "Bangalore, India",
location: "17.024522",
description: desc
},
function(response) {
console.log(JSON.stringify(response));
// handle the response
});
the following code works, but it only posts to activity stream, not to wall.
FB.api(
'me/namespace:review',
'post',
{
business: "http://samples.ogp.me/616004095080596"
},
function(response) {
// handle the response
}
);
I guess you're using a incomplete endpoint URL here
FB.api(
'/me',
...
);
You should call /me/feed with a post request as described here: https://developers.facebook.com/docs/graph-api/reference/user/feed/#publish