Check ownership of record in public CloudKit database - ios

I've just began working with CloudKit and planning to store data in a public CloudKit database. One feature I need is to display information about who has created a record and also let that owner to modify or delete their own records.
None of the tutorials I've read so far talk about this.
How is this done?

Just get that from the CKRecord like this:
record.recordID
record.recordType
record.creationDate
record.creatorUserRecordID
record.modificationDate
record.lastModifiedUserRecordID
record.recordChangeTag
The rights for the user (public, authenticated, owner) who can create / update / delete a record can be setup in the CloudKit dashboard

Related

Unable to detect a Delete on the server from the client

In my database, I have three entities: User, List and UserList (represents a many to many relationship between user and List). In my app, I have initialized SyncContext with StoreTrackingOptions.NotifyLocalAndServerOperations tracking option.
await Client.SyncContext.InitializeAsync(_store, StoreTrackingOptions.NotifyLocalAndServerOperations);
When my app is running for a given User, when I add a new List association for that user (by inserting a linkage record into UserList), I am able to detect this change:
var subscription = Client.EventManager.Subscribe<StoreOperationCompletedEvent>(async (storeEvent) => await StoreChangedEventHandler(storeEvent));
protected async Task StoreChangedEventHandler(StoreOperationCompletedEvent storeEvent) {..}
Now note that creating the linkage, will pull the UserList record for the User as well as the List record referenced by UserList.
When I delete this linkage record though, there is no notification of that coming to my client.
Questions: Is such notification (of deleted records) possible? If so, how do I make it happen?
I have solved this issue by enabling soft delete on the server (Azure Mobile Server SDK). By doing that, all soft-deleted records are pulled back to the client and I can filter them out for presentation. Works for me but may not work for everyone else.

Only read new events from Firebase Database

I was halfway done with implementing Core Data in my iOS app when I realized that Firebase has offline capabilities that would pretty much mimic what I was trying to accomplish the whole time.
In my database which is structured as such:
- Users
- user1
- user2
- Groups
- group1
- members
- user1
- events
- event1_By_Auto_Key
- event2_By_Auto_Key
I wanted to locally store all the events that have already been fetched by a user so that I wouldn't have to read all of them every single time I need to get a group's events. Now that I think I'm just going to stick with Firebase's offline capabilities instead of using Core Data, I have a question regarding how to efficiently read events from the database.
As seen from my database's structure the events are stored using the childByAutoId().setValue(data) method, meaning the keys are unknown when inserted. So my console for a given group might look like this:
My question is: how can I only read the new events from a group? The reason I was implementing Core Data was so that I could cache already fetched events, but I'm not sure how I can make sure that I don't re-read data.
There are a few strategies you could use. Since the ids generated are always lexically greater than any existing, you can use startAt() on your query with the newest record you already have. You just need to skip the record that matches the last ID you have. If you keep a timestamp in the events, you can use orderByChild() and the last timestamp and increment by one ms then you don't get any records you already have. It would be something like:
function getNewEvents(group, arrayOfExistingIds) {
let lastId = arrayOfExistingIds.sort().pop(),
ref = admin.database().ref('/Groups/' + group + '/events')
.orderByKey().startAt(lastId).on('value', function(snap){
if (snap.key === lastId) return;
console.log('New record: ' + snap.key);
})
}
Firebase provide you 10MB persistent memory to cache recently fetch records. In normal scenario 10MB is enough space.
You need to enable offline capabilities.

CloudKit : How to handle account changes with local persistent store?

In my application i have to maintain a local persistent store in sync with cloud kit private database. So I just wanted to know how can I handle account changes that may happen.
Confusion I have is as below:
say a set of records belong to user A now if user B log's in to the same phone I can do the following of the 2 things:
Ignore user and let data sync to B account too but that way A's data will get sync to B's private account too. Here the record change tag and all get a bit mess up since am saving CKRecord encoded fields to database.
I can maintain a user table and link each record to the user that is logged in that way user data will get separated. So should I maintain a user field along with all records ?
How can this be best handled even apart from above 2 things.
Of course in your local persistence store you could add the userID to personalize all records. An other mechanism is to remove all local data and fetch the users data when a change is detected. If you want to keep the users data on the device you could also create separate data stores for each user.
You can detect a changed login by adding the following code in your app delegate or root view controller:
NSNotificationCenter.defaultCenter().addObserverForName(NSUbiquityIdentityDidChangeNotification, object: nil, queue: nil) { _ in
/// remove local data and fetch user data
}
You should also refresh all user related data in memory and refresh the loaded views.

How to allow only one user to edit a Parse object?

I'm creating an app that allows co-workers to upload shifts (objects) to Parse that they need covered. I save all the shifts to a "Shifts" class (in the data browser). I want to restrict the ALC so that only the person who uploaded the shift/object can edit it (everyone can "read" it). Is there a way that I can create/upload that programmatically (rather than having to go into the Data Browser and add it manually)?
You can create a relationship between your Shifts and your existing _User table. If you add a shift, you can create a relationship to the _User table. Than, if you retrieve the info, you can check if the user who reads the record is also the one who created it by comparing the active PFUser.currentUser with the user from your shift.
//Initial safe
var user = PFUser.currentUser
var relation = user.relationForKey("shifts")
relation.addObject(yourShiftObject)
user.saveInBackground()
You can set the ACL on objects when you create them. The best would be to define a default ACL that allows the creating user to read and write the object while still allowing public read access.
Example taken from the documentation
var defaultACL = PFACL.ACL()
// Optionally enable public read access while disabling public write access.
defaultACL.setPublicReadAccess(true)
PFACL.setDefaultACL(defaultACL, withAccessForCurrentUser:true)
https://www.parse.com/docs/ios_guide#security-recommendations/iOS

updating many users at once in parse

I'd like to update user's column which presents related posts that the user might like,
my code is like that:
let users = query.findObjects() as [PFUser]
for user in users{
let rel = user.relationForKey("posts")
rel.addObject(post, forKey: "relatedPosts")
rel.saveInBackground()
}
I really don't know why, but I tried to do that in many versions (not only by relation, also by arrays and other methods) and it always updates just one user (the one who logged in)..
how can I get this done?
You can't update user that is not currently authenticated in your app.
The way I see it you have 2 options:
1) You can set some Cloud Code to run using the master key, so it can modify users.
2) You can add a new custom column to your Parse User class that will link to another class DB that has the related posts for the user.
take a look here: Parse.com Relations Guide
I would choose #2.

Resources