Possible Parse bug in matchesKeyInQuery - parse-platform

If a post in my Parse database is liked, I want to send a push to the author via cloud code.
To be able to send pushes to specific users, all installations store the objectId of the current user. To find the author of the liked post, I use the query
var userWhosePostWasLikedQuery = new Parse.Query(Parse.Installation);
userWhosePostWasLikedQuery.equalTo(kClassInstallationKeyCurrentUserId, userWhosePostWasLiked.id);
This works fine: A single push is sent to the author.
Now I want to send this push only if the author has such pushes enabled. Thus each user stores a push settings array with enable flags for different pushes.
I use now another query for all users who have such pushes enabled:
const User = Parse.Object.extend(kClassUser);
var pushEnabledUserQuery = new Parse.Query(User);
pushEnabledUserQuery.equalTo(kClassUserKeyPushSettings, kPushNotificationTypePostLiked);
This query correctly returns all users who have such pushes enabled.
Eventually, I want to constrain the query for installations with the author as current user, by this query for users who have pushes enabled. This is done in the following way:
var userWhosePostWasLikedQuery = new Parse.Query(Parse.Installation);
userWhosePostWasLikedQuery.equalTo(kClassInstallationKeyCurrentUserId, userWhosePostWasLiked.id);
userWhosePostWasLikedQuery.matchesKeyInQuery(kClassInstallationKeyCurrentUserId, kPFObjectId, pushEnabledUserQuery);
Since the old query without the 3rd line returns 1 user, the new query with the additional constraint (matchesKeyInQuery) should return the same user, since the author has pushes enabled.
But it returns 2 users, the author and another user who liked the post.
To my understanding, this looks like a Parse bug, since all constraints to a query are ANDed.
Any ideas, maybe for a workaround?

your var "kPFObjectId" should be change to "user".
the default parse Installation come with the pointer named "user" and not "kPFObjectId".
I can tell you that Im using the same method ("matchesKeyInQuery") and it is working well:
Parse.Cloud.define("sendPushForChat", function(request, response) {
var userId = request.params.userId;
var groupId = request.params.groupId;
var query = new Parse.Query('RecentActivity');
query.equalTo('groupId',groupId);
query.include('user');
query.notEqualTo('user', {__type: "Pointer", className: "_User", objectId: userId});
var queryInstallation = new Parse.Query(Parse.Installation);
queryInstallation.matchesKeyInQuery('user', 'user', query);
var message = request.params.messageContent;
Parse.Push.send({
where: queryInstallation,
data: {
alert: message,
badge: "Increment",
title: "מה נשמע?"
}
}, {
success: function() {
console.log("Push for chat was successful");
response.success('Push for chat was successful');
},
error: function(error) {
console.error(error);
response.error('error');
},
useMasterKey:true,
});
})

Related

How to update or create N:N relationship using the Client API

I'm writing some client-side customisations for a model driven app and I need to update an entry in an N:N relationship. I have been following the documentation here. I can read from the relationship table, but trying to update an entry or create a new entry is failing.
The N:N relationship is between a custom entity new_lastask and the built-in systemuser entity. The name generated for the N:N relationship is new_new_lastask_systemuser. I have managed to create and update other records, and I understand that you need to use the Schema name with the exact casing, not the name of the field and also the #odata.bind syntax when updating a lookup field, but I can't figure out what the name of the field should be.
The example code below tries to find a N:N record with a given user and switch it for another user, I have given an example with the updateRecord method, but I have tried with createRecord too and I get the same error.
// taskId is the Guid of the custom task entity, and userId is the guid of the user
var query = "?$filter=new_lastaskid eq " + taskId;
Xrm.WebApi.retrieveMultipleRecords("new_new_lastask_systemuser", query).then(
function success(result) {
for (var i = 0; i < result.entities.length; i++) {
if (result.entities[i].systemuserid===oldUserId) {
// found the offering user, replace them
var data = {
"systemuserid#odata.bind": "/systemusers" + newUserId
}
// try to just change the value of the user attached to the N:N record
Xrm.WebApi.updateRecord(tableName, result.entities[i].new_new_lastask_systemuserid, data).then(
function success(result) {
console.log("Successfully updated");
// perform operations on record update
},
function (error) {
console.log(error.message);
// An error occurred while validating input parameters: Microsoft.OData.ODataException:
// An undeclared property 'systemuserid' which only has property annotations in the payload...
}
);
}
}
},
function (error) {
console.log(error.message);
// handle error conditions
}
);
This is the same error I was getting when trying to update any lookup field on my entity when I was trying to use the name instead of the Schema Name, so I thought it might be related to the capitalisation of the field, so I have tried many variations (SystemUserId, User, SystemUser, systemuser, user, userid) and nothing works.
What should the Schema name be of the lookup field on my N:N table, or am I going about handling modifications to these the wrong way via this API?
I just could not get it to work via the Client API, so i just made the call to the web api using fetch, following the document from the 8.2 api here:
fetch('https://yoururl.crm.dynamics.com/api/data/v9.0/new_lastasks' + taskId + "/new_new_lastask_licensee/$ref", {
method: 'post',
headers: {
"Content-Type": "application/json",
"Accept": "application/json",
"OData-MaxVersion": "4.0",
"OData-Version": "4.0"
},
body: JSON.stringify(
{"#odata.id": "https://yoururl.crm.dynamics.com/api/data/v9.0/systemusers" + currentUser }
)
}).then(function(response) {
console.log(response)
})

How to update an User with useMasterKey in Parse

Issue Description
I'm trying to update an User when another user click on my Xamarin button.
Then, I used Cloud Code to perform this but it doesnt work
My Code
Here is my complete JS code :
Parse.Cloud.beforeSave("Archive", function(request, response) {
Parse.serverURL = 'https://pg-app-0brffxkawi8lqvf2eyc2isqrs66zsu.scalabl.cloud/1/';
var status = request.object.get("status");
if (status == "validated") {
var event = request.object.get("event");
event.fetch({
success: function(myEvent) {
var coinsEvent = myEvent.get("coins");
var user = request.object.get("user");
user.fetch({
success: function(myUser, coinsEvent, user) {
var email = myUser.get("email");
var coinsUser = myUser.get("coins");
myUser.set("coins", coinsUser + coinsEvent);
return myUser.save(null, {useMasterKey:true});
}
});
}
});
}
response.success();
});
I think myUser.save(null, {useMasterKey:true}); should work
I actually have that error :
Dec 24, 2017, 12:27 GMT+1 - ERRORError generating response for [PUT] /1/classes/_User/1GPcqmn6Hd
"Cannot modify user 1GPcqmn6Hd."
{
"coins": 250
}
Environment Setup
Server
parse-server version : v2.3.3
Server: Sashido
Your success branch never calls response.success() which is a problem... though maybe not THE problem.
You are also doing 2 fetches inside a 'beforeSave' function which is not recommended. 'BeforeSave' must happen very quickly and fetches take time. I would consider thinking through other options.
If you really need to do it this way, consider doing a Parse.Query("event") with an include("user") and trigger the query with query.first({useMasterKey:true}).
Are you sure coinsEvent is what you think it is? Fetch only returns the object fetched... not sure that you can curry in other parameters. I would change your final success routine to (double checking that coinsEvent is valid):
success: function(myUser) {
var coinsUser = myUser.get("coins");
myUser.set("coins", coinsUser + coinsEvent);
return myUser.save(null, {useMasterKey:true}).then(_ => response.success());
}

Session token empty for parse cloud code user query

I have written the following query to query a user with a given email and once found, return the session key.
Upon executing it returns an empty response.
I double checked that the user session entry actually exists and is linked to the user I am querying.
var query = new Parse.Query(Parse.User);
var email = request.params.email;
query.equalTo("email",email);
query.first({
success: function(user) {
Parse.Cloud.useMasterKey();
response.success(user.getSessionToken());
},
error: function(user, error) {
response.error(error);
},
useMasterKey: true
});
Ok, since you are using parse.com and not parse-server you need to write
the following line of code:
Parse.Cloud.useMasterKey();
in the first line because you tell cloud code that you want to use master key before you are executing any request to the server. Also it's better to use Promises (according to the best practices)
so at the end your code should look like this:
For running on parse.com
// in parse.com - it's the first thing that you do
Parse.Cloud.useMasterKey();
var query = new Parse.Query(Parse.User);
var email = request.params.email;
query.equalTo("email", email);
query.first().then(function(user) {
response.success(user.getSessionToken());
}, function(error) {
response.error(error);
});
For parse-server
in parse-server you use useMasterKey and send it to the function.
Parse.Cloud.useMasterKey(); will not work here.
// in parse-server - you send useMasterKey to the function
var query = new Parse.Query(Parse.User);
var email = request.params.email;
query.equalTo("email", email);
query.first({
useMasterKey: true
}).then(function(user) {
response.success(user.getSessionToken());
}, function(error) {
response.error(error);
});

doesNotMatch query in Parse not working

I have two objects in Parse. The first one is notification where I save every challenge my user get. The second one is UserChallenge where I store every challenge a user completes. I tried to do a combined query where I only get results of notifications for challenges the user didn't complete and I get nothing in return. I checked my data and I should get two objects back.
Does anyone can tell what I did wrong in the query?
var Completed = Parse.Object.extend("Picok_User_Challenge");
var completedQuery = new Parse.Query(Completed);
completedQuery.equalTo("picok_user_id",currentUser);
var Challenges = Parse.Object.extend("Picok_Notifications");
var challengesQuery = new Parse.Query(Challenges);
challengesQuery.include("new_challenge_id");
challengesQuery.equalTo("type", "CHALLENGE");
challengesQuery.equalTo("who_recived", currentUser);
challengesQuery.doesNotMatchKeyInQuery("new_challenge_id","picok_challenge_id",
completedQuery);
challengesQuery.find({
success: function(results) {
console.log("createNotifiction success count: " + results.length);
response.success("YAY");
},
error: function(object, error)
{
console.log(error);
alert('Failed to get challenge not completed for: ' + request.params.user);
response.error('Failed to get user challenges to complete for: ' + request.params.user);`
}
});

Parse - afterSave and accessing request object?

I send a request to parse that includes a Comment object that has a pointer to a User named "from".
In afterSave I need to read this and I'm having all kinds of problems. beforeSave works just fine, but I want to execute this code in afterSave;
Parse.Cloud.afterSave("Comment", function(request) {
var userQuery = new Parse.Query("User");
userQuery.get(request.object.get("from").id, {
success: function(user) {
},
error : function(error) {
console.error("errrrrrrrr" + error);
}
});
});
Here is the log I'm seeing on parse
errrrrrrrrr [object Object]
EDIT:
I also tried
var userQuery = new Parse.Query("_User");
Seems like I had to call useMasterKey, since I was fetching a user data.
I'm not entirely sure about this though so I'll keep this question open.
Parse.Cloud.useMasterKey();
Have you tried this?
var userQuery = new Parse.Query(Parse.User);
Try to fetch the pointer directly:
var fromUserPointer = request.object.get("from");
fromUserPointer.fetch().then(function(fetchedFromUser){
},function(error){
});
Slightly different approach.
This assumes that you have the comment object available right there, or at least its id.
Instead of querying the User collection, how about this:
var commentQuery = new Parse.Query("Comment");
commentQuery.include("from");
commentQuery.get(<commentId>, {
success: function (comment)
{
var user = comment.get("from"); // Here you have the user object linked to the comment :)
},
error: function (error)
{
console.log("ERROR: ");
console.log(error);
}
});

Resources