With this code, I try to add user to existing Parse.com role "banned":
var roleACL = PFACL()
var role = PFRole(name: "banned", acl:roleACL)
role.users.addObject(userObject) // This should add user
role.saveInBackground()
I get error 137
A duplicate value for a field with unique values was provided (Code: 137, Version: 1.6.1)
I guess it tries to recreate the role.
However, form the doc, at https://www.parse.com/docs/ios_guide#roles-security/iOS I don't see how i can add a user to an existing role.
Got the solution. The misleading code above, as is on Parse.com site tries to recreate a role.
The correct code is :
var queryRole = PFRole.query() // You need to get role object
queryRole.whereKey("name", equalTo:"banned")
queryRole.getFirstObjectInBackgroundWithBlock() {
(roleObject: PFObject!, error: NSError!) -> Void in
if error == nil {
// Assign user to banned role
var roleToAddUser = roleObject as PFRole
roleToAddUser.users.addObject(userObject)
roleToAddUser.saveInBackground()
}
}
Related
In my iOS app I am making a PFObject and saving it to Parse. Later, a user's account is created (which didn't exist before), and tries to modify it but can't because the PFObjects's ACL wasn't set to allow that user to have permission. How can I modify the ACL of an existing object in Parse to allow this user to have access? I do not want to allow public write access.
The following code prints Success! if given the right code query parameter, but when I check the ACL in Parse it has not been updated at all.
let query = PFQuery(className: "Bike")
query.whereKey("bikeID", equalTo: code)
query.findObjectsInBackground { (objects: [PFObject]?, error: Error?) in
guard let obj = objects?[0], error == nil else {
print("Error")
return
}
obj.acl?.setWriteAccess(true, for: PFUser.current()!)
obj.saveInBackground { (success: Bool, error: Error?) in
if error != nil {
print(error!.localizedDescription)
}
else {
print("Success!")
}
}
}
This post seems to suggest that the ACL cannot be changed through my app's Swift code.
If you know the object you want to grant access to up-front you can change it's ACL in the CloudCode afterSave hook of the User class: in afterSave, test whether the user was just created (to avoid redoing this work for subsequent save requests), then look up the object and set the access rights using the master key.
I'm trying aws cognito user pool and got stacked in the user sign up process. I already configured my user pool and are executing the sign-up method, but I can find a way to get the error code returned by aws services. Here my user pool instantiation, that is working fine:
let poolConfig = AWSCognitoIdentityUserPoolConfiguration(
clientId: userPool_clientId,
clientSecret: userPool_secret,
poolId: userPool_id)
AWSCognitoIdentityUserPool.registerCognitoIdentityUserPool(with: poolConfig,
forKey: userPoll_App)
userPool = AWSCognitoIdentityUserPool(forKey: userPoll_App)
Then, in my view controller I have a Button whit a #IBAction with this:
if userPool != nil {
let attName = AWSCognitoIdentityUserAttributeType()!
attName.name = "name"
attName.value = userNome
let attLast = AWSCognitoIdentityUserAttributeType()!
attLast.name = "family name"
attLast.value = userSobrenome
let attEmail = AWSCognitoIdentityUserAttributeType()!
attEmail.name = "email"
attEmail.value = userEmail
var result:Bool = false
userPool!.signUp(userNome,
password: userPwd,
userAttributes: [attName, attLast, attEmail],
validationData: nil).continue({(task:AWSTask!) in
if (task.error != nil) {
print (task.error!)
result = false
} else {
result = true
}
return nil
})
After that code, I test the result to see if it is true or false and take the appropriate action. But...
I'm having different errors in this process and I need to evaluate this errors in development time. For example, the first error that I got was because I misconfigured the AWS region. Ok! Game on!! But the second error was because the password informed by the user did not passed the validation of the pool. In this case, I want to know the error was because the validation process and inform the user to take the appropriate action. I do not want to have this logic in the iOS app. The task.error object just give a localized description property and it is not very helpful.
By the way: I'm using Swift 3.2, iOS 10.2, aws-ios-sdk2 and Xcode 8.
I would like to expand on behrooziAWS's answer.
In Swift 4 you can match the error code with enums like AWSCognitoIdentityProviderErrorType.TheErrorType.rawValue.
Here's a tip for searching your error type, just type "AWSErrorType" and Xcode's autocomplete would show all the enums and then you can look through them.
Here's a code I use.
AWSobject.AWSfunction().continueWith { task -> Any? in
if let err = task.error as NSError? {
switch err.code {
case: AWSCognitoIdentityProviderErrorType.userNotFound.rawValue:
// Handle case
default:
// Handle all other cases here
return nil
}
// Do stuff on success!
}
task.error.code will contain a code you can compare to values in this enum. Look here for the particular error codes that can be returned by SignUp.
I would like my user to add/edit details about their profile after they register with my app.
#IBAction func doneEditting(sender: AnyObject) {
self.completeEdit()
}
func completeEdit() {
var user = PFUser()
user["location"] = locationTextField.text
user.saveInBackgroundWithBlock {
(succeeded: Bool, error: NSError?) -> Void in
if let error = error {
let errorString = error.userInfo?["error"] as? NSString
println("failed")
} else {
self.performSegueWithIdentifier("Editted", sender: nil)
}
}
}
the breakpoint stops right at user.saveInBackgroundWithBlock. No of the docs show how to append new columns after the signup.
Thanks!
You are mentioning that the user should be able to edit their profile after they have registered. When registering a user with Parse using signUpInBackgroundWithBlock, then the Parse SDK will automatically create a PFUser for you.
In your provided code you are creating and saving a completely new PFUser instead of getting the one which is currently logged in. If you are not using the PFUser which is logged in, then you will get the following error at user.saveInBackgroundWithBlock (which you are also mentioning in your post):
User cannot be saved unless they are already signed up. Call signUp first
To fix this, you will need to change:
var user = PFUser()
To the following:
var user = PFUser.currentUser()!
The rest of your code (for example user["location"] = locationTextField.text) works fine and will dynamically/lazily add a new column to your User database (which is what you want).
Parse allows you to add columns to a class lazily, meaning that you can add a field to your PFObject and if it is not present in your Parse class, Parse will add that column for you.
Here's example how you would add a column via code:
// Add the new field to your object
yourObject["yourColumnName"] = yourValue
yourObject.saveInBackground()
You'll notice that Parse will create a new column named yourColumnName on their web portal.
reference from HERE.
Struggling to get this working, lack of understanding, but if anyone could help me to get there, that would be great. Currently I have a user logging in as an administrator by just setting a boolean, this works fine:
if (authority == "true"){
let acl = PFACL(user: PFUser.currentUser()) // Only user can write
acl.setPublicReadAccess(true) // Everybody can read
acl.setWriteAccess(true, forUser: PFUser.currentUser()) // Also
var role:PFRole = PFRole(name: "Administator", acl: acl)
role.users.addObject(PFUser.currentUser())
role.saveInBackground()
self.activityIndicator.stopAnimating()
let vc : AnyObject! = self.storyboard?.instantiateViewControllerWithIdentifier("Admin")
self.showViewController(vc as UIViewController, sender: vc)
}
This sets an admin role in my parse database. What I am trying to do is to give privileges to this user so that he could edit all other users e.g. giving points to the students for the correctly completed tasks.
if let object = userObject?{
println(tasksCorrect)
object["tasksCorrect"] = tasksCorrect + 1
println(object)
object.saveInBackground()}
You need to ensure that user objects have an ACL that includes read/write access for the "Administrator" role.
My app has a login and signup. Once the user is logged in he can then choose to upgrade the account. When the account is upgraded, a new class in parse is created called "Upgrade". Here it has a bunch of subclasses with stored information. Then once the user is upgraded it brings him to a special page that only upgraded users have access to. But how can I check on login if the user is upgraded, and if he is, automatically bring him to the special page.
In my parse, I have the User information stored with subclasses "Username" and "Password". Then in a separate class I have the upgrade information stores with subclasses "Address", "Phone Number", and I have a linker to link back to the user who created it.
my current code for login is:
#IBAction func loginButton(sender:AnyObject) {
var username = self.usernameTextField.text
var password = self.passwordTextField.text
if(password.utfCount <5) {
var alert = UIAlertView(title:"Invalid", message: "Password must be greater than 5", delegate: self, cancelButtonTitle:"OK")
}
else {
PFUser.logInWithUsernameInBackground(username, password: password, block:{(user, error) -> Void in
if ((user != nil) {
self.performSegueWithIdentifier("LoginSegue", sender: nil)
This is the basic code but it does not check to see if the user is upgraded.
I tried:
if(PFUser.currentUser() == PFQuery(className:"Upgrade")) {
self.performSegueWithIdentifier("UpgradedSegue")
But obivously this didnt work due to the current user not equaling that class.
What kind of code could I user to check if the user made a Upgrade class within parse?
I have tried messing around with fetchinbackground code and enter code hereobjectinbackground but I can't seem to make those work.
I don't know the Swift very well, so sorry if there are errors, but try something like:
var query = PFQuery(className:"Upgrade")
query.whereKey("user", equalTo:currentUser.objectId)
query.getFirstObjectInBackgroundWithBlock {
(object: PFObject!, error: NSError!) -> Void in
if error != nil
println("The getFirstObject request failed.")
} else if object == nil{
//No Upgrade object with that user's ID
} else {
// The find succeeded, user has created an Upgrade object
println("Successfully retrieved the object.")
}
}
You could also set up your code to store the pointer to the Upgrade object on the user, rather than the other way around. You could set a bool value on the user to see if they have upgraded. If it is true, then take them to the upgrade screen, or fetch the Upgrade object, whatever you need first.