Parse-server: Query for Parse.User is empty when calling 2nd time

Created on 26 Mar 2016  路  23Comments  路  Source: parse-community/parse-server

Environment Setup

Parse Server 2.2.2
Using Parse JS SDK

Steps to reproduce

I'm setting an ACL for every user that is saved in an afterSave Hook:

Parse.Cloud.afterSave('_User', function(request, response) {
  // Use the masterkey
  Parse.Cloud.useMasterKey();
  // Get the user
  var user = request.object;
  // Create an ACL
  var userACL = new Parse.ACL();
  userACL.setPublicReadAccess(false);
  userACL.setReadAccess(user, true);
  userACL.setWriteAccess(user, true);
  userACL.setRoleWriteAccess("admin", true);
  userACL.setRoleReadAccess("admin", true);
  // Set the ACL to the user
  user.setACL(userACL);
  // Save the user
  user.save()...

This should now allow only the user itself or and admin user to read/write the user object.
When I now query for ALL users as and admin like this:

    let query = new Parse.Query(Parse.User);
    query.ascending('username');
    query.find().then(users => {
      this.users = users;
      console.log(this.users);
    }, error => {
      console.log('Error: ' + error.code + ' ' + error.message);
    });

I get a list of all users. But when I run the same query a second time, it is empty.

Most helpful comment

Oh, this is already fixed in the master branch of the JS SDK. I'm just waiting on others to fix the issues with RN and the new LiveQueries interface before releasing 1.8.2.

All 23 comments

Again, Parse.Cloud.useMasterKey has no effet on parse-server!

Hmm, I do not 100% get what MasterKey has to do with that. I'm using the provided query within a webapp so I don't want to use masterKey at all. Does this mean that I can not get a list of users within an app?

Are you sure in the database that those users are stored with the permissions you expect? because you use Parse.Cloud.useMasterKey(); there is a chance you can't update the users with the permissions you'd expect. What's the status of user.save() ?

Jep, in the Db the users look correct:

{
  "_id": "eKePsMPrk3",
  "_rperm": [
    "eKePsMPrk3",
    "role:admin"
  ],
  "_wperm": [
    "eKePsMPrk3",
    "role:admin"
  ],
  "username": "myname",
  "email": "[email protected]",
  "role": "customer",
  ...
}

The strange thing is that the first time I run the query, the result contains the expected Users in the array. Only the second time it is empty.

What do you mean the second time? what's your code? Can you provide the server logs when running in VERBOSE?

As mentioned in the OP I have a query function which is called inside my App:

loadUsers() {
  let query = new Parse.Query(Parse.User);
  query.ascending('username');
  query.find().then(users => {
    this.users = users;
    console.log(this.users);
  }, error => {
    console.log('Error: ' + error.code + ' ' + error.message);
  });
}

The first time it is called I get a valid list of users.
Verbose output:

GET /api/classes/_User { host: 'localhost:1337',
  connection: 'keep-alive',
  'content-length': '236',
  origin: 'http://localhost:8100',
  'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1',
  'content-type': 'text/plain',
  accept: '*/*',
  referer: 'http://localhost:8100/',
  'accept-encoding': 'gzip, deflate',
  'accept-language': 'en' } {
  "where": {},
  "order": "username"
}
response: {
  "response": {
    "results": [
      {
        "ACL": {
          "QTS1i60M7m": {
            "read": true,
            "write": true
          },
          "role:admin": {
            "read": true,
            "write": true
          }
        },
        "objectId": "QTS1i60M7m",
        "username": "XXXX",
        "email": "XXXX",
        "role": "customer",
        "updatedAt": "2016-03-26T12:23:43.954Z",
        "createdAt": "2016-03-26T12:23:43.695Z"
      },
      {
        "ACL": {
          "UPUyk6WjaS": {
            "read": true,
            "write": true
          }
        },
        "objectId": "UPUyk6WjaS",
        "username": "[email protected]",
        "email": "[email protected]",
        "role": "super",
        "updatedAt": "2016-03-26T13:51:57.945Z",
        "createdAt": "2016-03-26T12:16:58.560Z",
      },
      {
        "ACL": {
          "eKePsMPrk3": {
            "read": true,
            "write": true
          },
          "role:admin": {
            "read": true,
            "write": true
          }
        },
        "objectId": "eKePsMPrk3",
        "username": "XXXX",
        "email": "XXXX",
        "role": "customer",
        "updatedAt": "2016-03-26T12:24:04.310Z",
        "createdAt": "2016-03-26T12:24:04.071Z"
      },
      {
        "ACL": {
          "tOWuF3IIcS": {
            "read": true,
            "write": true
          },
          "role:admin": {
            "read": true,
            "write": true
          }
        },
        "objectId": "tOWuF3IIcS",
        "username": "XXXX",
        "email": "XXXX",
        "role": "customer",
        "updatedAt": "2016-03-26T12:24:21.006Z",
        "createdAt": "2016-03-26T12:24:20.769Z"
      }
    ]
  }
}

When I run the exact same function a second time from my app, I get an empty array back:

GET /api/classes/_User { host: 'localhost:1337',
  connection: 'keep-alive',
  'content-length': '183',
  origin: 'http://localhost:8100',
  'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1',
  'content-type': 'text/plain',
  accept: '*/*',
  referer: 'http://localhost:8100/',
  'accept-encoding': 'gzip, deflate',
  'accept-language': 'en' } {
  "where": {},
  "order": "username"
}
response: {
  "response": {
    "results": []
  }
}

NOTE:
Both times I call the function as a logged in "admin" user.

I noted as well that if I log out and in again, my loadUsers() function suddenly returns the users but then again when calling it a second time, the result is an empty array again.

I just did a test for the same query using a standard curl request:

curl -X GET -H "X-Parse-Application-Id: myapp" -H "X-Parse-Session-Token: r:63fe72cfbb93cb1de49547e0dccaed0b" -H "Cache-Control: no-cache" "http://localhost:1337/api/classes/_User"

Where the session token is the one that my admin user got in the webapp. This request is always returning the correct user list. So I guess this could be an issue with the JS SDK...

Maybe @andrewimm, @drew-gross ? that do you think?

@flavordaaave I don't see the session token being passed to your queries...

@flovilmart I thought when using the JS SDK I don't need to pass the session token because the SDK automatically takes care of that as soon as I'm logged in and have a valid session. At least this is how it has been working with other queries for me so far.

What I'm saying is that I don't see the session token in your request headers in the server logs.

Ah, okay. Sorry...
Btw. I have a similar query in my app where I load all orders of a user. The order Objects have an ACL similar to my Users:

Order Object in DB:

{
  "_id": "2frxdfNlKZ",
  "_rperm": [
    "role:admin",
    "6qQBHeqaJY"
  ],
  "_wperm": [
    "role:admin",
    "6qQBHeqaJY"
  ],
  ...
}

Query for the Orders (as admin user) the same way as done with the Users class in the example above results in:

GET /api/classes/Order { host: 'localhost:1337',
  connection: 'keep-alive',
  'content-length': '280',
  origin: 'http://evil.com/',
  'user-agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1',
  'content-type': 'text/plain',
  accept: '*/*',
  referer: 'http://localhost:8100/',
  'accept-encoding': 'gzip, deflate',
  'accept-language': 'en' } {
  "where": {},
  "order": "-createdAt"
}
response: {
  "response": {
    "results": [
      {
        "ACL": {
          "role:admin": {
            "read": true,
            "write": true
          },
          "QTS1i60M7m": {
            "read": true,
            "write": true
          }
        },
        "objectId": "2frxdfNlKZ",
        ...
      }
    ]
  }
}

The strange thing here is that this query always returns the array including all the orders where as the user query still only returns results the 1st time it is called during a session...

Maybe related to the way we cache users and roles on parse-server

Sorry for all the spam but I noticed another interesting thing here:

Query for users:

let query = new Parse.Query(Parse.User);
query.ascending('username');
query.find().then(users => {
  console.log(users);
  return Parse.User.current().fetch();
}).then(currentUser => {
  console.log(currentUser);
}, error => {
  console.log(error);
});

==> Console shows error for fetching user

Query for orders:

let order = Parse.Object.extend('Order');
let query = new Parse.Query(order);
query.find().then(orders => {
  console.log(orders);
  return Parse.User.current().fetch();
}).then(user => {
  console.log(user);
}, error => {
  console.log(error)
});

==> User is fetched without any problems.

So it seems to me that when querying for the _User class, something with the session gets messed up.

Parse.User.current() is not available in Cloud Code in parse server, you need to use request.user

I'm running those queries in a webapp using the JS SDK, not cloud code.

Ok.

Another hint :wink:
When I exclude the current user from the query to get all users, everything is working as expected.

    let query = new Parse.Query(Parse.User);
    query.ascending('username');
    query.notEqualTo('email', Parse.User.current().getEmail());
    query.find().then(users => {
      console.log(users);
    }).then(currentUser => {
      console.log(currentUser);
    }, error => {
      console.log(error);
    });

This way my loadUsers() function always returns an array with users.
So it seems that only when the current user itself is part of the result of the query, things get messed up.

I just caught up with this thread and it is not clear to me if this is a backend issue or a JavaScript SDK issue. The best way to answer that question is to use the REST API directly.

Can you reliably reproduce the specific issue where running the query for a second time returns in an empty result set, when using the REST API?

If this can only be reproduced when the JavaScript SDK is used, this may actually be an issue with the SDK instead.

@hramos I already did the test against the REST API (see my curl example above) and there everything worked correct. So I guess this is an issue with the JS SDK. As far as I could debug I assume the JS SDK has problems when the result of a query for Parse.User contains the currently logged in user itself.

Oh, this is already fixed in the master branch of the JS SDK. I'm just waiting on others to fix the issues with RN and the new LiveQueries interface before releasing 1.8.2.

Great so this can be closed. THX

Was this page helpful?
0 / 5 - 0 ratings