How to get an object from a list of objects (ASP.NET MVC4) - asp.net-mvc-4

I know how to "translate" this into code:
if the Cancellation.User.Id is the same as currentUser.Id
if (cancellation.User.Id != currentUser.Id){...}
But what if my Cancellation object contains not one User but a List<User> Users?
How do I check if the Cancellation object contains a User whose Id is the same as currentUser.Id?

LINQ will solve this quite nicely.
if (cancellation.Users.Any(u => u.ID == currentUser.Id)){...}
Note that this is true if there is a matching user in the list, which is what you said in your last sentence, but seems counter to the code snippet you provided, which is checking if the ID does not match. If you want to trigger this code if none of the users match, just put a ! before the whole lot (not in the lambda).

Related

Firestore Database Rules for User

I'm following a tutorial about firestore but I don't understand firestore rules very well. I'm trying to allow anyone to be able to create in the standard
users/uid/
path but only allow updates if the requester is trying to update
users/theirUserId/
I saw this in the documentation, but it didn't seem to work for me:
allow write: if request.auth.uid == resource.data.author_id;
Can anyone explain the functionality of the above line and/or offer suggestions as to how I can achieve this?
Additionally, is there any way to specify rules for a specific piece of data within a document?
It looks like that your document doesn't contain a author_id field.
The Firebase documentation Writing Conditions for Security Rules use this example:
service cloud.firestore {
match /databases/{database}/documents {
// Make sure the uid of the requesting user matches the 'author_id' field
// of the document
match /users/{user} {
allow read, write: if request.auth.uid == resource.data.author_id;
}
}
}
It means that a random user will be able to read and write in the users collections only if their authentication ID equals the author_id field of a specific document.
The resource variable refers to the requested document, and resource.data is a map of all of the fields and values stored in the document. For more information on the resource variable, see the reference documentation.
For your second question, I recommend you to have a look on the documentation about resource variable (link in the quote above). It is the same logic as your author_id question.
You can split allow write in to three create, update, delete for specific cases.
In your case
allow create: if request.auth.uid != null;
allow update: if request.auth.uid == resource.data.author_id;
which says any authenticated users can create and only update their on document. and created user must have a field author_id which is their user id.

Firebase - Security Rule Restricting Write to Node Owner/Creator

In the screenshot below, my details branch/node contains lots of details named with a random-id. As shown in the example, 8641260c-900... is a detail record and there will be several others like these.
I would like to know whether my .write rule is correct or not? I wanted to enable restriction so that current auth.id exactly match the existing record's user field.
I would also wanted to restrict deletion of the record (via .remove).
Can I simply add && !data.exists() || newData.exists() to the .write rule?
Thanks in advance.
I would like to know whether my .write rule is correct or not?
First of all, giving ".read":true and ".write":true to the root will override all child node rules to true. Therefore any rules specified to child nodes will become redundant.
I wanted to enable restriction so that current auth.id exactly match the existing record's user field.
{"rules":{
"existing_record":{
"user":{
".write":"newData.isString() && auth.uid == newData.val()"
}
}
}}
I would also wanted to restrict deletion of the record (via .remove).
newData.exists() will prevent deletion of a node. newData represents how data will look like after the operation took place. Therefore, by ensuring that newData exists after the operation, deletion of a node is prohibited.

How do I implement, for instance, "group membership" many-to-many in Parse.com REST Cloud Code?

A user can create groups
A group had to have created by a user
A user can belong to multiple groups
A group can have multiple users
I have something like the following:
Parse.Cloud.afterSave('Group', function(request) {
var creator = request.user;
var group = request.object;
var wasGroupCreated = group.existed;
if(wasGroupCreated) {
var hasCreatedRelation = creator.relation('hasCreated');
hasCreatedRelation.add(group);
var isAMemberOfRelation = creator.relation('isMemberOf');
isAMemberOfRelation.add(group);
creator.save();
}
});
Now when I GET user/me with include=isMemberOf,hasCreated, it returns me the user object but with the following:
hasCreated: {
__type: "Relation"
className: "Group"
},
isMemberOf: {
__type: "Relation"
className: "Group"
}
I'd like to have the group objects included in say, 'hasCreated' and 'isMemberOf' arrays. How do I pull that using the REST API?
More in general though, am I approaching this the right way? Thoughts? Help is much appreciated!
First off, existed is a function that returns true or false (in your case the wasGroupCreated variable is always going to be a reference to the function and will tis always evaluate to true). It probably isn't going to return what you expect anyway if you were using it correctly.
I think what you want is the isNew() function, though I would test if this works in the Parse.Cloud.afterSave() method as I haven't tried it there.
As for the second part of your question, you seem to want to use your Relations like Arrays. If you used an array instead (and the size was small enough), then you could just include the Group objects in the query (add include parameter set to isMemberOf for example in your REST query).
If you do want to stick to Relations, realise that you'll need to read up more in the documentation. In particular you'll need to query the Group object using a where expression that has a $relatedTo pointer for the user. To query in this manner, you will probably need a members property on the Group that is a relation to Users.
Something like this in your REST query might work (replace the objectId with the right User of course):
where={"$relatedTo":{"object":{"__type":"Pointer","className":"_User","objectId":"8TOXdXf3tz"},"key":"members"}}

yii rbac: check autorizations on groups instead of users

I have a question about the rbac system. I think I've pretty well understood it but I need more informations about a special case.
I would like to do the autorisations on groups instead of users. I mean for instance the group "HR" has permission to create a person. Then any person who join this group would have it as well.
Let me give you more informations.
A part of my database:
And this a part of what my group hierarchy could be:
So what I'm looking for, this would be a must, is a system where each group has some autorizations. People get the autorizations of their group and of their parents group (for instance people in "Forsys" has the autorizations of "Forsys", "R&D" and "Administration").
The solution I see at the moment is using bizrule. But I'm not sure write php code in database is a good idea and then if I update the group hierarchy (R&D inherits of RH instead of Administration) I would have to modify bizrule in database. I tried it and it works well but as you can see it require a lot of code.
$user = User::model()->with("people","people.groups")->findByPk(Yii::app()->user->id);
foreach($user->people[0]->groups as $group)
if($group->id == 2)
return true;
return false;
It's just for see if a user is in a group (without checking parent groups and hierarchy)
Another possibility could be create a new table "group_auth" where we would say for instance:
-Group_2 has role "managePerson"
-Group_3 has operation "deleteUser"
...
And then everytime a user is added in or removed of a group we would update his autorizations in the auth_assigment table.
I'd like to hear other opinions on this subject.
All comments will be appreciated :)
Thank you for reading and sorry for my English if you had difficulties to understand me.
Michaƫl S.
Do users ever get their own authorization items? If not, seems like you could in essence swap out the userid column in auth_assignment and name it / treat it as groupID instead. That way you wouldn't need to worry about keeping user auth assignments in sync with your group roles.
A couple of places you'd probably need to make some changes:
- by default CWebUser passes in the logged in userid for use in bizrules. Might be good to change that our with your own override that passes in groupId/groupIds instead.
- you'd need to override CDbAuthManager and rework some of how things work there
We've done something similar on a project I've worked on (we were handling multi-tenant RBAC custom permissions), which required custom CDbAuthManager overrides. It gets a bit tricky if you do it, but there is an awful lot of power available to you.
Edit:
Understood about your users sometimes needing to have additional authorizations. What if your group has a 'roles' field with different roles serialized in it (or some other method of having multiple roles stored for that group, could also be a relationship).
Then, on user login (for efficiency), you'd store those roles in session. Probably the easiest way to handle things would be to write a custom checkAccess for your WebUser override:
https://github.com/yiisoft/yii/blob/1.1.13/framework/web/auth/CWebUser.php#L801
as that will make things simpler to do your custom checking. Then I'd probably do something like:
if(Yii::app()->user->hasGroupAccess() || Yii::app()->user->checkAccess('operation/task/role')) {
....
}
In your WebUser hasGroupAccess method, you could loop over all group roles and send those to checkAccess as well.
Think that will work?
What I use to check access for groups when it's in another table, or somewhere else in the application I give the user the role per default. By using this:
return array(
'components'=>array(
'authManager'=>array(
'class'=>'CDbAuthManager',
'defaultRoles'=>array('authenticated', 'R&D', 'Administration'),
),
),
);
Under: Using Default Roles
By using this, every user gets these assignments. Now, I create a business rule to make sure that the checkAccess('group') will return the correct value.
For example in your case the business rule for R&D would be:
return (
count(
Person::model()->findByPk(Yii::app()->user->id)->groups(array('name'=>'R&D'))
) > 0
) ? true : false;
So what this does is:
find the logged-in person by primary key
look into groups (from the user) for the group with name R&D
if there is a group: return true (else return false)

Rails3: Cascading Select Writer's Block

I have a big, flat table:
id
product_id
attribute1
attribute2
attribute3
attribute4
Here is how I want users to get to products:
See a list of unique values for attribute1.
Clicking one of those gets you a list of unique values for attribute2.
Clicking one of those gets you a list of unique values for attribute3.
Clicking one of those gets you a list of unique values for attribute4.
Clicking one of those shows you the relevant products.
I have been coding Rails for about 4 years now. I just can't unthink my current approach to this problem.
I have major writer's block. Seems like such an easy problem. But I either code it with 4 different "step" methods in my controller, or I try to write one "search" method that attempts to divine the last level you selected, and all the previous values that you selected.
Both are major YUCK and I keep deleting my work.
What is the most elegant way to do this?
Here is a solution that may be an option. Just off the top of my head and not tested (so there is probably a bit more elegant solution). You could use chained scopes in your model:
class Product < ActiveRecord::Base
scope :with_capacity, lambda { |*args| args.first.nil? ? nil : where(:capacity=>args.first) }
scope :with_weight, lambda { |*args| args.first.nil? ? nil : where(:weight=>args.first) }
scope :with_color, lambda { |*args| args.first.nil? ? nil : where(:color=>args.first) }
scope :with_manufacturer, lambda { |*args| args.first.nil? ? nil : where(:manufacturer=>args.first) }
self.available_attributes(products,attribute)
products.collect{|product| product.send(attribute)}.uniq
end
end
The code above will give you a scope for each attribute. If you pass a parameter to the scope, then it will give you the products with that attribute value. If the argument is nil, then the scope will return the full set (I think ;-). You could keep track of the attributes they are drilling down in in the session with 2 variables (page_attribute and page_attribute_value) in your controller. Then you call the entire chain to get your list of products (if you want to use them on the page). Next you can get the attribute values by passing in the set of products and the attribute name to Product.available_attributes. Note that this method (Product.available_attributes) is a total hack and would be inefficient for a large set of data, so you may want to make this another scope and use :select=>"DISTINCT(your_attribute)" or something more database efficient instead of iterating thru the full set of products as I did in the hack method.
class ProductsController < ApplicationController
def show
session[params[:page_attribute].to_sym] = params[:page_attribute_value]
#products = Product.all.with_capacity(session[:capacity]).with_weight(session[:weight]).with_color(session[:color]).with_manufacturer(session[:manufacturer])
#attr_values = Product.available_attributes(#products,params[:page_attribute])
end
end
Again, I want to warn you that I did not test this code, so its totally possible that some of the syntax is incorrect, but hopefully this will give you a starting point. Holla if you have any questions about my (psuedo) code.