Hi,
Great job on app ! It's possible to store conditions with operator in mongoDB ?
If i put "conditions:{email:"[email protected]"}" check ability return true in case of email like [email protected]. But how do you do for thing like "conditions:{email:{$regex:'^a'}}" for example ?
Thank you
Yes you can use:
$eq, $ne, $in, $all, $gt, $lt, $gte, $lte, $exists, $regex, $elemMatch, field dot notation
Exactly the same way as you would write query in MongoDB
Yes but what's the correct syntax for store in collection ? Because store thing like {conditions: email:{$regex:'^a'}} in DB throw error on $ in key name and wrapper key name with quote make my ability.can('read',Users) return false even when email is like [email protected].
I can do it directly by define rules : can('read',Users,{email:{$regex:/^a/}}) it's ok, ability.can('read',Users) return true if email is like [email protected].
Excuse my poor english, don't out your eyes please :/
I鈥檓 not sure what you mean by store in collection .
If you could provide the whole example in something like jsfiddle or at least show the shape of Users, it would help me to help you :)
Sorry.
I want to store ability in a mongoDB collection (named Roles)
The mongoose Schema for Roles is :
var rolesSchema = new Schema({
nom: String,
permissions : [{
actions: String,
subject: Array,
fields: Array,
conditions: Object,
inverted: Boolean
}]
});
i retrieve user roles with :
let {roles} = await Users.findOne({name:"admin"}).populate('roles')
and do something like
const userPermissions = new Ability(roles.permissions)
I test with ability.can function like this
userPermissions.can('read', Users)
With a rule (rule store in mongodb collection named roles) like
{actions:'read',subject:'Users',conditions:{email:'[email protected]'}}
if Users (Users is a mongoose model) has email field like '[email protected]' ability.can return true, false otherwise.
Alright, perfect, but if i want store a more complicate condition, with a regex for example like
{actions:'read',subject:'Users',conditions:{email:{$regex:'^a'}}
first : i can't save in mongoose model keyname (e.g. $regex) cause of first character ($).
If i save "$regex" (with double quote, or quote) it's ok, but in this case, my ability.can check return always false.
Hope this is more comprehensible. Otherwise nevermind and thank for job and time past :)
I see. Thanks for the details :)
The issue is that CASL perceives your Users as an object and it tries to read its email field. Obviously that is a function, and it doesn't have such field. So, the quick fix to this is to replace: ability.can('read', Users) with ability.can('read', 'Users') (pay attention at quotes).
Example: https://codesandbox.io/s/88q8nn9o72
Close in favor of #187
Thanks for the issue! By the way, PRs are welcome :)
I will test this in next day but i m afraid that i have not been clear. By the way, thank for your time, very nice job on your ecosystem.
No problem. Feel free to ask questions or reopen the issue if I missed something or left something unclear :)
Apologies for reviving this one but I'm having the exact same problem as the op and am sure someone must have resolved it already.
The problem isn't with CASL (I don't think) but with how to store advanced conditions in MongoDB.
For example, if I store the following in MongoDB:
{
"subject" : "Note",
"action" : "delete",
"conditions" : {
"published" : true
}
}
I can retrieve it, update CASL, and it works perfectly.
However, if I update it to this:
{
"subject" : "Note",
"action" : "delete",
"conditions" : {
"published" : { "$in": [true, false] }
}
}
i.e. use any 'complex' condition starting with $ then MongoDB says the update has worked but it actually hasn't and the 'published' condition is back to 'true'.
So, as I said, the issue isn't strictly related to CASL but an inability to save the CASL rules in MongoDB. I'm sure someone has done this before so any help on the correct syntax is appreciated.
UPDATE: It seems if I insert a new document with that rule (using "$in") it will work exactly as expected but ecen updating it afterwards to "$in": [true] will silently fail.
Ok. Now I got what was the initial request.
Based on this https://docs.mongodb.com/manual/reference/limits/#Restrictions-on-Field-Names the best way to store conditions is to serialize them into JSON string and parse on retrieval.
So, the issue is in MongoDB itself - https://jira.mongodb.org/plugins/servlet/mobile#issue/SERVER-30575
Thanks for the quick response. I agree that the problem is in MongoDB, I had just hoped there was a "known workaround". As a workaround I had prefixed the conditions with a ~ ("~in") and replace them with $ on retrieval, before passing into CASL. As I'm only getting them on login it's not much of an overhead but your suggestion of serializing them seems equally workable.
Thanks again for your help and your great library.
Most helpful comment
Ok. Now I got what was the initial request.
Based on this https://docs.mongodb.com/manual/reference/limits/#Restrictions-on-Field-Names the best way to store conditions is to serialize them into JSON string and parse on retrieval.