drools rule to relate two facts without eval - drools

So I'm still relatively new to drools. I know how to use eval to compare facts, but I'm under the impression I should be able to write the rules without the eval statement. I was hoping to get some help understanding how I would do so in the following situation?
I have a fact that a supervisor is being requested for a given user's email address:
declare SupervisorRequested
email : String
end
and a map from users to their supervisor (potentially -- some users have no supervisors)
// Map<String, User>
knowledgeResources.add(supervisors);
And so the rule I have written is
rule "Supervisor Inclusion Requested"
when
request : SupervisorRequested()
supervisors : Map()
eval(supervisors.get(request.email) != null)
then
...
end
So, the question is, how could I write this without resorting to using eval?

The below rule will fire for all instances where the map (assumed to be in working memory) contains a user mapped to the email and will not fire if $supervisors.get($email) returns null. One of the biggest conveniences of working with Drools in MVEL is that we should rarely have to do null checks.
rule "Supervisor Inclusion Requested"
when
$request : SupervisorRequested($email: email)
$supervisors: Map()
$supervisorWithEmail : User() from $supervisors.get($email)
then
...
end
Hope that helps, cheers.

Try the below rule to get the desired condition check :
rule "Supervisor Inclusion Requested"
when
request : SupervisorRequested()
map : HashMap(this.get(request.getEmail()) != null)
then
// .............
end

You can actually use the this syntax since it's an alias for get(...). For example: Map( $value: this["foo"]) is functionally the same as $value = map.get("foo").
Keeping that in mind, you can write your rule like:
rule "Supervisor Inclusion Requested"
when
SupervisorRequested( $email: email ) // gets the email
Map( this[$email] != null ) // checks that the map contains the email
then
// omitted
end

Related

can't read path variable in firestore rules

I have some rules like:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /teams/{teamId} {
allow read, write, delete, list:
if debug(teamId) in debug(request.auth.token.teams)
allow create:
if true;
}
}
}
I am using claims to control access. Each user has an array of teams in their token. That part is working fine.
Basically, teamId (coming from the path) doesn't exist. Nothing is printed in the log for this variable. I can't figure out whats going on. Is there some different way to access that teamId variable?
by doing some logs, it seems that for accessing /teams/teamXXXX I'm getting multiple rule hits. First on /database/default/documents/teams and then again on /database/default/documents/teams/teamXXX The first rule pass is failing because {teamId} is not defined on that path. I need to somehow allow access to the collection while limiting access to the child documents
It looks like the way I'm accessing teams may be causing a problem. I'm getting teams by doing a query like:
instance.collection("teams").where('owners',
arrayContains: FirebaseAuth.instance.currentUser!.uid);
This must be triggering the rule check where no {teamId} in the path. I thought about wrapping my match statement like:
match /teams/{document=**}
allow read:
if (request.auth.uid != "")
match /teams/{teamId} {
allow read, write, delete, list:
if debug(teamId) in debug(request.auth.token.teams)
allow create:
if true;
}
}
I'm worried that this will just allow all documents. I'm stuck.
answering my own question.
When doing a search / list on a collection, it still matches the rule of /teams/{teamId} even though you are not specifically querying by teamId.
Meaning a search like instance.collections("teams").where(...) will still match /teams/{teamId}
In the match, {teamId} will be blank. Instead, you must look at the input paramters coming in via the "resource" variable. The items you have in the "where" clauses will appear in the resource variable. You must use the resource data to resolve your rules.
So I had to separate the "list" rule form the rest of the rules.

Dialogflow CX: Is it possible to verify the value of an intent param in the condition section of the page?

I would like to use Conditions to dispatch the conversation through different Routes depending on the intent entity that appeared in the last user's message:
But it only enables me to use the condition $intent.params.entityX != null; when I try to extract the exact value of that entity like: $intent.params.entityX = "some_value" it does not match. I have also try $intent.params.entityX.original and $intent.params.entityX.resolved. It seems that the intent param values can apparently only be read in the Route response.
If what you're looking for is to evaluate a parameter that may have been filled through entity detection, you may wanna check in session rather than the intent:
$session.params.entityX

regex check and proceed next call

Iam new to gatling and scala.
I was trying to validate regex in galting-scala.
My scenario.
from the response capture (regex) X values, If available then execute step-ABC
If X value of component not found, ignore step_ABC
Your example uses .exists, which asserts that the regex must be matched and returns a boolean, not the value of the match. So the "logoId" session variable will always get set, but won't have any data useful for making a subsequent request. Additionally, since the logo is optional in your case, you don't want the scenario failing if it isn't there.
Optional checks and the gatling EL support your use-case.
.exec(
http("get merchant")
.get("some url")
.check(
regex(""""logoId":(.+?),""").optional.saveAs("logoId")
)
.doIf("${logoId.exists()}") {
exec(...)
}

Play Framework - how to bind form to a session field

Is there a way I can get some parameters from headers, say cookie (in my case logged in userId), and then apply it to a form so I know who is submitting the ticket?
SupportForm
supportForm:Form[SupportTicket] = Form(mapping(
"question" -> text,
"Priority" -> text
)(SupportTicket.Apply)(SupportTicket.Unapply)
What are the good practises here?
Is request present as an implicit when the call to Apply is made so that I can use it (and is this even a good practise?)
EDIT: One of the issues, ofcourse is someone spoofing if I were to create a hidden field with this value. I could encrypt, but the issue again is to somehow verify and return the form, not sure how this can be done....

Routing based on query parameter in Play framework

My web application will be triggered from an external system. It will call one request path of my app, but uses different query parameters for different kinds of requests.
One of the parameters is the "action" that defines what is to be done. The rest of the params depend on the "action".
So I can get request params like these:
action=sayHello&user=Joe
action=newUser&name=Joe&address=xxx
action=resetPassword
...
I would like to be able to encode it similarly in the routes file for play so it does the query param based routing and as much of the validation of other parameters as possible.
What I have instead is one routing for all of these possibilities with plenty of optional parameters. The action processing it starts with a big pattern match to do dispatch and parameter validation.
Googling and checking SO just popped up plenty of samples where the params are encoded in the request path somehow, so multiple paths are routed to the same action, but I would like the opposite: one path routed to different actions.
One of my colleagues said we could have one "dispatcher" action that would just redirect based on the "action" parameter. It would be a bit more structured then the current solution, but it would not eliminate the long list of optional parameters which should be selectively passed to the next action, so I hope one knows an even better solution :-)
BTW the external system that calls my app is developed by another company and I have no influence on this design, so it's not an option to change the way how my app is triggered.
The single dispatcher action is probably the way to go, and you don't need to specify all of your optional parameters in the route. If action is always there then that's the only one you really need.
GET /someRoute controller.dispatcher(action: String)
Then in your action method you can access request.queryString to get any of the other optional parameters.
Note: I am NOT experienced Scala developer, so maybe presented snippets can be optimized... What's important for you they are valid and working.
So...
You don't need to declare every optional param in the routes file. It is great shortcut for type param's validation and best choice would be convince 'other company' to use API prepared by you... Anyway if you haven't such possibility you can also handle their requests as required.
In general: the dispatcher approach seems to be right in this place, fortunately you don't need to declare all optional params in the routes and pass it between actions/methods as they can be fetched directly from request. In PHP it can be compared to $_GET['action'] and in Java version of Play 2 controller - DynamicForm class - form().bindFromRequest.get("action").
Let's say that you have a route:
GET /dispatcher controllers.Application.dispatcher
In that case your dispatcher action (and additional methods) can look like:
def dispatcher = Action { implicit request =>
request.queryString.get("action").flatMap(_.headOption).getOrElse("invalid") match {
case "sayHello" => sayHelloMethod
case "newUser" => newUserMethod
case _ => BadRequest("Action not allowed!")
}
}
// http://localhost:9000/dispatcher?action=sayHello&name=John
def sayHelloMethod(implicit request: RequestHeader) = {
val name = request.queryString.get("name").flatMap(_.headOption).getOrElse("")
Ok("Hello " + name )
}
// http://localhost:9000/dispatcher?action=newUser&name=John+Doe&address=john#doe.com
def newUserMethod(implicit request: RequestHeader) = {
val name = request.queryString.get("name").flatMap(_.headOption).getOrElse("")
val address = request.queryString.get("address").flatMap(_.headOption).getOrElse("")
Ok("We are creating new user " + name + " with address " + address)
}
Of course you will need to validate incoming types and values 'manually', especially when actions will be operating on the DataBase, anyway biggest part of your problem you have resolved now.