Check if Authenticated User Likes A Certain Page (Using SLRequest)? - objective-c

I've been looking through the open grpah reference docs, and can't seem to find a good example related to SLRequest regarding users and whether they like a certain page or not. I don't want to iterate through their entire list of likes.
I was looking at https://developers.facebook.com/docs/graph-api/reference/user/likes/ but I'm not sure how to work with it and SLRequest, I've done the following but I'm receiving the following response:
Received Response: {"error":{"message":"An active access token must be used to query
information about the current
user.","type":"OAuthException","code":2500}}
Thing is all of this code only runs if the suer has previously authenticated and granted permission, and so it must have found an account, yet I still get this respond. Could it be that I'm not requesting a specific permission? I've requested, "email, public_actions, user_likes and public_stream".
BTW I do have another view controller where I ask for these permissions (except user_likes), and everything works in that one. Is there anything that I'm missing here? Thanks!
NSURL *feedURL = [NSURL URLWithString:#"https://graph.facebook.com/me/likes/{MYPAGEID}"];
[SLRequest requestForServiceType:SLServiceTypeFacebook requestMethod:SLRequestMethodGET URL:feedURL parameters:nil];
[updateFeedRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
if (responseData ) {
NSLog(#"Received Response: %#", [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding]);
if (urlResponse.statusCode >= 200 && urlResponse.statusCode < 300) {
NSLog(#"Successful Connection");
} else {
}
} else {
NSLog(#"No response.");
}
}];

The error that you are getting is received when you try to make calls like /me but no user is currently logged-in to your app or the user has already logged-out of the app.
I'm not sure of your complete flow of the app but you can try this to validate your access token and call- you have the access token right? so, with your current API call just add an extra parameter access_token with its value.

Related

My azure blob is never returned, but no error is either

I have an IOS app using azure storage blobs for jpg photos. My issue is when retrieving the blobs for display.
Most of the time they are retrieved fine. But just occasionally an odd one will not be returned. Instead 749 bytes are returned but with error still = nil.
Now that would be fine, no problem really. However EVERY time after that when I try to retrieve that blob again then the same issue occurs.
All the surrounding blobs are returned fine. The blob in question is fine and can be retrieved using another device.
I have spent lots of time clearing all variables involved and recalling the blob in question and no matter what only ever 749 bytes are returned. Deleting the app from the device and reinstalling it is the only workaround!
So I presume Azure storage or mobile services think the returned data was ok (since it had no error) and keeps sending the same - how can I prevent that and demand a true retry?
The actual retrieving code below was courtesy of github: thank you Ajayi13 it is almost awesome
[request fetchDataWithBlock:^(NSData* data, NSError* error)
{
if(error)
{
if(block)
{
block(nil, error);
}
else if([(NSObject*)_delegate respondsToSelector:#selector(storageClient:didFailRequest:withError:)])
{
[_delegate storageClient:self didFailRequest:request withError:error];
}
return;
}
if(block)
{
block(data, nil);
}
else if([(NSObject*)_delegate respondsToSelector:#selector(storageClient:didGetBlobData:blob:)])
{
[_delegate storageClient:self didGetBlobData:data blob:blob];
}
}];
I have now added the following code based on AdamSorrin's response and a blog post BY DANIEL PASCO: https://blackpixel.com/writing/2012/05/caching-and-nsurlconnection.html
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection willCacheResponse:(NSCachedURLResponse *)cachedResponse {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)[cachedResponse response];
// Look up the cache policy used in our request
if([connection currentRequest].cachePolicy == NSURLRequestUseProtocolCachePolicy) {
NSDictionary *headers = [httpResponse allHeaderFields];
NSString *cacheControl = [headers valueForKey:#"Cache-Control"];
NSString *expires = [headers valueForKey:#"Expires"];
if((cacheControl == nil) && (expires == nil)) {
NSLog(#"server does not provide expiration information and we are using NSURLRequestUseProtocolCachePolicy");
return nil; // don't cache this
}
}
return nil;
}
BUT this has not fixed my issue :o(
I'm not sure exactly what networking library you're using (your request object), so I'm going to assume that it's based off of NSURLSession and NSURLRequest. If not, the details here will be wrong, but the underlying reason still might be correct.
I would guess that your problem is two-fold.
For NSURLSession downloadTaskWithRequest:completionHandler:, the NSError parameter passed into the completion handler block is set only for client-side errors. Retryable service-side errors (throtting, server busy, etc.) aren't detected as such on the client - you need to look at the HTTP response code/message and handle appropriately.
Look at the NSURLSessionConfiguration documentation, specifically requestCachePolicy. My guess is that you're getting stale data from the cache when you try and re-fetch the contents of the blob. You can use this parameter to force the request to re-fetch the data from the service, if this is indeed causing the problem.

OSX ACAccountStore requestAccessToAccountsWithType... returning 'granted=No' and error=nil after denying permissions

I am trying to request access to my facebook account. The first time I ran this it went well and I saw the popup requesting permissions. The popup asked me to allow or deny. I chose to deny because I wanted to test that use case. Now I cannot figure out how to get it to allow access again. I have deleted the app from my facebook account and deleted my facebook account from my mac. I've also tried adding the property
#"auth_type": #"rerequest"
to the options dictionary. I get the same result no matter what.
As mentioned in the title, the error is nil and granted is False.
Thanks in advance.
ACAccountType* accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];
NSDictionary* options = #{
ACFacebookAppIdKey: [[NSBundle mainBundle] objectForInfoDictionaryKey:#"FacebookAppID"],
ACFacebookPermissionsKey: #[#"public_profile", #"email", #"user_friends"],
};
[accountStore requestAccessToAccountsWithType:accountType options:options completion:^(BOOL granted, NSError* error)
{
if (granted)
{
ACAccount* account = [[accountStore accountsWithAccountType:accountType] lastObject];
macFacebookAccount = account;
}
else
{
NSLog(#"%#", error);
}
}];
I solved this: Facebook permission settings for an app are located under System Preferences > Security and Privacy. From there just click facebook and check the box next to your app

Social framework returns "(#803) Cannot query users by their username (username)" when trying to get user feed

I'm using iOs social framework in order to retrieve facebook feeds from a certain user.
For that purpose, after authenticating I'm doing the following:
NSURL *requestURL = [NSURL URLWithString:#"https://graph.facebook.com/username"];
SLRequest *request = [SLRequest requestForServiceType:SLServiceTypeFacebook requestMethod:SLRequestMethodGET
URL:requestURL parameters:nil];
request.account = self.facebookAccount;
[request performRequestWithHandler:^(NSData *data, NSHTTPURLResponse *response, NSError *error) { ... }];
The response returns:
error = {
code = 803;
message = "(#803) Cannot query users by their username (username)";
type = OAuthException;
};
The same works if I use /me instead of the username, but I want to retrieve someone else public feed.
I also tried using the user's id which also works for my user, but I it doesnt work for other users, the request returns the following:
code = 2500;
message = "The global ID 100008339709776 is not allowed. Please use the application specific ID instead.";
type = OAuthException;
I also tried passing the access token as parameter but the behavior is the same.
Any ideas?
Already pointed out in the comments, but you are not supposed to use the username anymore and you canĀ“t access data of users who did not authorize your App.
Changelog: https://developers.facebook.com/docs/apps/changelog
(just trying to get the answer rate on SO higher)

How to get user_likes from Facebook SDK

Im trying to get the user's likes from Facebook, I've been looking for a while for an example and I didn't find it.
With the code I have I get the user's profile information, but no likes. I was wondering if I was doing something wrong and then I looked at Facebook Developers and I found this https://developers.facebook.com/docs/ios/user-data-ios-sdk/
If you take a look at the JSON that is returned you won't see any likes, so what does that mean? There's no way to fech the likes of a user? Why even bother calling the permission "user_likes"?
Any direction will be very appreciated.
Thanks.
Well, let's put it this way. Facebook documentation is confusing.
To get he user likes you have to use FQL, the snippet, would be something like this.
// Query to fetch the active user's friends, limit to 25.
NSString *query =
#"SELECT page_id, type FROM page_fan WHERE uid = me()";
// Set up the query parameter
NSDictionary *queryParam = #{ #"q": query };
// Make the API request that uses FQL
[FBRequestConnection startWithGraphPath:#"/fql"
parameters:queryParam
HTTPMethod:#"GET"
completionHandler:^(FBRequestConnection *connection,
id result,
NSError *error) {
if (error) {
NSLog(#"Error: %#", [error localizedDescription]);
} else {
NSLog(#"Result: %#", result);
}
}];
This way you are getting the users Pages id. If you need something else, take a look at the documentation here: https://developers.facebook.com/docs/reference/fql/page_fan

Handle invalid accessToken with FBSession openActiveSessionWithReadPermissions in Facebook iOS 3.1.1 SDK

Before anything, I have read both this and this questions to solve the problem below and before asking.
My problem is that when the accessToken gets expired (either because the expiration date passes, or manually by deleting the app from my Facebook's App Center) the following code:
if ([[FBSession activeSession] isOpen]) {
//do something
}
else {
[FBSession openActiveSessionWithReadPermissions:nil allowLoginUI:YES completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
if(FB_ISSESSIONOPENWITHSTATE(status)) {
//do something
}
}
}];
}
gets in the else block with FBSession.activeSession open but when the 'do something' is executed the accessToken is invalid so the request gets Error: HTTP status code: 400.
When I try to do the whole procedure twice immediately the FBSession asks for permission (either UIAlertView for iOS6 integrated facebook, Facebook App or Facebook website in Safari) and the rest runs smoothly.
My concern is why I have to do everything twice to work well and why Facebook SDK cannot detect in the first time that the activeSession and accessToken are invalid.
Thank you all in advance!
The questions you linked are relevant, especially Facebook SDK 3.1 - Error validating access token which explains the problem where the Facebook account on the device is out of sync with the server (I.e., if you deleted the app from App Center). As mentioned there, in 3.1.1 the SDK will call to renew the device token only when it gets the invalid response from the server. This is a trade off in convenience for less round-trips to the server.
Assuming your code block is executed on applicationDidFinishLaunching or something similar, it will go to the else block because the app starts with a new session. When it calls openActiveSessionWithReadPermissions, the iOS 6 device thinks the token is valid and will let the state go to Open, so then your "do something" gets executed. Only then does the SDK get the invalid response from the server and invalidate the device token. As a result, the next time the procedure is called, it will prompt the user appropriately to authorize again.
This is intentional. For now, you can consider a automatic retry in your application if the error code describes an invalid token. For example, see the Scrumptious sample postOpenGraph retry code. In your case, it may look closer to something like (I used requestForMe as the "do something" for demonstration purposes):
else {
[FBSessionopenActiveSessionWithReadPermissions:nil allowLoginUI:YES completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
if(FB_ISSESSIONOPENWITHSTATE(status)) {
//do something
[[FBRequest requestForMe] startWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if (!error){
NSLog(#"success on first try");
} else if ([[error userInfo][FBErrorParsedJSONResponseKey][#"body"][#"error"][#"code"] compare:#190] == NSOrderedSame) {
//requestForMe failed due to error validating access token (code 190), so retry login
[FBSession openActiveSessionWithReadPermissions:nil allowLoginUI:YES completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
if (!error){
//do something again, or consider recursive call with a max retry count.
NSLog(#"success on retry");
}
}];
}
}];
}
}];
}