What is the current Parse email verification regex pattern? - ios

I am currently using the PFUser method ' signUpInBackgroundWithBlock: ' to sign up my users, but constraints on my UX mean that i can't sign them up on the same ViewController, hence I'm trying to validate the email before calling that method on a PFUser Parse object.
The alternative is to send my users back to earlier view controllers if parse gives me an error back after method call (which I do not want to do)
I have found this Regex pattern, but this is quite an old answer and I know fancier domains have been out since are now out:
https://www.parse.com/questions/email-validation-rules-for-pfsignupviewcontroller

"The alternative is to send my users back to earlier view controllers if parse gives me an error back after method call (which I do not want to do)"
Note - Unfortunately, you simply won't be able to build parse apps unless you "send them back" like that. Unfortunately "it's that simple." Quite literally every single such "step" when dealing with Parse, you have to be able to "go back" in the sense you describe.
In answer to your question, as you probably know essentially THERE IS NO really good way to truly check if a string is an email, due to various problems with the nature of defining an email, and the fact that you simply don't actually want the full set of "really possible" email strings, for any app.
In practice the following category works well.
It's in use in many high volume production apps.
Note that NSPredicate is, I feel, the most natural, reliable way to do this in iOS.
-(BOOL)basicLocalEmailCheck
{
if ( self.length > 50 ) return NO;
// note, first if it ends with a dot and one letter - that is no good
// (the regex below from W3C does allow a final single-letter tld)
NSString *rx = #".*\\..$";
NSPredicate *emailTest = [NSPredicate
predicateWithFormat:#"SELF MATCHES %#", rx];
if ( [emailTest evaluateWithObject:self] ) return NO;
// here's the original from the W3C HTML5 spec....
// ^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+#[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$
// i made a modification,
// you can't have eg "localhost" with no .com,
// and note you have to escape one backslash for the string from the W3C
rx = #"^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+#[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?){1,5}$";
emailTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", rx];
return [emailTest evaluateWithObject:self];
}
If you are a beginner and not familiar with categories, it's a good opportunity to use one.
Here are some typical real-world uses...particularly relating to Parse since you mention that.
-(IBAction)joinNow
{
[self.view endEditing:YES];
if ( [self _fieldBlank] )
{ [self woe:#"Please complete all fields."]; return; }
if ( ! [self.email.text basicLocalEmailCheck] )
{ [self woe:#"Please enter a valid email."]; return; }
if ( self.imageHasBeenSet == NO )
{ [self woe:#"Please add a picture."]; return; }
if ( self.password.text.length > 20 ||
self.firstname.text.length > 20 ||
self.surname.text.length > 20 )
{ [self woe:#"20 character limit for names and password."]; return; }
[self ageConfirmThenJoin];
}
-(IBAction)clickLogin:(id)sender
{
[self.view endEditing:YES];
[PFUser logOut];
if ( ! [self.loginEmail.text basicLocalEmailCheck] )
{
[UIAlertView ok:#"Please enter your email in the email field."];
[self begin];
return;
}
[APP huddie];
APP.hud.labelText = #"Logging in ...";
[PFAnalytics trackEvent:#"loginAttempt"];
[PFUser logInWithUsernameInBackground: [self.loginEmail.text lowercaseString]
password: self.loginPassword.text
block:^(PFUser* user, NSError* error)
{
[APP.hud hide:YES];
if (user) // Login successful
{
[PFAnalytics trackEvent:#"loginSuccess"];
[self isLoggedInCheckValid];
return;
}
else
{
// note, with Parse it SEEMS TO BE THE CASE that
// 100, no connection 101, bad user/pass
NSString *msg;
NSString *analyticsMsg = #"otherProblem";
if ( !error)
{
msg = #"Could not connect. Try again later...";
// seems unlikely/impossible this could happen
}
else
{
if ( [error code] == 101 )
{
msg = #"Incorrect email or password. Please try again.";
analyticsMsg = #"passwordWrong";
}
else
{
msg = #"Could not connect. Try again later.";
}
}
[PFAnalytics trackEvent:#"loginFailure"
dimensions:#{ #"reason":analyticsMsg }];
[UIAlertView ok:msg];
[self begin]; // not much else we can do
return;
}
}];
}

If you are after a regular expression, then you could take a look here and here for some solutions.
That being said, if you truly want to ensure that the user has provided you with a valid, active email account you should simply do some very basic validation (see it contains the # character for instance) and then simply send a mail with a link to activate the account.
The regular expressions linked to the answers provided aren't exactly user friendly. To add insult to injury, users can still provide you with bogus email addresses. It might also be the case where an edge case scenario email address fails the verification, thus according to your site the user won't be able to sign up.

Related

FireBase - maintain/guarantee data consistency

I'm trying to understand what is the right approach for this following scenario :
Multiplayer game,each game structured only with two players. Each game/match will be completely randomized
Lets assume 5 users "logs" the same time into my app, each one of them "searching" for a match. Each user hold a property named opponent which equal the the opponent uniqueID(initial value equal "". so far so good.
assuming user 1 matched with user 3. user 1 will update his own oppoent value to user 3 uniqueID and will do the same to user 3
Problem
1) What if at the same moment, user 2 tried to to the same to user 3?
2) What if at the same moment, user 3 tried to do so to user 4?
Main Point
Is it possible to "lock" a user values? or freeze them once they changed? Am i going in the wrong approach?
I was thinking using Security Rules and Validation in order to create consistency but i just may picked the wrong tech(FireBase). Any thoughts?
EDIT
Security rules i have tried, which still for some reason enable a third device change "already changed opponent" value.
{
"rules": {
".read": true,
".write": true,
"Users" :
{
"$uid" : {
"opponent" :
{
".write" : "data.val() == 'empty' || data.val() == null",
".validate": "data.val() == null || data.val() == 'empty' || newData.parent().parent().child(newData.val())
.child('opponent').val() == $uid"
}
,".indexOn": "state"
}
}
}
}
You can validate many things with Firebase security rules.
For example, you can say that an opponent can only be written if there currently is no opponent for the user:
"users": {
"$uid": {
"opponent: {
".write": "!data.exists()"
}
}
}
With this and the following operations:
ref.child('users').child(auth.uid).child('opponent').set('uid:1234');
ref.child('users').child(auth.uid).child('opponent').set('uid:2345');
The second set() operation will fail, because the opponent property already has a value at that point.
You can expand that to also validate that the opponents must refer to each other:
"users": {
"$uid": {
"opponent: {
".write": "!data.exists()"
".validate": "newData.parent().parent().child(newData.val())
.child('opponent').val() == $uid"
}
}
}
From the opponent that is being written, we go up two levels back to users: newData.parent().parent().
Then we go down into the opponent's node: child(newData.val()).
And we then validate that the opponent's opponent property matches our uid: child('opponent').val() == $uid.
Now both of the write operations from above will fail, because they're only setting the opponent one at a time. To fix this, you'll need to perform a so-called multi-location update:
var updates = {};
updates['users/'+auth.uid+'/opponent'] = 'uid:1234';
updates['users/uid:1234/opponent'] = auth.uid;
ref.update(updates);
We're now sending a single update() command to the Firebase server that writes the uids to both opponents. This will satisfy the security rule.
A few notes:
these are just some examples to get you started. While they should work, you'll need to write your own rules that meet your security needs.
these rules just handle writing of opponents. You'll probably also want to testing what happens when the game is over and you need to clear the opponents.
You might also look at the transaction operation.
Firebase transactions make sure that the current set of data you are acting on is really what is in the database, guaranteeing that you are updating data that is in the right condition. The docs indicate that this is the recommended way to avoid race conditions such as you describe.
Something like this (in IOS, and warning - not tested):
NSString* user1Key = #"-JRHTHaIs-jNPLXOQivY";
NSString* user2Key = #"-NFHUaIs-kNPLJDHuvY";
Firebase *user1Ref = [[Firebase alloc] initWithUrl: #"https://docs-examples.firebaseio.com.users/-JRHTHaIs-jNPLXOQivY/opponent"];
Firebase *user2Ref = [[Firebase alloc] initWithUrl: #"https://docs-examples.firebaseio.com.users/-NFHUaIs-kNPLJDHuvY/opponent"];
//See if the proposed opponent does not yet have a match
[user2Ref runTransactionBlock:^FTransactionResult *(FMutableData *opponent) {
if (opponent.value == [NSNull null]) {
//They have no match - update with our key and signal success
[opponent setValue:user1Key];
return [FTransactionResult successWithValue: opponent];
} else {
return [FTransactionResult abort]; //They already have an opponent - fail
//Notify the user that the match didn't happen
}
} andCompletionBlock:^(NSError *error, BOOL committed, FDataSnapshot *snapshot) {
if (!error && committed) {
//The transaction above was committed with no error
//Update our record with the other player - we're matched!
[user1ref setValue:user2Key];
//Do whatever notification you want
} else {
//Notify that the matchup failed
}
}];

Execute a charge from existing customer with card in Stripe out of iOS

I have a very hard time figuring out how to do this from the iOS app programmatically.
Im using (besides other) the following classes from github:
https://github.com/hybrdthry911/ELStripe
Class: ELCharge.m
+(ELCharge *)charge{
return [[ELCharge alloc]init];
}
(*****************code in between ************************)
//Will attempt to charge either a customer or card. Exactly one must exist
per charge. If multiple or neither exist an exception will be raised.
//Warning: This is the final step it will APPLY A CHARGE TO THE
ACCOUNT.
-(void)createChargeWithCompletion:(ELChargeCompletionBlock)handler{
[ELCharge createCharge:self completion:handler];
}
+(void)createCharge:(ELCharge *)charge completion
(ELChargeCompletionBlock)handler{
NSError *chargeError;
if (![charge validForProcessingWithError:&chargeError]) {
handler(nil,chargeError);
return;
}
if (!chargeError) {
[ELStripe executeStripeCloudCodeWithMethod:#"POST"
prefix:#"charges" parameters:[ELCharge
dictionaryForCreatingCharge:charge] completionHandler:^(id
jsonObject, NSError *error) {
handler([ELCharge
chargeFromParseStripeDictionary:jsonObject],error);
}];
}
}
In the iOS class, I do the following in order to create a test charge:
//create an automatic charge in stripe from an existing customer with card
attached to him
-(void) executeChargeInStripe:(UIButton*)sender
{
ELCharge *charge = [ELCharge charge];
//Assign the charge properties
charge.customerID = #"cus_72xvQI6Q5IC9it";
charge.currency = #"USD";
NSNumber *chargeAmount = [NSNumber numberWithInt:111];
charge.amountInCents = chargeAmount;
//Call ChargeMethod from Github Framework
[ELCharge createCharge:charge completion:^(ELCharge *charge, NSError
*error) {
if (!error) {
//code for normal handling
NSLog(#"Charge has been made successfully");
} else {
// error code handling
NSLog(#"Charge NOT made");
}
}];
}
Im passing this to the following clould code:
Parse.Cloud.define("stripeHTTPRequest", function(request, response)
{
//Check for valid pre/suf/postfixes, if they are not there do not include
them.
var prefix = request.params["prefix"];
var suffix = "";
var postfix = "";
var secondPostfix = "";
if (!isEmpty(request.params["suffix"])) suffix =
'/'+request.params['suffix'];
if (!isEmpty(request.params["postfix"])) postfix =
'/'+request.params['postfix'];
if (!isEmpty(request.params["secondPostfix"])) secondPostfix =
'/'+request.params['secondPostfix'];
//call from parse to stripe done by http request as parse/stripe api
uncomplete
Parse.Cloud.httpRequest(
{
method: request.params["method"],
//Create URL from base url and pre/suf/postfixes
url: 'https://'+STRIPE_API_BASE_URL + prefix + suffix + postfix +
secondPostfix,
headers: {
'Authorization': "Bearer " + STRIPE_SECRET_KEY
},
params:request.params["params"],
success: function(httpResponse)
{
//response text is a json dictionary
response.success(httpResponse.text);
},
error: function(httpResponse)
{
response.error(httpResponse.text);
}
});
});
Im now getting the following error:
Charge NOT made (my error message from the IOS class I created).
Im really surprised that I recieve neither an error in Parse Cloud nor in Stripe.
If for example, I use an already used token instead of the customerID, I have an error in both. So the connection seems to work I assume, maybe there is something which I do wrong in the iOS class.
Thank you!
have you reverted your Parse JavaScript SDK to 1.5.0? Anything past 1.5.0 is no longer supported.

Facebook iOS API only returning one friend from requestForMyFriends suddenly [duplicate]

I am trying to get my friend name and ids with Graph API v2.0, but data returns empty:
{
"data": [
]
}
When I was using v1.0, everything was OK with the following request:
FBRequest* friendsRequest = [FBRequest requestForMyFriends];
[friendsRequest startWithCompletionHandler: ^(FBRequestConnection *connection,
NSDictionary* result,
NSError *error) {
NSArray* friends = [result objectForKey:#"data"];
NSLog(#"Found: %i friends", friends.count);
for (NSDictionary<FBGraphUser>* friend in friends) {
NSLog(#"I have a friend named %# with id %#", friend.name, friend.id);
}
}];
But now I cannot get friends!
In v2.0 of the Graph API, calling /me/friends returns the person's friends who also use the app.
In addition, in v2.0, you must request the user_friends permission from each user. user_friends is no longer included by default in every login. Each user must grant the user_friends permission in order to appear in the response to /me/friends. See the Facebook upgrade guide for more detailed information, or review the summary below.
If you want to access a list of non-app-using friends, there are two options:
If you want to let your people tag their friends in stories that they publish to Facebook using your App, you can use the /me/taggable_friends API. Use of this endpoint requires review by Facebook and should only be used for the case where you're rendering a list of friends in order to let the user tag them in a post.
If your App is a Game AND your Game supports Facebook Canvas, you can use the /me/invitable_friends endpoint in order to render a custom invite dialog, then pass the tokens returned by this API to the standard Requests Dialog.
In other cases, apps are no longer able to retrieve the full list of a user's friends (only those friends who have specifically authorized your app using the user_friends permission). This has been confirmed by Facebook as 'by design'.
For apps wanting allow people to invite friends to use an app, you can still use the Send Dialog on Web or the new Message Dialog on iOS and Android.
UPDATE: Facebook have published an FAQ on these changes here: https://developers.facebook.com/docs/apps/faq which explain all the options available to developers in order to invite friends etc.
Although Simon Cross's answer is accepted and correct, I thought I would beef it up a bit with an example (Android) of what needs to be done. I'll keep it as general as I can and focus on just the question. Personally I wound up storing things in a database so the loading was smooth, but that requires a CursorAdapter and ContentProvider which is a bit out of scope here.
I came here myself and then thought, now what?!
The Issue
Just like user3594351, I was noticing the friend data was blank. I found this out by using the FriendPickerFragment. What worked three months ago, no longer works. Even Facebook's examples broke. So my issue was 'How Do I create FriendPickerFragment by hand?
What Did Not Work
Option #1 from Simon Cross was not strong enough to invite friends to the app. Simon Cross also recommended the Requests Dialog, but that would only allow five requests at a time. The requests dialog also showed the same friends during any given Facebook logged in session. Not useful.
What Worked (Summary)
Option #2 with some hard work. You must make sure you fulfill Facebook's new rules: 1.) You're a game 2.) You have a Canvas app (Web Presence) 3.) Your app is registered with Facebook. It is all done on the Facebook developer website under Settings.
To emulate the friend picker by hand inside my app I did the following:
Create a tab activity that shows two fragments. Each fragment shows a list. One fragment for available friend (/me/friends) and another for invitable friends (/me/invitable_friends). Use the same fragment code to render both tabs.
Create an AsyncTask that will get the friend data from Facebook. Once that data is loaded, toss it to the adapter which will render the values to the screen.
Details
The AsynchTask
private class DownloadFacebookFriendsTask extends AsyncTask<FacebookFriend.Type, Boolean, Boolean> {
private final String TAG = DownloadFacebookFriendsTask.class.getSimpleName();
GraphObject graphObject;
ArrayList<FacebookFriend> myList = new ArrayList<FacebookFriend>();
#Override
protected Boolean doInBackground(FacebookFriend.Type... pickType) {
//
// Determine Type
//
String facebookRequest;
if (pickType[0] == FacebookFriend.Type.AVAILABLE) {
facebookRequest = "/me/friends";
} else {
facebookRequest = "/me/invitable_friends";
}
//
// Launch Facebook request and WAIT.
//
new Request(
Session.getActiveSession(),
facebookRequest,
null,
HttpMethod.GET,
new Request.Callback() {
public void onCompleted(Response response) {
FacebookRequestError error = response.getError();
if (error != null && response != null) {
Log.e(TAG, error.toString());
} else {
graphObject = response.getGraphObject();
}
}
}
).executeAndWait();
//
// Process Facebook response
//
//
if (graphObject == null) {
return false;
}
int numberOfRecords = 0;
JSONArray dataArray = (JSONArray) graphObject.getProperty("data");
if (dataArray.length() > 0) {
// Ensure the user has at least one friend ...
for (int i = 0; i < dataArray.length(); i++) {
JSONObject jsonObject = dataArray.optJSONObject(i);
FacebookFriend facebookFriend = new FacebookFriend(jsonObject, pickType[0]);
if (facebookFriend.isValid()) {
numberOfRecords++;
myList.add(facebookFriend);
}
}
}
// Make sure there are records to process
if (numberOfRecords > 0){
return true;
} else {
return false;
}
}
#Override
protected void onProgressUpdate(Boolean... booleans) {
// No need to update this, wait until the whole thread finishes.
}
#Override
protected void onPostExecute(Boolean result) {
if (result) {
/*
User the array "myList" to create the adapter which will control showing items in the list.
*/
} else {
Log.i(TAG, "Facebook Thread unable to Get/Parse friend data. Type = " + pickType);
}
}
}
The FacebookFriend class I created
public class FacebookFriend {
String facebookId;
String name;
String pictureUrl;
boolean invitable;
boolean available;
boolean isValid;
public enum Type {AVAILABLE, INVITABLE};
public FacebookFriend(JSONObject jsonObject, Type type) {
//
//Parse the Facebook Data from the JSON object.
//
try {
if (type == Type.INVITABLE) {
//parse /me/invitable_friend
this.facebookId = jsonObject.getString("id");
this.name = jsonObject.getString("name");
// Handle the picture data.
JSONObject pictureJsonObject = jsonObject.getJSONObject("picture").getJSONObject("data");
boolean isSilhouette = pictureJsonObject.getBoolean("is_silhouette");
if (!isSilhouette) {
this.pictureUrl = pictureJsonObject.getString("url");
} else {
this.pictureUrl = "";
}
this.invitable = true;
} else {
// Parse /me/friends
this.facebookId = jsonObject.getString("id");
this.name = jsonObject.getString("name");
this.available = true;
this.pictureUrl = "";
}
isValid = true;
} catch (JSONException e) {
Log.w("#", "Warnings - unable to process Facebook JSON: " + e.getLocalizedMessage());
}
}
}
Facebook has revised their policies now. You can’t get the whole friendlist anyway if your app does not have a Canvas implementation and if your app is not a game. Of course there’s also taggable_friends, but that one is for tagging only.
You will be able to pull the list of friends who have authorised the app only.
The apps that are using Graph API 1.0 will be working till April 30th, 2015 and after that it will be deprecated.
See the following to get more details on this:
User Friends
Facebook Application Development FAQ
In Swift 4.2 and Xcode 10.1:
If you want to get the friends list from Facebook, you need to submit your app for review in Facebook. See some of the Login Permissions:
Login Permissions
Here are the two steps:
1) First your app status is must be in Live
2) Get required permissions form Facebook.
1) Enable our app status live:
Go to the apps page and select your app
https://developers.facebook.com/apps/
Select status in the top right in Dashboard.
Submit privacy policy URL
Select category
Now our app is in Live status.
One step is completed.
2) Submit our app for review:
First send required requests.
Example: user_friends, user_videos, user_posts, etc.
Second, go to the Current Request page
Example: user_events
Submit all details
Like this submit for all requests (user_friends , user_events, user_videos, user_posts, etc.).
Finally submit your app for review.
If your review is accepted from Facebook's side, you are now eligible to read contacts, etc.
As Simon mentioned, this is not possible in the new Facebook API. Pure technically speaking you can do it via browser automation.
this is against Facebook policy, so depending on the country where you live, this may not be legal
you'll have to use your credentials / ask user for credentials and possibly store them (storing passwords even symmetrically encrypted is not a good idea)
when Facebook changes their API, you'll have to update the browser automation code as well (if you can't force updates of your application, you should put browser automation piece out as a webservice)
this is bypassing the OAuth concept
on the other hand, my feeling is that I'm owning my data including the list of my friends and Facebook shouldn't restrict me from accessing those via the API
Sample implementation using WatiN:
class FacebookUser
{
public string Name { get; set; }
public long Id { get; set; }
}
public IList<FacebookUser> GetFacebookFriends(string email, string password, int? maxTimeoutInMilliseconds)
{
var users = new List<FacebookUser>();
Settings.Instance.MakeNewIeInstanceVisible = false;
using (var browser = new IE("https://www.facebook.com"))
{
try
{
browser.TextField(Find.ByName("email")).Value = email;
browser.TextField(Find.ByName("pass")).Value = password;
browser.Form(Find.ById("login_form")).Submit();
browser.WaitForComplete();
}
catch (ElementNotFoundException)
{
// We're already logged in
}
browser.GoTo("https://www.facebook.com/friends");
var watch = new Stopwatch();
watch.Start();
Link previousLastLink = null;
while (maxTimeoutInMilliseconds.HasValue && watch.Elapsed.TotalMilliseconds < maxTimeoutInMilliseconds.Value)
{
var lastLink = browser.Links.Where(l => l.GetAttributeValue("data-hovercard") != null
&& l.GetAttributeValue("data-hovercard").Contains("user.php")
&& l.Text != null
).LastOrDefault();
if (lastLink == null || previousLastLink == lastLink)
{
break;
}
var ieElement = lastLink.NativeElement as IEElement;
if (ieElement != null)
{
var htmlElement = ieElement.AsHtmlElement;
htmlElement.scrollIntoView();
browser.WaitForComplete();
}
previousLastLink = lastLink;
}
var links = browser.Links.Where(l => l.GetAttributeValue("data-hovercard") != null
&& l.GetAttributeValue("data-hovercard").Contains("user.php")
&& l.Text != null
).ToList();
var idRegex = new Regex("id=(?<id>([0-9]+))");
foreach (var link in links)
{
string hovercard = link.GetAttributeValue("data-hovercard");
var match = idRegex.Match(hovercard);
long id = 0;
if (match.Success)
{
id = long.Parse(match.Groups["id"].Value);
}
users.Add(new FacebookUser
{
Name = link.Text,
Id = id
});
}
}
return users;
}
Prototype with implementation of this approach (using C#/WatiN) see https://github.com/svejdo1/ShadowApi. It is also allowing dynamic update of Facebook connector that is retrieving a list of your contacts.
Try /me/taggable_friends?limit=5000 using your JavaScript code
Or
try the Graph API:
https://graph.facebook.com/v2.3/user_id_here/taggable_friends?access_token=
If you are still struggling with this issue on a development mode.
Follow the same process as mentioned below:
create a test app of your main app,
create test users, automatically install app for test users and assign them 'user_friend' permission.
Add your test users as a friend with each other.
I followed the same process after going through alot of research and finally it worked.
In the Facebook SDK Graph API v2.0 or above, you must request the user_friends permission from each user in the time of Facebook login since user_friends is no longer included by default in every login; we have to add that.
Each user must grant the user_friends permission in order to appear in the response to /me/friends.
let fbLoginManager : FBSDKLoginManager = FBSDKLoginManager()
fbLoginManager.loginBehavior = FBSDKLoginBehavior.web
fbLoginManager.logIn(withReadPermissions: ["email","user_friends","public_profile"], from: self) { (result, error) in
if (error == nil) {
let fbloginresult : FBSDKLoginManagerLoginResult = result!
if fbloginresult.grantedPermissions != nil {
if (fbloginresult.grantedPermissions.contains("email")) {
// Do the stuff
}
else {
}
}
else {
}
}
}
So at the time of Facebook login, it prompts with a screen which contain all the permissions:
If the user presses the Continue button, the permissions will be set. When you access the friends list using Graph API, your friends who logged into the application as above will be listed
if ((FBSDKAccessToken.current()) != nil) {
FBSDKGraphRequest(graphPath: "/me/friends", parameters: ["fields" : "id,name"]).start(completionHandler: { (connection, result, error) -> Void in
if (error == nil) {
print(result!)
}
})
}
The output will contain the users who granted the user_friends permission at the time of login to your application through Facebook.
{
data = (
{
id = xxxxxxxxxx;
name = "xxxxxxxx";
}
);
paging = {
cursors = {
after = xxxxxx;
before = xxxxxxx;
};
};
summary = {
"total_count" = 8;
};
}

Search for Specific String in another String

I am using this Code snippet to search for an String inside another String.
It works fine for the first if, but then after the second if it only returns YES (true) if I search for both Words (Word from first if, the Word I want to search now)
works if hypothesis contains : "OPEN TWITTER" not if it is "PLEASE OPEN TWITTER" p.e.
if ([hypothesis rangeOfString:#"OPEN"].location == !NSNotFound) {
NSLog(#"hypothesis contains OPEN");
if ([hypothesis rangeOfString:#"OPEN TWITTER"].location == !NSNotFound) {
[[UIApplication sharedApplication]openURL:[NSURL URLWithString:#"twitter://"]];
}
if ([hypothesis rangeOfString:#"OPEN FACEBOOK"].location == !NSNotFound) {
[[UIApplication sharedApplication]openURL:[NSURL URLWithString:#"fb://"]];
}
}
I want it to work also if there are any other Words in the String, I just want to it to hit on the Keywords somewhere in the String and then return YES (to determine that 'hypothesis' contains the words and then do the action)
== !NSNotFound
should be changed to
!= NSNotFound

verify log-in YouTube

I have an app in which the user uploads a video to youtube. I have the user input their password and username to sign in and then they input the "title", "description", "tags", "category", and "privacy setting" i.e. public, private, unlisted. All works well. However I am not able to verify that the password for the given username is valid or even if the username is valid. When the password and username are filled in and the "sign in" button is tapped these are saved into the documents directory as password.txt and username.txt. Then these are used to complete the process and in fact loaded from the documents directory upon subsequent uploads until the user signs out, in which case the files are removed.
My problem is I would like to check with YouTube when the user fills in the password and username and goes to save them to make sure they are valid. Can someone help me with this.
This is the code I use to input the username and password as well as developers key to YouTube to get a service to allow uploading video.
- (GDataServiceGoogleYouTube *)youTubeService {
static GDataServiceGoogleYouTube* service = nil;
if (!service) {
service = [[GDataServiceGoogleYouTube alloc] init];
[service setShouldCacheResponseData:YES];
[service setServiceShouldFollowNextLinks:YES];
[service setIsServiceRetryEnabled:YES];
/*[service setUserCredentialsWithUsername:accountView.text password:PasswordDisplayField.text];*/
}
NSString *username = [accountView.text retain];
NSCharacterSet *whitespace = [NSCharacterSet whitespaceAndNewlineCharacterSet];
accountView.text = [username stringByTrimmingCharactersInSet:whitespace];
/*if ([accountView.text rangeOfString:#"#"].location == NSNotFound)
{ accountView.text = [kYoutubeUsername stringByAppendingString:#"#gmail.com"]; }*/
if (([accountView.text length] > 0) && ([PasswordDisplayField.text length] > 0))
{ [service setUserCredentialsWithUsername:[accountView.text retain] password:[PasswordDisplayField.text retain]]; }
else
{ [service setUserCredentialsWithUsername:nil password:nil]; }
[service setYouTubeDeveloperKey:devKey];
return service;
}
and then I use this code to get the URL for uploading
NSURL *url = [GDataServiceGoogleYouTube youTubeUploadURLForUserID:kGDataServiceDefaultUser];
but I am not sure how to use these to check to see if the username and password are matched and compatible and return an error message is they are not . Also I don't want to save them if they are not correct.
If someone can suggest a solution, a tutorial, video or something else to help me accomplish this I would greatly appreciate it.
Thanks
I would strongly suggest moving to OAuth 2 using the Objective-C client library:
http://code.google.com/p/gdata-objectivec-client/
http://code.google.com/p/gtm-oauth2/
As a user of your application, I'd feel awful knowing that you were storing my Google Account address and password in clear text like that. Please, switch to OAuth 2.

Resources