Parse iOS SDK: Calling Cloud Functions From Xcode - javascript

Scenario
I have these two Cloud Functions that I want to use in my application. They check for the online status of the user and I want to set a boolean key "isOnline" for each user to YES if the user is online and to NO if they are not.
var moment = require("moment");
Parse.Cloud.define("registerActivity", function(request, response) {
var user = request.user;
user.set("lastActive", new Date());
user.save().then(function (user) {
response.success();
}, function (error) {
console.log(error);
response.error(error);
});
});
Parse.Cloud.define("getOnlineUsers", function(request, response) {
var userQuery = new Parse.Query(Parse.User);
var activeSince = moment().subtract("minutes", 2).toDate();
userQuery.greaterThan("lastActive", activeSince);
userQuery.find().then(function (users) {
response.success(users);
}, function (error) {
response.error(error);
});
});
Problem
I am not the best with Javascript, and because of that I need some help getting my head around what is happening/what I'm supposed to do.
Questions
1) When do I call "registerActivity" and "getOnlineUsers" inside my Xcode project?
2) Is "response.success(users)" just an array of PFUser Objects?
3) If "2)" is true, then how do I set the bool key "isOnline" for all of the users in the "response.success(users)" to YES if they are in the array?

You would call these functions when you want to get the online users. The code for calling these would be:
[PFCloud callFunctionInBackground:#"registerActivity" withParameters:#{#"user": Put objectId for user here}
block:^(NSString *response, NSError *error) {
if (!error) {
}
}];
[PFCloud callFunctionInBackground:#"getOnlineUsers" withParameters:#{}
block:^(NSArray *users, NSError *error) {
if (!error)
{
} }];
Yes, I believe it would just be an array of PFUser objects, I would run this just to make sure, though.
Once you get the response from "getOnlineUsers" you should probably send it back up to another cloud code function that uses the master key (Parse.Cloud.useMasterKey();) to access/change user objects, and change the "isOnline" field to YES.

Related

MeteorJS Infinite loop when using meteor call and meteor method

I have a sample code that goes like this:
Client Helper:
getUsername: function (userId) {
Meteor.call("getUsername", userId, function (err, result) {
if(!err) {
Session.set("setUsername", result);
else {
console.log(err);
}
});
return Session.get("setUsername");
}
Server
Meteor.methods({
"getUsername": function (userId) {
var x = Meteor.users.find({_id: userId}, {fields: {username:1}}).fetch()[0];
return x.username;
}
});
The result of this code is an infinite loop of username passing to the client. Is there a way to stop the loop and pass only the data that is needed on the client? I believe the reactivity is causing the data to loop infinitely and I am not sure how to stop it. I tried using "reactive":false on my query in the server but it does not work.
If you want to access username everywhere in client templates (so thats why you put it into session), I would not set it in template helper. I would set it on startup and get username from session in template helpers (without calling server method)
If you need username just in one template, so you want to return its value from your template helper, do not put it into session, just return it in your server method callback.
Based on your sample code, I assume, you have a set of posts and you are retrieving user name based on user id for each post. Then instead of doing it this way, you should use publish composite package to publish related users as well.
Meteor.publishComposite('getPosts', function (postIds) {
return [{
find: function() {
return Posts.find({ _id: { $in: postIds }});
// you can also do -> return Posts.find();
// or -> return Posts.find({ /* or what ever your selector is to get the posts you need*/ });
},
children: [{
find: function(post) {
return Meteor.users.find({
id: post.userId //or the correct field in your post document to get user id
}, {
fields: {
"profile": 1
}
});
}
}}
}]
});
This way your publication will take care of publishing related users along with posts. You don't need to use methods and call them each time.

Routing to a specific user profile using iron router (METEOR)

As the question says, I need to create a specific route for every user that I have. In my case employers. Now all the examples on the web are connected with the USERS collection.
In my case I want to route to: "/employer/:_id" but I have the Employer ID in the Collection Employers. So basically I have to get the Employer ID via the key from User ID
Im kinda stuck on returning the Employer ID value to the route...
METHODS.js
getEmployerId: function(currentuser){
employerId = Employer.find({"user":currentuser}).fetch();
return employerId;
}
ROUTER.js
Router.route("/employer/:_id", {
name:"employer",
template:"employer",
layoutTemplate:'employerLayout',
data: function(){
var currentuser = Meteor.userId();
Meteor.call("getEmployerId", currentuser, function(error, result){
if(error){
console.log("error", error);
}
if(result){
return true; // I belive here is where I have to pass it up to the ROUTE
}
});
},
onBeforeAction:function(){
var user = Meteor.userId();
if(!user || !Roles.userIsInRole(user, ['employer'])) {
Router.go("verification");
}else {
this.next();
}
return true;
},
});
And this is how my Employer collection looks like:
meteor:PRIMARY> db.employer.find().pretty()
{
"_id" : "qCFGZa4ogc5LR56PL", // I need this for the route
"createdAt" : ISODate("2015-07-18T13:19:16.098Z"),
"user" : "owfJ4ozrfsp26o8G4" // the key through which i can return the ID, got it from the user session?
}
Anyone has a suggestion how to do this? And is this a good approach for each user(employer) profile? Any tutorial, example or anything that describes an application with user profiles would be much appriciated!
Ok, looks like you're nearly there.
I don't think you want the ::id parameter. You send the user to simply /employer, where he does the sign in, so you have his user id.
Then change getEmployerId to getEmployer: in other words, get the whole of the employer record.
getEmployer: function(currentuser){
return Employer.find({"user":currentuser}).fetch();
}
Then in your data: function of the router instead of returning true you return the record you find. In this way the record is available for your template (that's what the data function is for)
data: function(){
var currentuser = Meteor.userId();
Meteor.call("getEmployer", currentuser, function(error, result){
if(error){
console.log("error", error);
}
if(result){
return result;
}
});
},

Using Parse User's Master Key to save relations not working

I am attempting to link a School class with a list of users (a School can have many Users, and a User belongs to a School). Per several suggestions, I am using Parse's Cloud Code and Master key to accomplish this.
My issue is that, instead of passing a string parameter or another User, I am linking a School object to the user.
Here is my Cloud Code, which is causing an error when ran and no changes made to Parse's backend:
Parse.Cloud.define('addNewSchoolRelation', function(request, response) {
var userId = request.params.userId,
associatedSchoolObject = request.params.associatedSchoolObject;
var User = Parse.Object.extend('_User'),
user = new User({ objectId: userId });
var relation = user.relation("schoolRelation");
relation.set(associatedSchoolObject);
Parse.Cloud.useMasterKey();
user.save().then(function(user) {
response.success(user);
}, function(error) {
response.error(error)
});
});
And inside my app, this is how I call it:
PFQuery *schoolQuery = [PFQuery queryWithClassName:#"School"];
[schoolQuery whereKey:#"objectId" equalTo:#"FgpHfOGIdC"]; //this is the test one
[schoolQuery findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (error) {
NSLog(#"Error %#", error);
} else {
PFObject *school = [objects firstObject];
[PFCloud callFunctionInBackground:#"addNewSchoolRelation" withParameters:
#{#"userId": #"BHqvZ6PrLl", //testing for now
#"associatedSchoolObject": school,
} //sets that user's newChats
block:^(id object, NSError *error) {
if (error){
NSLog(#"Error %#", error);
} else {
NSLog(#"Saved on remote user");
}
}];
}
}];
I'm pretty sure culprit is in my Javascript code - am I passing the parameter incorrectly? I'm not sure what I'm doing incorrectly and any help is much appreciated, thanks!

angular push adds operator that that results in MongoError

I am implementing the tutorial on the mean stack https://www.youtube.com/watch?v=AEE7DY2AYvI
I am adding a delete feature to remove items from the database on a button click
My client side controller has the following 2 functions to add to db and remove
$scope.createMeetup = function() {
var meetup = new Meetup();
meetup.name = $scope.meetupName;
meetup.$save(function (result) {
$scope.meetups.push(result);
$scope.meetupName = '';
});
}
$scope.deleteMeetup = function() {
item = $scope.meetups[0];
console.log("deleting meetup: " + item["name"]);
Meetup.delete(item);
scope.meetups.shift();
}
My server side has the following code
module.exports.create = function (req, res) {
var meetup = new Meetup(req.body);
meetup.save(function (err, result) {
res.json(result);
});
}
module.exports.remove = function(req, res) {
console.log("GOING TO REMOVE!!!");
console.log(req.query);
item = req.query;
Meetup.remove(item, function (err, results) {
console.log("done");
console.log(err);
console.log(results);
});
}
When I run my code and if I delete an already loaded item in the list, it is removed from Mongodb just fine. But if I add an item to the list and I do not refresh the page, it results in an error at my server that appears as
GOING TO REMOVE!!!
{ '$resolved': 'true',
__v: '0',
_id: '54ec04e70398fab504085178',
name: 'j' }
done
{ [MongoError: unknown top level operator: $resolved]
name: 'MongoError',
code: 2,
err: 'unknown top level operator: $resolved' }
null
I if I refresh the page, the it gets deleted fine. But if I added the entry, angular seems to be adding a new variable $resolved. Why is that happening?
Also another question, What is the proper way to call delete? I call it now but I am not able to put a callback. I want a callback which returns and then I shift the list of items. I tried adding a callback but the code never reaches it.
ie I tried the following
/*
Meetup.delete(item, function () {
console.log("In callback!!");
console.log(returnValue);
console.log(responseHeaders);
$scope.meetups.splice(item);
});
*/
/*Meetup.delete(item,
function (returnValue, responseHeaders) {
console.log("In callback!!");
console.log(returnValue);
console.log(responseHeaders);
$scope.meetups.splice(item);
},
function (httpResponse){
// error handling here
console.log("Need to handle errors");
});
*/
I am very new to node and am confused. Any help is very, very appreciated
Looks like it possible to call item.delete instead of Meetup.delete(item). You can call same methods on model instance. It prevent sending angular properties to server.
But better to make a rest API with delete method
DELETE /meetups/:id
and send just a _id
Meetup.remove({id: item._id});

Adding data to Users and then saving them using Parse Cloud Code

I'm trying to make a cloud function which saves the sender's objectId and username as an array, inside the array "request", for the target and have the target's objectId and username saved as an array, in the array "pending" for the sender.
Parse.Cloud.define("newGameRequest", function(request, response) {//A
// Get the user who called the function
var user = request.user;
var target;
var query = new Parse.Query(Parse.User);
query.get(request.params.friendId, {
success: function(object) {
var target = object;
var friendInfo = [target.objectId, target.username];
var userInfo = [user.objectId, user.username];
user.add("pending",friendInfo);
target.add("request",userInfo);
Parse.Object.saveAll([user, target], { useMasterKey: true });
response.success("Success");
},
error: function(object, error) {
response.error(error);
}
});
});
Looking in the data browser shows that the arrays for each respective user were saved, but saved with null values only ([[null,null]] for both).
The call is from an iOS device and is the following:
[PFCloud callFunctionInBackground:#"newGameRequest"
withParameters:#{#"friendId": self.friend.objectId}
block:^(NSString *result, NSError *error) {
if (!error) {
}
else {
NSLog(#"%#",result);
}
}];
self.friend.objectId has been tested and is the right result.
What is the issue with my cloud code?
I'm an idiot.
getting the object Id of user is the like the following:
user.id
and getting the username is done like this:
user.getUsername()

Categories