Returning multiple Parse classes in one PFQuery? - ios

I currently have my parse classes set up as follows
User - objectid, usename, password, location
Profile - birthday, weight, height, et....
Settings - user app preferences such as "Show my location"
Both profile and settings have a pointer to the user objectid called "user"
Is there anyway I can call a query knowing the Users.objectid that returns both Profile and Settings?
I have played around with includes key and matches query but only get back empty results.
If it isn't possible is there a way to execute a function once both queries have completed? (using getFirstObjectInBackgroundWithBlock)
Any help would greatly be appreciated.

No, but you could hide the combination in a function....
function profileAndSettingsForUser(user) {
var profiles;
var profileQuery = new Parse.Query("Profile");
profileQuery.equalTo("user", user);
return profileQuery.find().then(function(result) {
profiles = result;
settingsQuery = new Parse.Query("Settings");
settingsQuery.equalTo("user", user);
return settingsQuery.find();
}).then(function(settings) {
return profiles.concat(settings);
});
};
You could even locate that function in the cloud, so to hide the combination from the client.
Parse.Cloud.define("profileAndSettingsForUser", function(request, response) {
// we could pass a userId in params, then start by querying for that user
// or, if we know its always the current user who's calling for his own profile and settings...
var user = request.user;
profileAndSettingsForUser(user).then(function(profileAndSettings) {
response.success(profileAndSettings);
}, function(error) {
response.error(error);
});
});

Related

Parse - Delete another user as super admin from iOS app

I use back4app for my app, I would like to delete another user (not authorised user on this device).
The app throws this:
[Error]: User cannot be deleted unless they have been authenticated. (Code: 206, Version: 1.19.1)
which make sense to me if I am not a super admin of the product. But in case I have super admin rights I would like to remove a user from the system completely.
Is there any solution for this purpose? I've tried to find some function from Parse.Cloud code.
The idea was to create cloud code and execute it form the iOS device by calling smth like this:
PFCloud.callFunctionInBackground("deleteUserAsSuperAdmin",
withParameters: user id param here)
{ success, error) -> Void in
}
I have not found such a solution and for me it's a bit difficult to write such code in a right way using cloud code, for sure if this is an option.
You will have to create a cloud code function for that, and use useMasterKey option to delete the user. Something like:
Parse.Cloud.define('deleteUser', async ({ user, params: { userIdToDelete } }) => {
if (user) {
const query = new Parse.Query(Parse.Role);
query.equalTo('name', 'admin');
query.equalTo('users', user);
const count = await query.count({ useMasterKey: true });
if (count === 1) {
const userToDelete = new Parse.User();
userToDelete = userIdToDelete;
return userToDelete.destroy({ useMasterKey: true });
}
}
throw new Error('Not an admin');
});

Getting email id value null as response during apple-authentication

I'm implementing apple-authentication in react native using expo-apple-authentication package.
Below is the code which I'm calling on button's onPress.
async handleSocialLogin() {
const { mutate, BB, onSuccess, navigation } = this.props;
try {
const result = await AppleAuthentication.signInAsync({
requestedScopes: [
AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
AppleAuthentication.AppleAuthenticationScope.EMAIL,
],
});
Alert.alert(JSON.stringify(result))
// signed in
} catch (e) {
Alert.alert(e)
if (e.code === 'ERR_CANCELED') {
// handle that the user canceled the sign-in flow
} else {
// handle other errors
}
}
}
It should return me authentication-token, Full_Name and Email which I requested in scope but It is giving me null for Full_Name and Email.
As per the documentation:
requestedScopes (AppleAuthenticationScope[]) (optional) - Array of user information scopes to which your app is requesting access. Note that the user can choose to deny your app access to any scope at the time of logging in. You will still need to handle null values for any scopes you request. Additionally, note that the requested scopes will only be provided to you the first time each user signs into your app; in subsequent requests they will be null.
You have probably already logged in once and didn't catch the logs. Subsequent log in will result in this data being null

Sending Parse Push with Cloud Code

I cannot find any documentation on Parse.Push used in Parse Cloud Code. The usage case that I see is like this...
// Send the push notification to results of the query
Parse.Push.send({
where: pushQuery,
data: {
alert: message
}
}).then(function() {
response.success("Push was sent successfully.")
}, function(error) {
response.error("Push failed to send with error: " + error.message);
});
What I am trying to do is send a push notification if a recipient user is setup for notifications (i.e. has a valid Installation instance, associated to their user).
At the moment I create the query and pass that into the above with pushQuery. What I notice is that a Push is created in the Parse dashboard but the Pushes sent is 0.
Really I just want to create the Push if a user exists. I have created the query and can run this and return if I get results or not like this...
Parse.Cloud.define("sendTurnNotificationToUser", function(request, response) {
var senderUser = request.user;
var recipientUserId = request.params.recipientId;
var message = request.params.message;
// Validate the message text.
// For example make sure it is under 140 characters
if (message.length > 140) {
// Truncate and add a ...
message = message.substring(0, 137) + "...";
}
// Send the push.
// Find devices associated with the recipient user
var recipientUser = new Parse.User();
recipientUser.id = recipientUserId;
var pushQuery = new Parse.Query(Parse.Installation);
pushQuery.equalTo("user", recipientUser);
pushQuery.find({
success: function(results) {
response.success("push user lookup was ok");
response.success(results);
},
error: function() {
response.error("push user lookup failed");
}
});
I could add the Parse.Push.send call to the success of the query. However the Parse.Push.send has a where clause and I do not know what is required there? I do not want to run the query twice.
You're on the right track. Push "advanced targeting" allows the app to push to installations resulting from a query. That's what the where clause is for...
// don't run find on the pushQuery. set it up as you have it
// then, assuming it returns some installation(s)...
Parse.Push.send({ where: pushQuery, data: "hello" }).then(function(result) {
response.success(result);
}, function(error) {
response.error(error);
});
Incidentally, you can use createWithoutData on Parse.User as a shortcut ...
var recipient = Parse.User.createWithoutData(request.params.recipientId);
but the longer form you have should work, too.
It seems like you may be overthinking this. There's no harm in sending a push notification to 0 installations as the push query will not match any recipients. I wouldn't worry too much about this and I wouldn't add such a pre-check to your code. It would add an unnecessary delay to your code and of course would result in the query being run twice.
If you want to do this anyway -- maybe you wish to keep your push logs free of clutter - you can indeed query over the Installation class to check if the query would have matched a set of installations, and if it does, you can then pass that same query to Parse.Push.send().
Yes, that will result in the query run twice, but that's to be expected, as you can't know how many objects will be matched without running the query.

SAPUI5 get username/userid from OData request

I am currently focussing a problem which I thought it would be easy to solve. but I didnt. There are controls which allow us to show the username or logged in user, such as the lovely shell-headitems:
var oShell = new sap.ui.ux3.Shell("myShell", {
headerItems: [
new sap.ui.commons.TextView({
text: oController.getUserName() }),
],
});
It looks like this:
In here we define headerItems, which are in my opinion foreseen to show a username / or the currently logged in user. but how can I receive it? my idea is to get it from the odata request, which was made earlier. It requires me to enter username and password -> thus I want to read this username in my controller-method, but how?
getUserName : function() {
// return navigator.userAgent;
var model = sap.ui.getCore().getModel();
return model.getProperty('sUser'); // doesnt work :(
},
I also tried to get it from navigator.userAgent() but this information does not belong to the user.
Anybody knows how to receive it?
And yes: I searched in google and found some threads discussing about users/login but none of these threads solved my issue. Otherwise I thought about transferring sy-uname from SAP to the frontend, but how could you send a single Text? I don't want to build a complete service for this single transaction.
If you do not provide sUser and sPassword during oData-Model-Initialization it will be empty during runtime. You cannot access it from the model, though I realized an own service for this.
The username is in the sap.ui.model.odata.ODataMetadata of ODataModel.
var getUserName = function() {
var model = sap.ui.getCore().getModel();
var sUser = model.oMetadata.sUser;
// Display user logic here.
};
oModel.attachMetadataLoaded(null,getUserName);
Update answer for comment question from zyrex:
var user = new sap.ui.commons.TextView();
var getUserNameCallBack = function(userName) {
user.setText(userName);
}
oController.getUserName(getUserNameCallBack);
Controller method:
getUserName: function(callback) {
var userName = '';
$.getJSON(sServiceUrl).done(function(data) {
userName = data.d.Name;
callback(userName);
});
}

Parse iOS SDK: How to set user "online" status?

Scenario = I have an app that allows users to log in and view other users who are also "online". In order to set each user's online status I believe that I should set the code...
[PFUser currentUser] setObject:[NSNumber numberWithBool:YES] forKey:#"isOnline"];
[[PFUser currentUser] saveInBackground];
at certain times in the application when the user uses the app. Probably the appDelegate but I'm not sure.
(if this is not correct then please correct me)
Question = Where should this code be set inside the application so that it always keeps track of when a user is "online" and when they are "offline"?
(please include method names)
The most reliable way to handle this is to create a column named lastActive of type Date, then create a Cloud Code function to update this with the server time (so clock differences isn't an issue).
Then to get "online" users just have another Cloud Function that does a query where lastActive is greater than now - some time window like 2 minutes.
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);
});
});
Your client will want to call the registerActivity Cloud Function every 1.5 minutes to allow some overlap so users don't appear to go offline if their internet is a bit slow.
Of course you can adjust the time windows to suit your needs. You could also add the ability to filter which users are returned (e.g. online friends only).

Resources