How to create a new user with custom required fields in Parse - ios

I am using Parse and created a new colums in the User. I set the field to "Required", but now I can't create a user anymore.
Error i get:
Login failed: ParseError code=142 error=myCustomColumn is required
This is how I did it:
do {
let currentUser = try User.signup(username: "user", password: "password")
print("Login succes: \(currentUser)")
} catch {
print("Login failed: \(error)")
}
How can I set my custom field? It's already created in the struct. I just need to set the value.
I am using ParseSwift.
https://github.com/parse-community/Parse-Swift

This can be done by using the instance version of signUp in the documentation. An example is shown in the playgrounds:
//: To add additional information when signing up a user,
//: you should create an instance of your user first.
var newUser = User(username: "parse", password: "aPassword*", email: "parse#parse.com")
//: Add any other additional information.
newUser.targetScore = .init(score: 40)
newUser.signup { result in
switch result {
case .success(let user):
guard let currentUser = User.current else {
assertionFailure("Error: current user not stored locally")
return
}
assert(currentUser.hasSameObjectId(as: user))
print("Successfully signed up as user: \(user)")
case .failure(let error):
print("Error logging in: \(error)")
}
}
Also, in my example above, I’m signing up asynchronously, which is most likely the way you want to signup. In your example, you are signing up synchronously, which can hold up the main queue and cause run-time warnings in Xcode

Related

Realm device sync "Action on service 'mongodb-atlas' forbidden: no rules have been configured for this service" error

I'm developing a mobile app using Swift and Realm database.
I configured Realm Device Sync and tried to add custom user data to a cluster I created.
Even though I watched dozens of tutorials about realm permissions I still can't figure out what's wrong with the in-app permissions
here is the authentication function I am using to add Custom User Data
func login() {
isLoading = true
errorMessage = nil
let credentials = Credentials.emailPassword(email: username, password: password)
DispatchQueue.main.async {
app.login(credentials: credentials) { [weak self] result in
switch (result) {
case .failure(let error):
print(String(describing: error))
self?.errorMessage = error.localizedDescription
case .success(let user):
if user.customData.isEmpty {
let client = user.mongoClient("mongodb-atlas")
let database = client.database(named: "UserAPI")
let collection = database.collection(withName: "Users")
// Insert the custom user data object
let customUserData: Document = [
"_id": AnyBSON(user.id),
"email": .string(self!.email),
"province": .string(self!.province),
"_partition": .string(user.id)
]
collection.insertOne(customUserData) {result in
switch result {
case .failure(let error):
print("Failed to insert document: \(error.localizedDescription)")
case .success(let newObjectId):
print("Inserted custom user data document with object ID: \(newObjectId)")
}
}
}
}
self?.isLoading = false
}
}
}
But when I try to create a new user, it successfully creates one. The problem is, when it comes things comes to adding the Custom User Data it returns an error like this:
Failed to insert document: no rule exists for namespace 'UserAPI.Users'
and when I check the MongoDB logs, I can see the error in more detail:
my Custom User Data settings:
and my app permissions:
any help would be appriciated, I'm struggling with this error for 3 days, thanks in advance.
#GrandSirr - have you tried setting "users can read and write all data" permissions template (for development, at least)?
Also, what is your actual 'Users' collection? User custom data should be a separate collection in my opinion as size of user custom data is limited.
My flow - login users with email password - set database triggers to create a new user document with relevant fields that a user can later fill in eg 'profile settings' page of your app and another trigger to create a document in a separate user custom data collection to save some permission roles or subscription to notifications etc.

How to refer to currently logged in users in swift using Firestore?

This code shows the app's main view controller. We would like increment the currently logged in user's field value by 1. In the code below we are only able to do this by manually pasting "nDcAFLPpRuPXI9AOLkln" which we copied from fire base itself.
How do we automatically refer to the currently logged in user?
snapchot of our firestore data tree
#IBAction func bidButton(_ sender: Any) {
let updateScore = db.collection("users").document("nDcAFLPpRuPXI9AOLkln")
updateScore.updateData([
"leaderboardscore": FieldValue.increment(Int64(1))
])
db.collection("users").document("nDcAFLPpRuPXI9AOLkln")
.addSnapshotListener { documentSnapshot, error in
guard let document = documentSnapshot else {
// there was an error
print("Error fetching document: \(error!)")
return
}
// no data to show
guard let data = document.data() else {
print("Document data was empty.")
return
}
self.leaderBoardScoreLabel.text = String("Current data: \(data)")
//print("Current data: \(data)")
}
If you are using Firebase Authentication, and asking how to get the currently signed in user, you should follow the instructions in the documentation:
The recommended way to get the current user is by setting a listener on the Auth object:
handle = Auth.auth().addStateDidChangeListener { (auth, user) in
// ...
}
By using a listener, you ensure that the Auth object isn't in an
intermediate state—such as initialization—when you get the current
user.
You can also get the currently signed-in user by using the currentUser
property. If a user isn't signed in, currentUser is nil:
if Auth.auth().currentUser != nil {
// User is signed in.
// ...
} else {
// No user is signed in.
// ...
}
I would strongly suggest learning how to use the listener, which will give you a callback every time the user is seen to sign in or out.
Once you have a User object, you can use its uid property to get the string you're looking for:
let uid = user.uid

Firebase Auth and Swift: Check if email already in database

I'm working on an iOS app which will use Firebase for user management (sign up, sign in, etc.)
I'm new to Firebase, but it's mostly going ok. I've connected it, I have created users and logged in, etc.
But, I'm trying to change my UI so that the "Sign up" button is initially hidden and will only appear when:
all fields are not empty
email address is valid (using regex)
email address in not already in the database
user name is not already in the database
password and confirmPassword fields are equal
I can't figure out #3 and #4.
I've been reading documentation, watching videos, chasing links all over StackO and beyond, but I can't figure it out.
Can anyone point me in the right direction?
If you are using email & password authentication, the solution is very simple.
Firebase Authentication will not allow duplicate emails so when the createUser function is executed, if the email already exists Firebase will return a emailAlreadyInUse error in the error parameter. You can then cast this to an NSError to see which one it is and handle appropriately.
So the function is like this
Auth.auth().createUser(withEmail: createEmail, password: password ) { user, error in
if let x = error {
let err = x as NSError
switch err.code {
case AuthErrorCode.wrongPassword.rawValue:
print("wrong password")
case AuthErrorCode.invalidEmail.rawValue:
print("invalid email")
case AuthErrorCode.accountExistsWithDifferentCredential.rawValue:
print("accountExistsWithDifferentCredential")
case AuthErrorCode.emailAlreadyInUse.rawValue: //<- Your Error
print("email is alreay in use")
default:
print("unknown error: \(err.localizedDescription)")
}
//return
} else {
//continue to app
}
I threw some random errors into that case statement but check the link for a complete list of all AuthErrorCodes.
You can also do this
Auth.auth().fetchSignInMethods(forEmail: user, completion: { (signInMethods, error) in
print(signInMethods)
})
I think you can check it by using this method
let ref1 = Database.database().reference().child("Users").queryOrdered(byChild: "UserName").queryEqual(toValue: "UserName enter by user")
ref1.observeSingleEvent(of: .value) { (sanpshot) in
print(sanpshot.exists()) // it will return true or false
}
and same for email.

iOS/Swift/Firebase Authentication: Help Needed on Accessing "isNewUser"

In my iOS/Swift/Firebase app, I am trying to access the "isNewUser" parameter after a user successfully signs in via email/password so that I can pop a window to compel them to reset their password from the temporary one initially assigned upon user creation.
Any insights would be appreciated. Thanks.
The .isNewUser Bool is available from the FirebaseAuth AdditionalUserInfo class.
Here is the link. In order to utilize this code, please see a demo sign in function I wrote below.
Auth.auth().signIn(with: credential) { (result, error) in
if let error = error {
print("Error: \(error)");
return;
}
// Fetch the user's info
guard let uid = result?.user.uid else {return}
// Safely unwrap the boolean value rather than forcing it with "!" which could crash your app if a nil value is found
guard let newUserStatus = result?.additionalUserInfo?.isNewUser else {return}
// Test the value
print("\nIs new user? \(newUserStatus)\n")
if newUserStatus == true {
// Provide your alert prompt
}
else{
// Transition view to continue into the app
}
}

Sync Realm Object Server connection completion with follow up realm object usage

I’m using Realm Object Server for a simple test project and I’m facing problems synchronizing ROS connection setup and follow up usage of the realm object to access the database.
In viewDidLoad I’m calling connectROS function to initialize realmRos object/connection:
var realmRos: Realm!
override func viewDidLoad() {
connectROS()
if(FBSDKAccessToken.current() != nil){
// logged in
getFBUserData()
}else{
// not logged in
print("didLoad, FB user not logged in")
}
}
func connectROS() {
let username = "realm-admin"
let password = "*********"
SyncUser.logIn(with: .usernamePassword(username: username, password: password, register: false), server: URL(string: "http://146.185.154.***:9080")!)
{ user, error in
print("ROS: checking user credentials")
if let user = user {
print("ROS: user credentials OK")
DispatchQueue.main.async {
// Opening a remote Realm
print("ROS: entering dispatch Q main async")
let realmURL = URL(string: "realm://146.185.154.***:9080/~/***book_test1")!
let config = Realm.Configuration(syncConfiguration: SyncConfiguration(user: user, realmURL: realmURL))
self.realmRos = try! Realm(configuration: config)
// Any changes made to this Realm will be synced across all devices!
}
} else if let error = error {
// handle error
print("ROS: user check FAIL")
fatalError(String(describing: error))
}
}
}
In viewDidLoad function next step is to get FB logged user (in this case I’m using FB authentication). After the logged FB user is fetched, the application perform check is that FB user is new user for my application and my proprietary ROS User’s table.
func checkForExistingProfile(user: User) -> Bool {
var userThatExist: User?
do {
try self.realmRos.write() {
userThatExist = self.realmRos.object(ofType: User.self, forPrimaryKey: user.userName)
}
} catch let error as NSError {
print("ROS is not connected")
print(error.localizedDescription)
}
if userThatExist != nil {
return true
} else {
return false
}
}
At this point checkForExistingProfile usually (not always) crashes at try self.realmRos.write() which happens to be nil.
I think the problem comes from the synchronization between connectROS execution (which is asynchrony) and checkForExistingProfile which execution comes before connectROS completion.
Since you didn't show how checkForExistingProfile() is called after viewDidLoad() this is conjecture, but based on everything else you described it's the likely cause.
What you need to do is not call checkForExistingProfile() until the sync user has logged in and your self.realmRos variable has been initialized. Cocoa Touch does nothing to automatically synchronize code written using an asynchronous pattern (like logIn(), which returns immediately but reports its actual completion state in a callback), so you need to manually ensure that whatever logIn() is supposed to do has been done before you call any additional code that depends on its completion.

Resources