UPDATED CODE:
I have an open graph action pending approval. I received a message back from Facebook saying this:
Your code is currently configured to publish a stream story. You must change your code so that when the test user triggers the action it produces an open graph story. Please make the appropriate changes and resubmit.
I followed all the tutorials regarding publishing actions and my tests all published successfully to my app timeline. The problem is that my app (which is a page tab) is already up and running - so I want to update it and add these new actions.
Are Facebook looking at the code in my current page tab - which is using the fmbl posttofeed share button - or are they looking at the tests I carried out with the new action? Is anyone able to shed some light on this?
This is the code I have in my test page that I used to publish the actions:
function postShare()
{
FB.api(
'/me/namespace:share',
'post',
{ photo: 'https://domain.com' },
function(response) {
if (!response || response.error) {
alert('Error occurred : ' + response.error);
} else {
alert('Share was successful! Action ID: ' + response.id);
}
});
}
// Load the SDK Asynchronously
(function(d){
var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
if (d.getElementById(id)) {return;}
js = d.createElement('script'); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/all.js";
ref.parentNode.insertBefore(js, ref);
}(document));
// Init the SDK upon load
window.fbAsyncInit = function() {
FB.init({
appId : 'APP ID', // App ID
channelUrl : '//channel url', // Path to your Channel File
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
xfbml : true // parse XFBML
});
// listen for and handle auth.statusChange events
FB.Event.subscribe('auth.statusChange', function(response) {
if (response.authResponse) {
// user has auth'd your app and is logged into Facebook
FB.api('/me', function(me){
if (me.name) {
document.getElementById('auth-displayname').innerHTML = me.name;
}
})
document.getElementById('auth-loggedout').style.display = 'none';
document.getElementById('auth-loggedin').style.display = 'block';
} else {
// user has not auth'd your app, or is not logged into Facebook
document.getElementById('auth-loggedout').style.display = 'block';
document.getElementById('auth-loggedin').style.display = 'none';
}
});
// respond to clicks on the login and logout links
document.getElementById('auth-loginlink').addEventListener('click', function(){
FB.login();
});
document.getElementById('auth-logoutlink').addEventListener('click', function(){
FB.logout();
});
}
function loginUser() {
FB.login(function(response) { }, {scope:'publish_actions, email'});
}
I can't see how this is configured to publish a stream story and not an open graph story? Can anyone help with this is it's driving me insane and can't find anything out there to suggest what I'm doing is not publishing an action.
If, however when they are reviewing my actions they are looking at the code in my live app then of course it is not set up to trigger any open graph stories - as they haven't been approved yet!
Any help would be hugely appreciated.
Many thanks
Your question isn't entirely clear, but both the publish_actions and publish_stream Permissions both allow you to post Open Graph actions. The publish_stream permission however covers many other publishing types and is also optional, and if users remove that permission you won't be able to post OG actions for those users.
Update your authentication code to request publish_actions instead / as well
Finally got it working. Steps:
1. Added "Publish_action" Permission
2. Tested on FB Graph API Explorer successfully
3. Modified my Javascript (similar code as the postShare() method above)
FB.api('/me/namespace:purchase',
'post',
{ product: 'samples.ogp.me/367683346642550'; },
function(response) {
if (!response || response.error) {
alert('Error occured'+response.error);
} else {
alert('Post was successful! Action ID: ' + response.id);
}
});
The Facebook testers need the actual code running at your production server. They are going to use a Facebook test user to execute all the steps you described when you submitted the action. They won't use the already published stories. They will probably use the "Open Graph Test User".
You have two options here:
Try to publish the action with every user and if it doesn't work, publish the stream (so that the test user get the action published but your real user publish using the old code)
--- OR ---
Identify if the user is a test user (by recording the test users ids) and serve him the new code.
Anyway, the real action flow must be executable on the production server.
Basically you cannot post something to an album or any other kind of post when you are using an open graph story. For example the following is not allowed:
$data = $facebook->api('/me/photos', 'post', $args);//disallowed
$facebook->api(
'me/invig-test:share',
'POST',
array(
'app_id' => $configParam['appId'],
'type' => "test:photo",
'photo' => "http://samples.ogp.me/574859819237737",
'title' => "a photo",
'image[0][url]'=>"http://www.testapp.com/".$imgFile,
'image[0][user_generated]'=>'true',
'message' => $comments,
'fb:explicitly_shared'=>true,
)
);
Instead only do the "share":
$facebook->api(
'me/invig-test:share',
'POST',
array(
'app_id' => $configParam['appId'],
'type' => "test:photo",
'photo' => "http://samples.ogp.me/574859819237737",
'title' => "a photo",
'image[0][url]'=>"http://www.testapp.com/".$imgFile,
'image[0][user_generated]'=>'true',
'message' => $comments,
'fb:explicitly_shared'=>true,
)
);
Related
I have some users signed into my actions-on-google app via Google Sign-In ( https://developers.google.com/actions/identity/google-sign-in )
I want to sent push notifications to one of those users.
For getting push notifications work with actions in the first place, I tried this sample: https://github.com/actions-on-google/dialogflow-updates-nodejs/blob/master/functions/index.js but I only can get this to work without this commit: https://github.com/actions-on-google/dialogflow-updates-nodejs/commit/c655062047b49e372da37af32376bd06d837fc7f#diff-1e53ef2f51bd446c876676ba83d7c888
It works fine, but I think const userID = conv.user.id; returns the deprecated Anonymous User ID. The commit suggests to use const userID = conv.arguments.get('UPDATES_USER_ID'); which returns undefined.
I use this nodejs code to send the push notifications.
const request = require('request');
const {JWT} = require('google-auth-library');
const serviceAccount = require('./service-account.json');
let jwtClient = new JWT(
serviceAccount.client_email, null, serviceAccount.private_key,
['https://www.googleapis.com/auth/actions.fulfillment.conversation'],
null
);
jwtClient.authorize((authErr, tokens) => {
let notification = {
userNotification: {
title: process.argv[2],
},
target: {
userId: USERID,
intent: 'tell_latest_status',
// Expects a IETF BCP-47 language code (i.e. en-US)
locale: 'en-US'
},
};
request.post('https://actions.googleapis.com/v2/conversations:send', {
'auth': {
'bearer': tokens.access_token,
},
'json': true,
'body': {
'customPushMessage': notification, 'isInSandbox': true
},
}, (reqErr, httpResponse, body) => {
console.log(httpResponse.statusCode + ': ' + httpResponse.statusMessage);
});
});
I simply can't get this to work with the const userID = conv.arguments.get('UPDATES_USER_ID'); version, because as I said
When I use conv.user.profile.payload.sub as suggested here: https://developers.google.com/actions/identity/user-info the AoG API returns "SendToConversation response: Invalid user id for target."
Is there any way to make this work with Google Sign-In?
Has anyone made this work? I mean with the UPDATES_USER_ID field?
I already created an issue on the samples repo: https://github.com/actions-on-google/dialogflow-updates-nodejs/issues/15 but I was sent here.
Thanks!
While researching why I sometimes got undefined I found an answer on this question that solved my issue.
I've found solution for this problem. While getting UPDATES_USER_ID
conv.arguments.get() only works for first attempt. So, while building
your action you must save it. If you didn't store or save, you can
reset your profile and try again, you will be able to get.
You can reset your user profile for the action here.
Problem Description
My Android app collects data via Google Analytics for Firebase. For privacy reasons, users must be able to wipe their data off the Firebase servers, should they choose to do so.
The app requests a deletion by forwarding its Firebase APP_INSTANCE_ID to my own server. This server has been prepared in advance with credentials, from my personal Google account (via oauth2), for managing the Firebase project. The server authenticates with www.googleapis.com, and, using the supplied APP_INSTANCE_ID, invokes the upsert.
As noted by the documentation, the generic Google Analytics API is appropriate for this task.
After some initial trouble (b/c I didn't have the correct auth scope, and the Analytics API wasn't properly enabled), googleapis.com now returns HTTP 200 for each upsert request. (As an aside, even if you supply a bogus APP_INSTANCE_ID, it returns 200.)
Here is a sample response from the upsert, which shows nothing amiss:
{ kind: 'analytics#userDeletionRequest',
id:
{ type: 'APP_INSTANCE_ID',
userId: (REDACTED 32-char hexidecimal string) },
firebaseProjectId: (REDACTED),
deletionRequestTime: '2018-08-28T12:46:30.874Z' }
I know the firebaseProjectId is correct, because if I alter it, I get an error. I have verified that the APP_INSTANCE_ID is correct, and stable up until the moment it is reset with resetAnalyticsData().
Test Procedure
To test the deletions, I populated Firebase with several custom events, using the procedure below (Nexus 5X emulator, no Google Play, no Google accounts configured, but that shouldn't make any difference):
Install the app
Fire off some custom events (FirebaseAnalytics.logEvent)
Observe those events appear on the Firebase console
(About a minute later:) Make the upsert call, observe HTTP 200, and note the "deletionRequestTime"
Immediately call FirebaseAnalytics.resetAnalyticsData (to clear any event data cached on the device)
Uninstall the app
Rinse & repeat 7 or 8 times
However, even 24 hours later, 100% of the Firebase events are still present in the events table. No discernable state change has taken place on the Firebase server as a result of the upserts.
Question
So, what am I doing wrong? how do I successfully delete user data from Google Analytics for Firebase?
EDIT
Here's the code I'm using to make a request (from node.js):
const request = require( 'request' );
...
_deletePersonalData( data )
{
return new Promise( (resolve, reject) => {
request.post({
url: 'https://www.googleapis.com/analytics/v3/userDeletion/userDeletionRequests:upsert',
body: {
kind: 'analytics#userDeletionRequest',
id: {
type: 'APP_INSTANCE_ID',
userId: data.firebaseAppInstanceId
},
firebaseProjectId: (REDACTED)
},
headers: {
Authorization: 'Bearer ' + iap.getCurAccessToken()
},
json: true
}, (err, res, body) => {
console.log( 'user-deletion POST complete' );
console.log( 'Error ' + err );
console.log( 'Body ', body );
if( err )
{
reject( err );
return;
}
if( body.error )
{
reject( new Error( 'The Google service returned an error: ' + body.error.message + ' (' + body.error.code + ')' ) );
return;
}
resolve({ deletionRequestTime: body.deletionRequestTime });
});
});
}
Here's a sample request body:
{
kind: 'analytics#userDeletionRequest',
id: {
type: 'APP_INSTANCE_ID',
userId: (REDACTED 32-char hexidecimal string)
},
firebaseProjectId: (REDACTED)
}
And here's the console output for that same request (same userId and everything):
user-deletion POST complete
Error: null
Body: { kind: 'analytics#userDeletionRequest',
id:
{ type: 'APP_INSTANCE_ID',
userId: (REDACTED 32-char hexidecimal string) },
firebaseProjectId: (REDACTED),
deletionRequestTime: '2018-08-29T17:32:06.949Z' }
Firebase support just got back to me, and I quote:
Upsert method deletes any individual user data we have logged, but aggregate metrics are not recomputed. This means that you might not see any changes in the events tab in your Analytics console.
So, basically my mistake was expecting the events to disappear from the console.
This, of course, raises the question of how one determines that the API is actually working... but maybe the HTTP 200 is enough.
I want to send an email when a new order is created in my firebase database, but nothing happens when I create an order. My function:
exports.sendEmailConfirmation = functions.database.ref('/orders').onCreate(event => {
const mailOptions = {
from: '"Someone." <noreply#firebase.com>',
to: 'someone#gmail.com',
};
// Building Email message.
mailOptions.subject = 'New order from mobile app!';
mailOptions.text = 'John Doe lorem ipsum';
return mailTransport.sendMail(mailOptions)
.then(() => console.log('¡¡¡ Enail sent !!!'))
.catch((error) => console.error('Error!!', error));
});
This code works using onWrite()....
Your function isn't triggering because /orders already exists. onCreate triggers will only run when the path you specify is newly created.
If you want to know when a child is newly added under /orders, you should use a wildcard in the path:
functions.database.ref('/orders/{orderId}')
CONTEXT
I'm writing a custom checkout process using tokenized payments inside a WebView since I need to use payments outside US.
I'm using this code, based on this facebook guide, to ask for the user's credit card info.
const saveThis = this
MessengerExtensions.requestPaymentCredentials(
function success(name, email, cardType, cardLastFourDigits, shippingAddress) {
console.log('success getting user payment info', cardLastFourDigits)
saveThis.printAsyncData(cardType)
},
function error(err, errorMessage) {
console.log('error trying to get user payment info', errorMessage)
saveThis.printAsyncData(errorMessage)
},
['CONTACT_NAME', 'CONTACT_EMAIL', 'CONTACT_PHONE', 'SHIPPING_ADDRESS']
);
CONSIDERATIONS
saveThis.printAsyncData() function is a workaround to log the
output in mobile devices so I can debug the code, since payments
don't work using the Messenger web client.
I'm testing this chatbot with my facebook account which is the one having the chatbot's Administrator role.
Administrator user returns the profile property is_payment_enabled: true
OUTPUT
I'm getting the following error: "An unexpected error has occured.24002". In the facebook's error reference, 24002 means "Payment request cannot be processed due to missing privacy url".
QUESTION
Does that mean that I have to provide a privacy policy URL to test payments even when I'm using the Administrator's chatbot account in a testing environment??
UPDATE
As suggested, I implemented the updated WebView payment code as follows:
const methodData = [{
supportedMethods: ['fb'], //only 'fb' is supported
data: {
merchantTitle: 'Merchant name', // optional, defaults to the Facebook Page name
merchantImageUrl: 'imageURL', //optional, defaults to the app icon
confirmationText: 'Thank you!', // optional, defaults to "Thank you for your payment"
merchantFBPageId: '28636603843****', // page id with onboarded payment method. Need to be the same with the page id in thread or messenger extension
termsUrl: 'https://www.facebook.com/' // Merchant payment privacy terms and conditions.
}
}]
const paymentDetails = {
displayItems: [ //array of items being charged for
{
label: 'T-shirt',
amount: {
currency: 'USD',
value : '15.00'
}
}
],
total: {
label: 'Total', // defaults to "Total"
amount: {
currency: 'USD',
value : '16.23'
}
},
shippingOptions: [ // Optional. Array of options for user to select
{
id: 'free-shipping', // custom ID
label: 'Free shipping in US', //human-readable name
amount: {currency: 'USD', value: '0.00'},
selected: true
}
]
}
const additionalOptions = {
requestShipping: false, // If shipping is required. If true, handle shippingoptionchange and shippingaddresschange events.
requestPayerName: true, // Name of the payer sent with the final response
requestPayerEmail: true, // Email address, same as above
requestPayerPhone: false // Phone number, same as above
}
let request = new this.messengerExtensions.PaymentRequest(
methodData, // array of payment methods and their setup
paymentDetails, // array of items, total, shipping options
additionalOptions, // request shipping information, payee email address, etc
);
request.canMakePayment()
.then(response => {
this.printAsyncData(response + ' from canMakePayment')
if (response === true) {
// proceed
} else {
// something went wrong, e.g. invalid `displayItems` configuration
// or the device does not run a
// recent enough version of the Facebook app
}
})
.catch(error => {
this.printAsyncData(error+' error from canMakePayment')
// an error such as `InvalidStateError`
// if a payment is already in process
});
This suggested implementation returns the variable response as false. Each configuration variable is copied from this link. I changed the MerchantPageID with the PageID I found on my Chatbot's fb page > Information, so I don't think this could be the problem. I checked the Messenger's version of my Android device and is the latest, being the 147.0.0.25.86 one.
I even tried to implement the payment dialog as follows just to see how it behaves.
request.show().then(response => {
// Process the payment if using tokenized payments.
// Process the confirmation if using Stripe/PayPal
this.printAsyncData(response)
// paymentResponse.complete('success').then(() => {
// // cleanup UI, log, etc
// });
}).catch(error => this.printAsyncData(error+'from show()'));
Payment dialog pops over nicely. It shows user's name and email but under the METHOD PAYMENT header it shows a loading spinner indefinitely. Moreover, .show() never triggers the callback thus not allowing to print its response on the line before paymentResponse.complete('success').
UPDATE 2
I've got the supported features with the following code to try to get some clue of what I'm missing
const saveThis = this
MessengerExtensions.getSupportedFeatures(function success(result) {
var features = result.supported_features;
saveThis.printAsyncData(features)
}, function error(err, errorMessage) {
saveThis.printAsyncData(errorMessage)
});
This is the output on my android messenger client:
["sharing_broadcast","sharing_direct", "sharing_open_graph", "permissions", "thread_context", "context", "sharing_media_template"]
There is no "payments" as it should be, based on this reference
Yes, but since you are just testing it can be any URL. Once you submit your bot for approval it will need to point to a real privacy policy.
You are also using the deprecated version of payments. For webview payments you should use PaymentRequest which is explained here:
https://developers.facebook.com/docs/messenger-platform/payments/webview-payments
I'm testing some forms in a Meteor application using Mocha. The routes in the application are authenticated, so only logged in users or users who have a role of 'administrator' can view them.
When the test opens the browser to view the url and fill the form in, it gets redirected to the login page as expected.
Is there a way to automatically log the user in before doing the test so I don't have to remove the route authentication?
Here's the test code so far
describe( 'Create a Client', function() {
it( 'should create a new client #watch', function() {
browser.url('http://localhost:3000/dashboard/clients/new')
[...]
});
});
use this:
function login(user) {
browser.url('http://localhost:3000')
browser.executeAsync(function(user, done) {
Meteor.loginWithPassword(user.username, user.password, done)
}, user)
}
// now you can do this:
login({
username: 'someone',
password: 'aSecret'
});
browser.url('http://localhost:3000/dashboard/clients/new')
Note that you need to make sure the user exists first, and for that you can use fixtures.
See here for more info:
https://forums.meteor.com/t/solved-how-can-i-wait-for-before-hooks-to-finish-when-testing-with-chimp-meteor-cucumber/18356/12