Mapping Facebook friend id to Firebase uid in realtime database - facebook

How do I map a Facebook friend id to a Firebase uid in the realtime database? It's my understanding that the Firebase uid is not the same as a Facebook id.
My current user flow is logging into Facebook through the Facebook sdk, and then passing the facebook access token to the Firebase sdk to login with Firebase.
My end goal is to store game scores so that a user can see the scores of their friends as well as their own. I do not want to request every score for every player and filter for this information on the client. I would rather send X queries for X amount of friends and only request the scores desired.

Not sure what the downvote was for, but here is the solution I ended up using.
Storing the scores by facebookId instead of firebaseId allows the lookup of scores of friends, since a facebookId can't be mapped to a firebaseId without storing it in the database anyway. It looks like this:
facebookUsers {
facebookId {
"firebaseId" : firebaseId,
"scores" : {
level : score,
}
}
}
This structure allows you to easily lookup scores by facebookId, and also map facebookIds to firebaseIds if desired for other operations.
To save scores:
FirebaseDatabase.DefaultInstance
.GetReference("facebookUsers")
.Child(facebookId)
.Child("scores")
.Child(level)
.SetValueAsync(score);
To lookup scores:
FirebaseDatabase.DefaultInstance
.GetReference("facebookUsers")
.Child(facebookId)
.Child("scores")
.Child(level)
.GetValueAsync();
To restrict writes based on facebookId, use the following rules:
{
"rules": {
".read": "auth != null",
"facebookUsers": {
"$facebookId" : {
".write": "data.child('firebaseId').val() == auth.uid || (!data.exists() && newData.child('firebaseId').val() == auth.uid)",
}
}
}
}
Hopefully this helps someone more than a downvote.

Related

Create hidden user node using firebase realtime

I am having some issues with Firebase security rules. I want any user to be able to create an account using my iOS app at the same time once he or she establishes the account I want to have two nodes one is private, and one is public. I want the public to be accessed by anyone, including the user its self, but the user that created the account only accesses the private node. I have tried a lot of things, but none of my work seems to work. I want to fetch all the public node values by just having a link without knowing the uid of each user
1- Anyone can create an account
2- Only the user can access his own private node
3- A link where I can fetch all of the user's public node only
Thank you!!!!
for example, I would like to fetch all the users https://id.firebaseio.com/Ireland.json
Here is some of my work
{
"rules": {
"Ireland": {
"users": {
"$uid": {
"private": {
".read": "auth != null && auth.uid == $uid",
".write": "auth != null && auth.uid == $uid",
},
"public": {
".read": true,
".write": "auth != null && auth.uid == $uid",
},
},
},
},
},
}
here is my swift code, but every time I try to create an account it says permission denied
guard let uid = result?.user.uid else { return }
let privateValues = ["email": email, "username": username, "password": password, "profileImageUrl": profileImageUrl, "country": "Ireland"]
let publicValues = ["username": username, "profileImageUrl": profileImageUrl]
let values = [uid: ["private": privateValues, "public": publicValues]]
Database.database().reference().child("Ireland").child("users").updateChildValues(values, withCompletionBlock: { (error, reference) in
if let error = error {
print("Failed to save user info to database: ", error)
self.signUpButton.wiggle()
return
}
Firebase security rules cannot be used to filter data. All they do is check if a certain read operation is allow, without checking each individual node.
So if you attach a listener to /Ireland, the server checks if the current user has read permission to /Ireland. Since nobody has permission on that level, the read operation is rejected.
This is also known as 'rules are not filters' in both the documentation and previous questions.
Last year Firebase added support for validating queries in security rules, so that for example you can allow queries that also filter by a ownerUID type property. See the documentation on query based rules for more on that.
But that won't work for your use-case either, since read operations always return full nodes. Which brings us back to the fact that security rules can't be used to filter data.
You will have to separate the public and private data into two separate top-level nodes: private and public. This is one of the many reasons the Firebase documentation recommends keeping your data structure flat.
Also see:
How to create public/private user profile with Firebase security rules?
Firebase: How to structure public/private user data

How do I get user entitlements to persist across conversations

I am trying to see if a user has purchased a product by checking conv.user.entitlements but except for immediately after purchase, this is empty.
This value seemed to be persisting between conversations previously, now it is always empty. I am able to see the entitlement using conv.user.entitlements immediately after purchase, but then it is gone.
if (arg.purchaseStatus === 'PURCHASE_STATUS_OK') {
console.log('purchase2 ', conv.user.entitlements);
//this works as expected showing the entitlement
In the logs I see: purchase2 [ { entitlements: [ [Object] ],
packageName: 'com.chad.myfirstapp' } ]
But when I try to log the same in the next conversation, I get:
purchase2 [ ]
While the conv.user object is capable of storing data across conversations, there are both technical and legal limitations to keep in mind, documented here.
When the Assistant can match an identity to the user, the contents of user storage never expires, and only the user or the Action itself can clear it.
When the Assistant can't match an identity to the user, the content of user storage is cleared at the end of the conversation. Examples of cases where the Assistant can't match an identity to the user are:
Voice match is set up and there is no match.
The user disabled personal data.
In addition to the conv.user object, you can also store data in your preferred database. This Github sample demonstrates how to connect Dialogflow to a Firebase Firestore database.
You can find the write function here:
function writeToDb (agent) {
// Get parameter from Dialogflow with the string to add to the database
const databaseEntry = agent.parameters.databaseEntry;
// Get the database collection 'dialogflow' and document 'agent' and store
// the document {entry: "<value of database entry>"} in the 'agent' document
const dialogflowAgentRef = db.collection('dialogflow').doc('agent');
return db.runTransaction(t => {
t.set(dialogflowAgentRef, {entry: databaseEntry});
return Promise.resolve('Write complete');
}).then(doc => {
agent.add(`Wrote "${databaseEntry}" to the Firestore database.`);
}).catch(err => {
console.log(`Error writing to Firestore: ${err}`);
agent.add(`Failed to write "${databaseEntry}" to the Firestore database.`);
});
}
If you just want to see if a user has purchased an item in the past, use the conv.user.storage to store either a boolean whether the user has purchased something in the past:
conv.user.storage.hasPurchasedItem = true
Or perhaps you can make an array of purchases in conv.user.storage and check its length:
conv.user.storage.purchases = conv.user.storage.purchases || []
conv.user.storage.purchases.push({item: bananas, cost: 0.99})

How to extract users ids from targeting in facebook marketing api

I want to know, can I extract users ids in facebook marketing api by my own targeting parameters?
For example, I have:
from facebookads.adobjects.adaccount import AdAccount
from facebookads.adobjects.adset import AdSet
account = AdAccount('act_<AD_ACCOUNT_ID>')
targeting_spec = {
'geo_locations': {
'countries': ['US'],
},
'age_min': 20,
'age_max': 40,
}
I can get estimated users coverage:
params = {
'currency': 'USD',
'optimize_for': AdSet.OptimizationGoal.offsite_conversions,
'targeting_spec': targeting_spec,
}
reach_estimate = account.get_reach_estimate(params=params)
print(reach_estimate)
But can I also get the list of users ids by this targeting?
This is not possible (thankfully). If you want to target specific people, you need to already come to Facebook with these people identified, either by Facebook ID from your App, or email address/phone numbers etc from your CMS

How to know if a facebook friend has a significant other but does not want to disclose?

I am trying to use facebook api to get my friends' relationship status:
FB.api("/me/friends", {
fields: "id, name, relationship_status, significant_other, picture.type(large)"
}, function (response) {
if (response.data) {
...
$.each(response.data, function (index, data) {
if (data.significant_other) {
// If has a significant other
} else {
// If do not have a significant other
}
});
}
});
I tried to determine if a friend has a significant other by looking at the significant_other field. But how can I know if my friend has a significant other but doesn't want to disclose?
I have a solution. If relationship_status equals "In a relationship" but data.significant_other is not in the data. Then that means the friend has a significant_other but does not want to disclose.
If data isn't accessible via the API, there's no way to access that data via the API
This is pretty much a tautology, but if the data were accessible to you, you'd have it via the API call you just included in your question

Missing Photos from Timeline Photos album

I'm using Facebook Graph API to get all the photos of a user graphPath: me/albums and find something weird with Timeline Photos album.
Photos exist in Timeline album on Facebook, but not returned from API call graphPath/{timeline_photos_album_id}/photos, or they are returned with lower number of photos.
What is the problem?
Logs:
Calling for albums graphPath: me/albums:
.....
{
"can_upload" = 0;
count = 3; !!!!!!!!!!!
"created_time" = "2013-06-18T10:43:27+0000";
description = cool;
from = {
id = 100006100533891;
name = "Mike Mike";
};
id = 1387760311437307;
link = "https://www.facebook.com/album.php?
fbid=1387760311437307&id=100006100533891&aid=1073741829";
name = "Timeline Photos";
privacy = everyone;
type = wall;
"updated_time" = "2013-06-18T10:47:53+0000”;
},
.....
Calling for album photos graphPath/{timeline_photos_album_id}/photos:
{
data = (
);
}
Unfortunately "it is not a bug, it is by design".
I tried the following (with "user_photos" permission) and it works:
Fetch the album photo count for my user:
https://graph.facebook.com/me/albums?fields=id,count&access_token={access_token}
The result is
{
"data": [
{
"id": "{album_id}",
"count": 161,
"created_time": "2010-11-05T15:41:42+0000"
},
....
}
Then query for the photos of this album:
https://graph.facebook.com/{album_id}/photos?fields=id&limit=500&access_token={access_token}
The result is
{
"data": [
{
"id": "{photo_id1}",
"created_time": "2013-12-29T09:59:52+0000"
},
{
"id": "{photo_id2}",
"created_time": "2013-12-17T10:40:26+0000"
},
...
}
I count the correct number of 161 ids in the result. So everything seems to work fine.
You can also test this via FQL:
https://graph.facebook.com/fql?q=select+pid+from+photo+where+album_object_id+=+{album_id}+limit+1000&access_token={access_token}
there have been changes in the FB API recently, did you try to add the fields you want to get back in the result from the API? In the past, API always returned "standard fields", newest you always have to provide a list of fields of what you want to have back in the result such as ....fields=name,id...
I think you are missing the user_photos permission in the Access Token. The end point:
/{timeline_photos_album_id}/photos is working perfectly fine for me when I tried it using the Graph API Explorer to retrieve photos from my Timeline photos album. And, I don't think that it is necessary to provide the fields.
I'll suggest you should try the same using the Graph API Explorer. Just press the Get Access Token button on the top right and check the user_photos permission to test your request.
In case you are getting lesser results, you can try your query using pagination options limit and offset. This sometimes returns more results as compare to normal(nothing about this on docs, just my personal experience). Something like:
{timeline_photo_album_id}/photos?limit=500&offset=0
But again, as you pointed out, there are strange things going on with the API. Take a look at this article. This article refers to it as an expected behavior of the API!