I am experiencing problems with accessing an object i created with role ACL. I created the object like this
var Enquiry = Parse.Object.extend("Enquiry");
var enquiry = new Enquiry();
enquiry.set("first", firstName);
enquiry.set("last", lastName);
var enquiryACL = new Parse.ACL();
enquiryACL.setRoleWriteAccess("XXX_User", true);
enquiryACL.setRoleReadAccess("XXX_User", true);
enquiry.setACL(enquiryACL);
enquiry.save();
I later on try to access the same object i created when a user of the role "XXX_User" is logged in
var Item = Parse.Object.extend("Enquiry");
var query = new Parse.Query(Item);
query.find({
success : function(items) {
displayItems(items);
},
error : function(error) {
alert("couldn't display list: " + error.code + " " + error.message);
}
});
Now the problem is that the query doesn't return any rows even though i can see in the dashboard that the object is created. The ACL set for the enquiry objects is {"role:XXX_User":{"write":true,"read":true}}
I can see that there is a Role Object with name "XXX_User" in the data browser and i can also see that the user i log in with is shown when i click "View Relations" on the Role object in the data browser.
Is there anything i am missing? Any help on this is deeply appreciated.
I figured out the problem. It was not working because the role XXX_User i created was saved with public read access to be false. I had to make sure that the role is publicly readable and then it worked like a charm.
Related
I have the class "Users" the default of Parse Dashboad. I have also the class "Friends", where I store the friendships between users like this:
There are two columns, "toUser" and "fromUser", which are showing who of the two users sent the friend request. These two columns are Pointers(Pointer<_User>) to the Users Class.
My concept is to retrieve two lists:
1. Friendlist for the logged in user
2. Userlist of users (who are not friends with the logged in user)
What would be the appropriate queries for that?
The first one logically should not scan all the class Users because it may slow down the perfomance of the app which is using Ionic 3 and Angular 4
Thank you
you don't need another class to do so all you need is a relation column in the default user class
to add new friend you just need the following code
var friendtoadd
//this is the friend object from parse user class you want to add you can get it by anyway you want
var currentUser = Parse.User.current();
var relation = currentUser.relation("friends");
relation.add(friendtoadd)
currentUser.save();
to retrieve array of friends of logged in user you can use the following code
var currentUser = Parse.User.current();
var friendRelation = currentUser.relation('friends');
var env = this
friendRelation.query().find({
success: function(users) {
for (var i = 0; i< users.length; i++) {
var object = users[i];
env.friends.push(object)
console.log(env.friends)
}
}
});
// you should define friends = []; in the class
if I understood your question right you want to find the friend requests you sent, or the ones you received. because I don't see where you made a relation between the user and his friends.
this is the code if you want to do this using cloud code:
First I validated the parameters of the friendRequest being saved :
Parse.Cloud.beforeSave("Friends", function(request, response){
var friendRequest = request.object;
if (!friendRequest.has("toUser") || !friendRequest.has("fromUser")) {
response.error("Invalid parameters");
return;
}
response.success();
});
then I created two cloud functions, one for retrieving the sentRequests:
Parse.Cloud.define("getSentRequests", function(request, response){
var query = new Parse.Query("Friends");
query.equalTo("fromUser", request.user);
if (!request.master) {
query.find({ sessionToken: request.user.getSessionToken() }).then(function(friends){
response.success(friends);
});
}else{
query.find({useMasterKey:true}).then(function(friends){
response.success(friends);
});
}
});
and you can call this either from a logged in user or using the masterKey if you want, and the other query is for the recievedRequests:
Parse.Cloud.define("getRecievedRequests", function(request, response){
var query = new Parse.Query("Friends");
query.equalTo("toUser", request.user);
if (!request.master) {
query.find({ sessionToken: request.user.getSessionToken() }).then(function(users){
response.success(users);
});
}else{
query.find({useMasterKey:true}).then(function(users){
response.success(users);
});
}
});
I am migrating Parse.com cloud code to hosted parse-server. Mongodb is already migrated.
The code is supposed to retrieve a user's sessionToken according to its google plus id. The find operation succeeds and a user is returned but the user does not have any sessionToken.
EDIT regarding mongodb:
Checking mongo db directly - the _User table record holds a _session_token value. In the _Session table I could not find that _session_token. Also I could not find any entry for that _User (I concatenated _User$ when searching).
The code is (more or less) so:
Parse.Cloud.define("getParseUserSessionToken", function(request, response) {
var googlePlusId = ...;
// here we're doing some code to get the google id
// assume it is set
var googleIdQuery = new Parse.Query(Parse.User);
googleIdQuery.equalTo(GOOGLE_PLUS_ID_FIELD_KEY, googlePlusId);
searchUserQuery.find({
useMasterKey: true
}).
then(function(users) {
if (users && users.length > 0) {
var user = users[0]; //user exist
var token = user.getSessionToken();
if (token) {
//user exist, return sessionToken
// ....
} else {
// CODE REACHES HERE AS THERE'S NO TOKEN
// return error: "no token"
}
}
}
As you can see I pass userMasterKey: true to find()
With a debugger I can see that I get a user with data, but without a token. I tried several things but nothing works.
Any idea what am I missing?
I have created a trigger that will auto-create a contact when a specific Account record type is created or updated. The problem is that I am not sure how to populate the Contact 'Account Name' lookup field. This field is a lookup to the Account object. My code is below. Any help on how to integrate this missing component would be greatly appreciated.
trigger autoCreateContact on Account (after update, after insert)
{
List newContact = new List();
for (Account oAccount : trigger.new)
{
if (oAccount.RecordTypeid == '012F0000001MCfgIAG')
{
List<Contact> cCheck = [SELECT ID From Contact WHERE LastName=:oAccount.Name];
if(cCheck.isEmpty()==True)
{
System.debug(oAccount);
Contact oContact = new Contact();
oContact.LastName = oAccount.Name;
oContact.phone = oAccount.Phone;
oContact.email = oAccount.Email__c;
oContact.Owner = oAccount.Owner;
newContact.add(oContact);
}
}
if(newContact.isEmpty() == false)
{
Database.insert(newContact);
}
}
}
nice trigger I'm pretty sure you just need to add one line which is a reference to the account.id.
So if I were you I would add the link:
oContact.AccountID = oAccount.id;
NOTE: its not a good practice to have a SOQL inside the for loop.
I have a custom object Team in Parse with a relation field for the default User object. What I would like to do is retrieve all User objects which are not related to any Team object. Can anyone point me in the right direction on how to do this using the JavaScript SDK? I've been going over the documentation for the Query object but I can't find anything.
Perhaps another type of relation, or placing the relation at another place is a better solution. What I want to accomplish is the following: Each user is allowed to be in one team and one team only. In addition I need to be able to query the following information from Parse:
I want to retrieve the User objects of all the users assigned to a team
I want to retrieve the User objects of all the users who are not assigned to any team
I have tried using a join table with both the user and team object ids. Then I tried to following query to get all users not assigned to a team:
var teammember = Parse.Object.extend('TeamMember'),
query = new Parse.Query("User");
var innerQuery = new Parse.Query("TeamMember");
query.doesNotMatchQuery('user', innerQuery);
query.find({
success: function(results) {
response.success(results);
},
error : function(error) {
response.error(error);
}
})
But this just gets me the following response: error: "{"code":102,"message":"bad type for $notInQuery"}".
I like the Relation type as I can add or remove multiple members at once with a single call to the REST API. I also have no problems retrieving the information on team members when using the Relation type to connect the users to the teams. It is just getting the users which are not assigned to any team that is giving me problems.
It doesn't sound like you need a relation at all. Instead, add a Pointer column to User that points to Team. It ensures that a User can only belong to one team, and your other requirements can be captured as follows.
// All users assigned to a team
query = new Parse.Query('User');
query.exists('team');
// All users assigned to a specific team
query = new Parse.Query('User');
query.equalTo('team', specificTeam);
// All unassigned users
query = new Parse.Query('User');
query.doesNotExist('team');
Update: If you need to support multiple teams per User in the future, then I would suggest creating a Parse table called Membership with two columns: a Pointer to User and a Pointer to Team. This essentially gives you more control than relying on Parse relations, but it gets a little more complicated.
_ = require('underscore'); // Or lodash
// All users assigned to a team
query = new Parse.Query('Membership');
query.find().then(function (results) {
// http://underscorejs.org/#uniq
users = _.uniq(results, false, function (user) { return user.id; });
});
// All users assigned to a specific team
query = new Parse.Query('Membership');
query.equalTo('team', specificTeam);
// All unassigned users
var assignedUsers = []
var unassignedUsers = []
memberQuery = new Parse.Query('Membership');
userQuery = new Parse.Query('User');
memberQuery.find().then(function (memberResults) {
// http://underscorejs.org/#map
var ids = _.map(memberResults, function (user) { return user.id; });
// http://underscore.js.org/#uniq
assignedUsers = _.uniq(ids);
userQuery.find();
}).then(function (userResults) {
var users = _.map(userResults, function (user) { return user.id; });
// http://underscorejs.org/#difference
unassignedUsers = _.difference(users, assignedUsers);
});
To add and remove Users to/from Teams, you would create Membership objects and save API calls with Parse.Object.saveAll() and Parse.Object.destroyAll().
I ran into trouble with the answer provided by Seth. When retrieving the users not assigned to a team the difference between the two arrays would be incorrect. I am assuming this is due to the assignedUsers having object of type Membership and userResults being of type User. This would make it impossible for underscore to make a proper match.
I would up using this as my Cloud Code:
Parse.Cloud.define("getTeamlessUsers", function(request, response) {
var _ = require("underscore"),
assignedUsers = [],
companyUsers = [],
memberQuery = new Parse.Query("TeamMembers"),
userQuery = new Parse.Query("User"),
index,
ubound;
memberQuery.find().then(function(memberResults) {
// Make sure each User ID will appear just once
memberResults = _.unique(memberResults, false, function(item) { return item.get('user').id; });
// Loop over the unique team members and push the User ID into the array
for (index = 0, ubound = memberResults.length; index < ubound; index++) {
var user = memberResults[index].get("user");
assignedUsers.push(user.id);
}
// Get al the users
return userQuery.find();
}).then(function(userResults) {
// Loop over all the users and push the ID into the array
for (index = 0, ubound = userResults.length; index < ubound; index++) {
companyUsers.push(userResults[index].id);
}
// Create an array of user IDs which are not present in the assignedUsers array
var result = _.difference(companyUsers, assignedUsers);
// Return the IDs of user not assigned to any team
response.success(result);
}).fail(function(error) {
response.error(error);
});
});
Here's what I am trying to achieve but somehow I am stuck and I am not sure what's the proper approach, I cannot find any good examples of such case so I am seeking your help.
Each registered user can add new object to class "List". Once the new item is created I call afterSave function and assign proper ACL creating new role ("membersOf_" + List.id). Next, user can add new object to class "Items", which will store List.id as a reference and ACL for item should be inherited from list. Lists and Items can be shared between multiple users of their choice. There are few problems in such case:
when creating new List, I need to create new role and assign creator to it and add such role to created List
when creating new Item, I need to pass List.id as a payload and validate with cloud code if current user can create such item (assigned to specified List) by checking first if he has proper permissions to List
if permission check is ok, I need give this item the same ACL as List has and proceed with saving
Here's my afterSave for List, creating role properly and assigning ACL to List object. (1) I am missing adding this role to user (creator)
Parse.Cloud.afterSave("List", function(request, response) {
var list = request.object;
var user = Parse.User.current();
if (list.existed()) {
// quit on update, proceed on create
return;
}
var roleName = "membersOf_" + list.id;
var listRole = new Parse.Role(roleName, new Parse.ACL(user));
return listRole.save().then(function(listRole) {
var acl = new Parse.ACL();
acl.setPublicReadAccess(false);
acl.setPublicWriteAccess(false);
acl.setReadAccess(listRole, true);
acl.setWriteAccess(listRole, true);
var itemData = new Parse.Object("List", {
ACL: acl
});
return itemData.save('objectId', list.id);
});
// to do - add user to this role too
});
Here's my Item beforeSave to validate if user can actually create such object, I am checking if he can query the List table, if he get >0 results for such List that means he will be ok to adding an Item assigned to this List. (2) Missing ACL inheritance
Parse.Cloud.beforeSave("Item", function(request, response) {
var item = request.object;
var listId = request.object.get("list");
var user = Parse.User.current();
var List = Parse.Object.extend("List");
var query = new Parse.Query(List);
query.equalTo("objectId", listId);
query.first({
success: function(list) {
if (list.id) {
response.success();
}
else {
response.error('No such list or you don\'t have permission to perform this operation.');
}
},
error: function(error) {
response.error(error);
}
});
});
Can someone point me to the proper solution or help solve that puzzle? I am missing two things:
- (1) I need to add user (creator) to new role created in afterSave
- (2) I need to add the same ACL to Item, inherit it from List object
I have tried many things, passing ACL in afterSave for Item, modifying payload in beforeSave. Many different functions following documentation and different examples, but still no luck.
Any advice would be awesome!
Ok, I think I finally figured it out. Hopefully this will help someone in future.
Here are final beforeSave and afterSave functions adding user to specified role and assigning the same ACL to Item object
Parse.Cloud.afterSave("List", function(request, response) {
var list = request.object;
var user = Parse.User.current();
if (list.existed()) {
// quit on update, proceed on create
return;
}
var roleName = "membersOf_" + list.id;
var listRole = new Parse.Role(roleName, new Parse.ACL(user));
//+ adding user to role in this line:
listRole.relation("users").add(user);
return listRole.save().then(function(listRole) {
var acl = new Parse.ACL();
acl.setPublicReadAccess(false);
acl.setPublicWriteAccess(false);
acl.setReadAccess(listRole, true);
acl.setWriteAccess(listRole, true);
var itemData = new Parse.Object("List", {
ACL: acl
});
return itemData.save('objectId', list.id);
});
// to do - add user to this role too
});
Parse.Cloud.beforeSave("Item", function(request, response) {
var item = request.object;
var listId = request.object.get("list");
var user = Parse.User.current();
// + modifying payload with the same ACL here
var acl = new Parse.ACL();
acl.setPublicReadAccess(false);
acl.setPublicWriteAccess(false);
acl.setRoleWriteAccess("membersOf_" + listId, true);
acl.setRoleReadAccess("membersOf_" + listId, true);
item.set('ACL', acl);
var List = Parse.Object.extend("List");
var query = new Parse.Query(List);
query.equalTo("objectId", listId);
query.first({
success: function(list) {
if (list.id) {
response.success();
}
else {
response.error('No such list or you don\'t have permission to perform this operation.');
}
},
error: function(error) {
response.error(error);
}
});
});