Parse: Get roles for an array of users - parse-platform

I have an array of users and I want to get each user's roles. For example, imagine my app displays a list of users and the names of their roles under their usernames. I cannot find any straightforward and cheap (without many requests) way to do this.

Query the roles. In most cases this will be one, small query.
For each user on your list, search the returned roles' users for that user. If you're searching on ID, you have all you need. (edit - removed reference to includeKey).

Can you not use a matchQuery. So from your list of users, use query to get all of user objects, and then use that query to get all of your roles. Once you have the roles, you can then match the roles to the users. I have gave the answer below for the Android SDK as you haven't specified which SDK you are using.
String[] userIds;
ParseQuery<ParseUser> innerQuery = ParseUser.getQuery();
innerQuery.whereContainedIn("objectId", userIds);
ParseQuery<ParseObject> query = ParseQuery.getQuery("Role");
query.whereMatchQuery("user", innerQuery);
query.findInBackground(new FindCallback<ParseObject>() {
public void done(List<ParseObject> roleList, ParseException e) {
}
});
Obviously you would need to fill out the userIds variable with the userIds of all your users. To be honest you could even use any other query for the users that would return all the users you want.

Related

Data normalization in GraphQL query

I'm using GraphQL to query a database that has two data types: User and Group.
Groups have a field users which is an array of User objects which are in that group. I have one field at root named groups which returns an array of all of my groups.
A typical query might look something like this:
{
groups {
id,
name,
users {
id,
name,
address,
email,
phone,
attitude,
job,
favoriteQuote,
favoriteColor,
birthday
}
}
}
The problem is that a lot of those users can belong to multiple groups and, seeing as User has a lot of fields, this can make responses quite large.
Is there any way to get one set of fields for the first instance of an object, and a different set for every other instance in the response?
I only need name, job, email etc etc once per user in the response, and just the id thereafter (I can do my own normalization afterwards).
alternatively
Is there any way to only get id fields for all users in groups and return a separate array of all unique User objects that have been referenced in the query (which is not all User objects)?
Is there any way to get one set of fields for the first instance of an object, and a different set for every other instance in the response?
No. The same set of fields will be returned for each item in a list unless the type of the individual item is different, since a separate selection set can be specified for each type returned at runtime.
Is there any way to only get id fields for all users in groups and return a separate array of all unique User objects that have been referenced in the query (which is not all User objects)?
You could design your schema to accommodate this. Something like
{
groups {
nodes {
id
name
users {
id
}
}
uniqueUsers {
id
# other fields
}
}
}
Your groups resolver would need to handle all the normalization and return the data in the appropriate shape. However, a simpler solution might be to just invert your relationship:
{
users {
id
name
address
email
phone
attitude
job
favoriteQuote
favoriteColor
birthday
groups {
id
name
}
}
}
Generally - usually
... normalization ... of course ... f.e. using apollo and it's normalized cache.
All records returned from API has to be the same shape.
You can get data and render some <MembersList/> component using query for ids and names only (full/paginated).
Later you can render details in some <UserProfile/> component with own query (hook useQuery inside) to fetch additional data from cache/api (controllable).
Your specific requirements - possible
1st option:
Usually response is of one common shape (as requested), but you can decide on resolver level what to return. This requires query structure changes that allows (API, backend) to null-ify some properties. F.e.
group {
id
name
users {
id
name
profile {
photo
email
address
With profile custom json type ... you can construct users resolver to return full data only for 1st record and null for all following users.
2nd option:
You can use 2 slightly different queries in one request. Use aliases (see docs), in short:
groupWithFullMember: group ( groupId:xxx, limitUsers:1 ) {
id
name
users {
id
name
address
email
...
}
}
groupMembers: group ( groupId:xxx ) {
id
name // not required
users {
id
name
}
}
Group resolver can return it's child users ... or users resolver can access limitUsers param to limit response/modify db query.

How to limit access from pivot table? Laravel

I have tables:
user
id
name
companies
id
name
company_user
company_id
user_id
Tables has Many To Many relationships.
As it complicated relationship for me, I can't find way how to make this limit, when user can see companies that was created by this user. (probably not well experienced)
Now I have this, but user can see any company
CompanyController:
public function show($company_id)
{
$company = Company::where('id', $company_id)->firstOrFail();
return view('company.settings', compact('company'));
}
So tip me please how to make user can see only companies created by this user.
You can do this:
public function show($company_id)
{
$company = auth()->user()->companies()->findOrFail($company_id);
return view('company.settings', compact('company'));
}
It will scope the company to the currently logged in user (through the many-to-many relationship on the User model). If none is found, it will return 404.
Since it many to many relation, you can map one company to many users, also map one user to many companies. Check if you have not mistakenly assign the company to many user
Also the above code can be written the way
public function show($company_id)
{
$company = Company::findOrFail($company_id);
return view('company.settings', compact('company'));
}

GraphQL relations leaking data, even with context.user resolver already set. How to prevent data exposure via relations?

How is everyone doing authentication across relations to prevent data from being traversed via relations?
For example we have a Shop which has Users.
// Returns error as i've set custom resolver to allow only context.user.is_shop_owner
{
shops {
name
users {
email
...
}
}
}
This query is normally blocked with a custom resolver like context.user.is_shop_owner, so you cannot execute this from root query.
However, if a malicious person traverses relations to reach the users object he is able to get the sensitive user data.
// Data exposed un-intendedly due to relation traversal. How to prevent this?
{
products {
name
price
shop {
users { ... } // boom, exposed
}
}
}
Is this a flaw in graphql? How are you guys working around this?
This is on a python-graphene stack btw.
Edit: Btw, i know we can do exclude_fields, but then i won't be able to access Users from the ShopNode, which is an important information to query for the ShopNode, so limiting fields are probably not a good idea. (edited)
This should probably be controlled within the Shop type, to return null when the user does not have the right permissions. Otherwise if a Shop were accessed from a second field, you'd have to duplicate the check.
I wound up setting custom resolvers for each node to block out the relations you want to limit access to based on the context.user. Refer to the code below in response to my question above.
class ProductNode(DjangoObjectType):
class Meta:
model = Product
interfaces = (graphene.relay.Node)
# Exclude nodes where you do not need any access at all
exclude_fields = ['users']
# For nodes where you need specific/limited access, define custom resolvers.
# This prevents the relation traversal loophole
def resolve_shop(self, args, context, info):
""" Allow access to nodes only for staff or shop owner and manager """
if get_is_staff_user(context.user, self):
return self.shop
Operations.raise_forbidden_access_error()

Laravel roles and permissions

I am new with Laravel and i am trying to build an application based on roles, but in my case the user can have only one role (there is no a pivot table between users and roles) and we can create new role us we like(assign many permissions to one role). Any help? and thanks a lot
So here is one way I would do it.
You need 2 tables :
One table I would call "ranks", inside it you can have everything about the rank itself :
Its id of course, but also :
Is it an admin rank ? (all permissions)
What's it name ? ...
One table I would call "ranks_abilities", inside it you can have everything about what a rank can do
Therefore, it would have three columns : an id, a rank_id, and the name of the ability
And you need to put the rank_id inside the users table.
Note : if you wanna do it really nicely, you can have a table "abilities" containing all the possible abilities, and you'd reference their ids instead of the name
So how would it work ?
You would therefore have three models :
User
Rank
RanksAbility
Inside of your User model, you'd have a belongs_to relationship to the Rank model (call it rank)
Inside of the Rank model, you'd have a has_many relationship to the RanksAbility model (call it ranks_abilities)
I guess we are now fine with the database structure, let's get to the point of allowing to do something.
So, of course, where a login is required, you have the auth middleware that does it perfectly
Then, to handle the permissions itself, there are several ways to do it, here is one I would recommend.
Step 1 :
Create a policy for some action for example if you have posts you can create a PostPolicy (https://laravel.com/docs/5.4/authorization#creating-policies)
If, you want, for example, a permission so that a user can edit all posts, you'd have an update method in that PostPolicy
public function update(User $user, Post $post)
{
return $user->hasPermission('post.update'); // You can also add other permissions for example if the post belongs to your user I'd add || $post->user_id == $user->id
}
I would do something like that.
Then, you'd have to make the hasPermission method.
So, in your User model, you could put something like this :
public function hasPermission($permission){
if(!$this->relationLoaded('rank')){
$this->load('rank', 'rank.ranks_abilities');
}
if(!$this->rank){
return false;// If the user has no rank, return false
}
foreach($this->rank->rank_abilities as $ability){
if($permission === $ability->name){
return true;// If the user has the permission
}
}
return false;
}
And here the method is done.
Last step, you can use all the methods listed here https://laravel.com/docs/5.4/authorization#authorizing-actions-using-policies to avoid an user from doing something he can't.
Personally, I would do a FormRequest, and handle the authorization with it (https://laravel.com/docs/5.4/validation#authorizing-form-requests).
I hope to be clear, if you have any more questions go ahead
For setting up customized user roles and permissions, you may give a try to https://thewebtier.com/laravel/understanding-roles-permissions-laravel/.
It's a complete guide on how to setup roles and permissions in your Laravel project.

Can I filter the Users returned by GetAllUsers based on a role they are in

I am trying to create an administration interface where users and roles (among other things) can be administered. I have a list of users who can be edited, deleted or viewed. I have this code in the action:
var model = Membership.GetAllUsers()
.Cast<MembershipUser>()
.Select(x => new UserModel
{
UserName = x.UserName,
Email = x.Email,
UserRoles = Roles.GetRolesForUser(x.UserName)
});
return View(model);
This is all fine except that I don't want admins to be able to edit each other. So I need to filter out all users in the "super admin" role. I can certainly figure this out by stepping through each role for each user to see if they are a member. I am wondering if there is a nice sucinct way to do this by filtering the result set in the Select statement, or using Except or Where
I would normally think about the sql I want generated then try write the linq, filtering by roles should be fairly easy with a simple where statement.
However it appears you're trying to abstract each part of the query into smaller bits, this may make it easier to write but can have a devastating effect on performance. For example, I wouldn't be suprised if the GetRolesForUser method you are calling causing an extra database query per user that is returned by GetAllUsers, using the Include method is a much nicer way to get all roles at the same time.
var model = context.Users
.Include(user => user.UserRoles)
.Where(user => !user.UserRoles.Any(role => role == superAdmin)
.Select(user => new UserModel() { UserName = user.UserName, Email = user.Email, UserRoles = user.UserRoles});

Resources