iOS Swift + Parse User Sign up not passing any data to parse - ios

I do not get any errors and the application builds fine but when I check parse, there is no new user added. here is the code:
import UIKit
import Parse
class ViewController: UIViewController {
#IBOutlet var passwordTextField: UITextField!
#IBOutlet var emailTextField: UITextField!
//#IBOutlet var messageLabel: UILabel!
#IBAction func loginVerifyButton(sender: AnyObject) {
var pwdEntered = passwordTextField.text
var emlEntered = emailTextField.text
if pwdEntered != "" && emlEntered != "" {
// If not empty then yay, do something
func userSignUp() {
var user = PFUser()
user.email = emlEntered
user.password = pwdEntered
user.signUpInBackgroundWithBlock {
(succeeded: Bool, error: NSError?) -> Void in
if let error = error {
let errorString = error.userInfo?["error"] as? NSString
// Show the errorString somewhere and let the user try again.
} else {
// Hooray! Let them use the app now.
}
}
}
}else {
//self.messageLabel.text = "All Fields Required"
}

You should be setting the userName of the PFUser as well, you are only setting the email and passwrod, but you should do this, ObjC, sorry:
PFUser *user = [PFUser user];
user.password = [[[self contentView] passwordField] text];
user.email = [[[self contentView] emailField] text];
user.username = [[[self contentView] emailField] text];
and then doing this:
[user signUpInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (succeeded) {
//do work
} else {
//bad stuff
}
}];
Just set the userName to the the email address
AND if you read the header files for Parse API, you find this:
#abstract Signs up the user *asynchronously*.
#discussion This will also enforce that the username isn't already taken.
#warning Make sure that password and username are set before calling this method.
#param block The block to execute.
It should have the following argument signature: `^(BOOL succeeded, NSError *error)`.
*/
- (void)signUpInBackgroundWithBlock:(PF_NULLABLE PFBooleanResultBlock)block;
This means that you must have a userName declared in the PFUser. So, change from this:
var user = PFUser()
user.email = emlEntered
user.password = pwdEntered
user.signUpInBackgroundWithBlock {
to this:
func myMethod() {
var user = PFUser()
user.username = "myUsername"
user.password = "myPassword"
user.email = "email#example.com"
// other fields can be set just like with PFObject
user["phone"] = "415-392-0202"
user.signUpInBackgroundWithBlock {
(succeeded: Bool, error: NSError?) -> Void in
if let error = error {
let errorString = error.userInfo?["error"] as? NSString
// Show the errorString somewhere and let the user try again.
} else {
// Hooray! Let them use the app now.
}
}
}
from Parse's web site itself

Related

Parse email and username login

I'm trying to login a user by using the username or email. Right now my code works to log the user in by only Username. I'm using a "PFUser.logInWithUsername", but I'd also like to login with the users email. I'm trying to change my code to allow the user to have the choice to either email or a username. Here is my code.
#IBAction func LogInButton(_ sender: AnyObject) {
// login functions
PFUser.logInWithUsername(inBackground: UsernameOrEmail.text!, password: Password.text!) { (user:PFUser?, error:Error?) -> Void in
if error == nil {
// remember user or save in App Memeory did the user login or not
UserDefaults.standard.set(user!.username, forKey: "username")
UserDefaults.standard.synchronize()
// call login function from AppDelegate.swift class
let appDelegate : AppDelegate = UIApplication.shared.delegate as! AppDelegate
// Delay the dismissal by 5 seconds
let delay = 1.0 * Double(NSEC_PER_SEC)
var time = DispatchTime.now() + Double(Int64(delay)) / Double(NSEC_PER_SEC)
DispatchQueue.main.asyncAfter(deadline: time, execute: {
appDelegate.login()
})
} else {
}
You can use a regex pattern to detect if the user enters an email. If the detection returns false, then you "know" that the user entered their username.
This is what I use in my applications(works ok):
//A function that returns true or false based on the input. True if email, false if something else.
func isValidEmail(email:String) -> Bool {
let emailRegEx = "[A-Z0-9a-z._%+-]+#[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"
let emailTest = NSPredicate(format:"SELF MATCHES %#", emailRegEx)
return emailTest.evaluate(with: email)
}
//check if user enters email or not:
if isValidEmail(email: user!.username){
//email adress detected
}else{
//username detected
}
EDIT:
As I understand your problem the function above will solve your problem. I have provided a some code for you to test out.
I do not know what PFUser is capable of, but I assume there is a function for login with username and another for email.
//A function that returns true or false based on the input. True if email, false if something else.
func isValidEmail(email:String) -> Bool {
let emailRegEx = "[A-Z0-9a-z._%+-]+#[A-Za-z0-9.-]+\\.[A-Za-z]{2,}"
let emailTest = NSPredicate(format:"SELF MATCHES %#", emailRegEx)
return emailTest.evaluate(with: email)
}
#IBAction func LogInButton(_ sender: AnyObject) {
//check if user enters username or email
if let usercredentials = UsernameOrEmail.text { //get the username from textfield
if isValidEmail(email: usercredentials){
//user did enter his email as login credential
PFUser.logInWithEmail(inBackground: usercredentials, password: Password.text!) { (user:PFUser?, error:Error?) -> Void in
if error == nil {
//do your login stuff here
} else {
}
}else{
//user did enter his username as login credential
PFUser.logInWithUsername(inBackground: usercredentials, password: Password.text!) { (user:PFUser?, error:Error?) -> Void in
if error == nil {
//do your login stuff here
} else {
}
}else{
//textfield not accessible
}
}

integrating security for user objects in swift

I am relatively new to iOS software development.
I am trying to add security for user objects in my parse app.
But have no idea on how to add it to the project.
Should it be like this?
func logInViewController() {
PFUser.logInWithUsernameInBackground("myname", password: "mypass") {
(user: PFUser?, error: NSError?) -> Void in
if user != nil {
// Do stuff after successful login.
let user = PFUser.logInWithUsername("my_username", password: "my_password")
user.username = "my_new_username" // attempt to change username
user.save() // This succeeds, since the user was authenticated on the device.
// Get the user from a non-authenticated method.
let query = PFUser.query()
let userAgain = query!.getObjectWithId(user.objectId!) as! PFUser
userAgain.username = "another_username"
// This will crash, sinse the PFUser is not authenticated
userAgain.save()
} else {
// The login failed. Check error to see why.
}
let currentUser = PFUser.currentUser()
if currentUser != nil {
// Do stuff with the user
} else {
// Show the signup or login screen.
}
}
}
or like this?
func userOnlyNameChange() {
let user = PFUser.logInWithUsername("my_username", password: "my_password")
user.username = "my_new_username" // attempt to change username
user.save() // This succeeds, since the user was authenticated on the device.
// Get the user from a non-authenticated method.
let query = PFUser.query()
let userAgain = query!.getObjectWithId(user.objectId!) as! PFUser
userAgain.username = "another_username"
// This will crash, sinse the PFUser is not authenticated
userAgain.save()
}
or have I just done it completely wrong?

Storing user input from text field to Parse Database

I am trying to store the information a user inputs for the signup page into a parse database, but can't seem to figure out how to do it.
class ViewController: UIViewController {
#IBOutlet var fullnameField: UITextField!
#IBOutlet var emailAddressField: UITextField!
#IBOutlet var usernameField: UITextField!
#IBOutlet var passwordField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let userFullname = fullnameField.text
let userEmailAddress = emailAddressField.text
let userName = usernameField.text
let userPassword = passwordField.text
let User = PFObject(className: "User")
User["FullName"] = "Example Name"
User["EmailAddress"] = "JohnDoe#example.com"
User["Username"] = "Example"
User["Password"] = "Ilovesmores12345"
User.saveInBackgroundWithBlock { (success: Bool, error: NSError?) -> Void in
println("Object has been saved.")
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
When a user enters his/her information to the text fields and hit's sign up, I need for the information to save into a parse database for further use on the log in page. I feel like i'm over thinking and making it more complicated, is there a way to do this easily?
For signing up don't use user.save - use user.signUpInBackgroundWithBlock
Check this link, it's Parse iOS Guide.
My example, create a button and connect it to signUpPressed method. Here's the method.
#IBAction func signUpPressed(sender: AnyObject) {
let userName = userNameField.text
let email = emailField.text.lowercaseString
let password = passwordField.text
let fullName = fullNameField.text
var user = PFUser()
user.username = userName
user.email = email
user.password = password
//for custom fields use default key-value assign
user["fullName"] = fullName
user.signUpInBackgroundWithBlock{ (succeeded: Bool, error: NSError?) -> Void in
if let error = error {
let errorString = error.userInfo?["error"] as? String
// Show the errorString somewhere and let the user try again.
} else {
// Hooray! Let them use the app now.
}
}
}
And I'd recommend to name your object's fields starting with lowercase letter, so that it can't be confused with class names.

How to integrate third-party authentication(except facebook and twitter) in ios native app in Parse?

I'm using Parse.com, I'd like to integrate third-party authentication( except facebook and twitter), Sina weibo for example, I found no way to achieve this:
After my app authenticated by Sina Weibo App, I got an uid and an access token, First I query the uid in Parse data, if not found, I signup with a random username and password, then my PFUser.currentUser() is not nil
while what if the uid exist? how to become a user now?
Here is my code:
func upsertUser(userInfo: ISSPlatformUser!){
var query = PFQuery(className: "TokenStorage")
query.whereKey("wb_uid", equalTo: userInfo.uid())
query.findObjectsInBackgroundWithBlock({
(objects: [AnyObject]!, error: NSError!) in
println(objects)
if( objects.count == 0 ){
println("this account not register ")
self.newUser(userInfo)
}else{
println("already register")
var tokenData = objects[0] as PFObject
var user = tokenData.objectForKey("user") as PFUser
var accessToken = userInfo.credential().token()
println("accessToken:" + accessToken)
println("user:")
println(user)
if accessToken != tokenData.objectForKey("accessToken") as NSString {
tokenData.setObject(accessToken, forKey: "accessToken")
}
tokenData.saveInBackgroundWithBlock({
(succeed: Bool!, error: NSError!) in
if succeed! {
var sessionToken = user.sessionToken
println("sessionToken:")
println(sessionToken)
println("currentUser:")
println(PFUser.currentUser() )
PFUser.becomeInBackground(sessionToken, block: nil)
}
})
}
})
}
func newUser(userInfo: ISSPlatformUser!){
println("new user ")
var user = PFUser()
var s = NSMutableData(length: 24)!
SecRandomCopyBytes(kSecRandomDefault, UInt(s.length), UnsafeMutablePointer<UInt8>(s.mutableBytes))
let base64str = s.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.allZeros)
user.username = "wb_" + userInfo.uid()
user.password = base64str
user.signUpInBackgroundWithBlock({
(succeed: Bool!, error: NSError!) in
if succeed! {
var ts = PFObject(className: "TokenStorage")
ts.setObject(userInfo.uid(), forKey: "wb_uid")
ts.setObject(userInfo.credential().token(), forKey: "accessToken")
ts.setObject(user, forKey: "user")
var acl = PFACL()
acl.setPublicReadAccess(true)
acl.setPublicWriteAccess(false)
ts.ACL = acl
ts.saveInBackgroundWithBlock(nil)
}
})
}
The session token is nil that can not become a user, which make me frustrated.
One solution could be to sign up your user with a password you know. For instance, to create a unique password per user, you can encode the userInfo.uid() with a constant string you keep safe.
This way, if you find that a user is already registered, you can log in with username/password.
Let us know if you found a better solution.

Parse retrieve objectId from class causes app to stop (not crash)

I have already submitted a question on how to retrieve an objectId (swift - retrieve objectId field causes fatal error) but that seems to only apply to objects during a save because I have spent a long time (days) trying to retrieve the objectId from a saved row in a Parse cloud DB with absolutely no luck. I've mimicked the code in the Parse object retrieval documentation (https://parse.com/docs/ios_guide#objects-retrieving/iOS), using the special values provided for objectId's:
let objectId = gameScore.objectId
I was getting a crash every time but now the app just stops after printing the successful login message. Here is the code and sequence of events.
I signup a new user (let's call him vin).
The signup code:
#IBAction func signUp(sender: AnyObject) {
if countElements(self.userNameTextField.text) > 0 && countElements(self.passWordTextField.text) > 0 {
var megabyker = PFUser()
user.username = self.userNameTextField.text
user.password = self.passWordTextField.text
user.signUpInBackgroundWithBlock{
(succeeded:Bool!, error:NSError!)->Void in
if error == nil {
println("Sign Up successfull")
//associate current user for parse remote push notifications
var installation:PFInstallation = PFInstallation.currentInstallation()
installation.addUniqueObject("goride", forKey: "channels")
installation["user"] = PFUser.currentUser()
installation.saveInBackground()
//default row for allData table
//save default settings row for GUEST user
var alldata:PFObject = PFObject(className: "allData")
alldata["divvy_routes"] = "ON"
alldata["sortBy"] = "distance"
alldata["totalRides"] = 0
alldata["username"] = user.username
//self.useGuestUser = "USER"
alldata["user"] = PFUser.currentUser()
alldata.saveInBackgroundWithBlock{(success:Bool!, error:NSError!) ->Void in
if success != nil {
NSLog("%#","OK-alldata REAL data saved")
self.allDataSignUpObjectId = alldata.objectId
println("printing out objectId var in ALLDATA REAL section: ")
println(self.allDataSignUpObjectId)
self.performSegueWithIdentifier("go-to-main-menu", sender: self)
}
else
{
NSLog("%#",error)
}
}
} else {
let alert = UIAlertView()
alert.title = "Invalid Signup"
alert.message = "Sorry, a username (unique) and a password are required to create a new account."
alert.addButtonWithTitle("OK")
alert.show()
}
}
}
else
{
let alert = UIAlertView()
alert.title = "Invalid Signup"
alert.message = "Sorry, a username (unique) and a password are required to create a new account."
alert.addButtonWithTitle("OK")
alert.show()
}
}
The signup code works fine. It creates a new user and row in the User table and new default row in the allData table. The allData table has a user pointer column to associate it with the User table. I grab the objectId and assign it to an instance variable because I want to pass it to another viewcontroller to use:
self.allDataSignUpObjectId = alldata.objectId
println(self.allDataSignUpObjectId)
And here is a screenshot of the ParseDB where you can see the row has been saved in the user table for the new user. His objectId is 9vRF8BvdlZ and the row in the allData table has an objectId of DEaj0iWZ3X. This is the objectId I am trying to get (DEaj0iWZ3X).
allData table:
Now here is the allData where the new user's default setting row is inserted and it's automatically linked to the Vin's user table:
I then go to the Settings view controller and Save as the newly created user:
#IBAction func updateSettings(sender: AnyObject) {
var alldata:PFObject = PFObject(className:"allData")
var user = PFUser.currentUser()
var query = PFQuery(className:"allData")
query.whereKey("user", equalTo: user)
var id = allDataPass
println(id)
query.getObjectInBackgroundWithId(id) {
(alldata: PFObject!, error: NSError!) -> Void in
if error != nil {
NSLog("%#", error)
} else {
alldata["routes"] = self.RoutesSetting
alldata.saveInBackground()
}
}
}
It saves with no problems and the updated time in the row updates.
But when I logback in as Vin (after resetting the contents and settings on the simulator to get a fresh start), I get to LOGIN but it just stops (not crash, just stops and won't get past the login screen).
Here's the console printout:
2015-02-26 22:19:01.732 MegaByke[51906:6996084] Location Services Not Determined, must ask user
2015-02-26 22:19:01.734 MegaByke[51906:6996084] location services enabled: true
Location services success - <MegaByke.AppDelegate: 0x7ff4b145bd80>
2015-02-26 22:19:15.700 MegaByke[51906:6996084] Reachability Flag Status: -R -----l- networkStatusForFlags
<PFUser: 0x7ff4b167f830, objectId: 9vRF8BvdlZ, localId: (null)> {
username = vin;
}
Login successfull
objectId preFETCH
nil
Here is my login code:
#IBAction func login(sender: AnyObject) {
switch reachability!.currentReachabilityStatus().value{
case NotReachable.value:
var alert = UIAlertView(title: "No Internet Connection", message: "In order to login, you must have internet connection. You can still login as a Guest", delegate: nil, cancelButtonTitle: "Dismiss")
alert.show()
default:
if countElements(self.userNameTextField.text) > 0 && countElements(self.passWordTextField.text) > 0 {
PFUser.logInWithUsernameInBackground(userNameTextField.text, password: passWordTextField.text){
(user:PFUser!, error:NSError!)->Void in
if user != nil
{
println(user)
println("Login successfull")
//associate current user for parse remote push notifications
var installation:PFInstallation = PFInstallation.currentInstallation()
installation.addUniqueObject("goride", forKey: "channels")
installation["user"] = PFUser.currentUser()
installation.saveInBackground()
var user = PFUser.currentUser()
var query = PFQuery(className:"allData")
query.whereKey("user", equalTo: user)
// Retrieve the most recent one
query.orderByDescending("createdAt")
query.limit = 1;
//assign objectId
var alldata = PFObject(className:"allData")
println("objectId preFETCH")
println(alldata.objectId)
//refresh object
alldata.fetch()
let id = alldata.objectId
println("objectId postFETCH")
println(id)
query.getObjectInBackgroundWithId(id) {
(alldata: PFObject!, error: NSError!) -> Void in
if error == nil {
//Load parse data from cloud
NSLog("%#", alldata)
self.performSegueWithIdentifier("go-to-main-menu", sender: self)
} else {
NSLog("%#", error)
}
}
}
else { // Log details of the failure
NSLog("Error: %# %#", error, error.userInfo!)
}
}
}
else{
println(user)
let alert = UIAlertView()
alert.title = "Invalid Login"
alert.message = "Sorry, that username and/or password is incorrect. Please enter a valid combination."
alert.addButtonWithTitle("OK")
alert.show()
println("Login failed")
}
}
}
The println that's supposed to occur after the fetch never gets to the console so I'm assuming I have not successfully retrieved the objectId. I have also checked Parse's user forum and no help there.

Resources