Firebase Realtime Database Security Rules: need newData's child that is dynamically created and wildcard $ doesnt work - firebase-realtime-database

I only want to be able to add that user(object) to my "Entry" node if the name field exist in the "AllowedEntry" node.
-AllowedEntry
|--ABC
| |--name: "ABC"
| |--age: 20
|--LMN
| |--name: "LMN"
| |--age: 55
|--XYZ
|--name: "XYZ"
|--age: 88
-Entry
|--ABC
|--name:"ABC"
|--age:20
|--dept:"Code"
|--isAdmin:false
Over here the ABC record at Entry is possible because the name field value of ABC(ie "ABC") exists under AllowedEntry
but the below must fail
-Entry
|--PQR
|--name:"PQR"
|--age:52
|--dept:"dsfg"
|--isAdmin:true
because this PQR objects name("PQR") doesnt exist under the node of AllowedEntry
This is what I have tried from my end but been unsuccessful. the Reading permission has been set successfully... we dont need that
"Entry": {
"$id": {
".write": "root.child('AllowedEntry/'+ newData.child('$id').child('name').val() ).exists()",
}
}
The above doesnt work because a wildcard '$id' doesnt work with newData.child()
And if i do away with the '$id' we are not able to access the child node in the Json eg.
"Entry": {
".write": "root.child('AllowedEntry/'+ newData.child(**???**).child('name').val() ).exists()",
}
I wouldnt know what to enter in the ??? since the Json that comes flying into our DB looks like this
{
"ABC": {
"name": "ABC",
"age": 20,
"dept": "Code",
"isAdmin": true
}
}
You see Json with only
{
"name": "ABC",
"age": 20,
"dept": "Code",
"isAdmin": true
}
would work perfectly with ".write": "root.child('AllowedEntry/'+ newData.child('name').val() ).exists()"
but then there would be only one reord in the ENTRY node.
Adding an image to show you the outputs, the Json and the data

This fragment in your first rules snippet is wrong:
newData.child('$id').child('name')
The '$id' in there is just a literal string, rather than the value of the $id capture variable. To use the latter:
newData.child($id).child('name')
Also, there is no need for string concatenation and this is more readable:
"root.child('AllowedEntry').child(newData.child($id).child('name').val()).exists()"
In your screenshot I noticed that you:
Define the rules on the $id node,
Then use newData.child('$id').child('name').val() in your condition.
newData refers to the new data on the node where it is used. So this code now looks for a node named $id under the $id node, which exist. You probably want newData.child('name').val().

Related

How to return friendly field names for zapier trigger (zapier developers)

I am working on a Zapier integration for an online form builder. Each unique form for our users has lots of long, auto-generated field names.
We have a trigger called “New form entries”, which polls our server for form entries, and comes back like this:
[
{
"id": "6209aee326baa600224d822c",
"email_907058157108782": "test#test.com",
"phone_589083232390193": "12345",
},
{
"id": "61fd629f19408200225e1893",
"email_907058157108782": "test#test2.com",
"phone_589083232390193": "54321",
},
]
However, this results in end users seeing these really long, gross field names in the Zapier interface:
My question: how do I get Zapier to display friendly labels to the user, whilst using the unique field IDs behind the scenes?
I’m thinking of returning something like the following (each object represents a form entry, , but I need to know how to actually use “friendlyFieldName” and “value” in Zapier!-
[
{
// the id for the entry
"id": "62179ec5ab9daa0022df7d1d",
// the id for the first field entry
"text_576692390099896": {
// a friendly name and value for zapier
"friendlyFieldName": "What is your favourite colour?",
"value": "Blue"
}
}
]
Thank you :)
You can define output fields labels in outputFields. Here are the reference document that you can follow: Output Fields

Firebase Realtime Database Rules - Using a variable as a key in the data key value pair when writing

This is a rough example of what my database looks like.
"userA": {
"uf": {
"userB": "0"
}
},
"users": {
"userA": "0",
"userB": "0",
"userC": "0"
}
And this is a rough example of the rule I am trying to write.
//USER ID
"$uid": {
//USER FRIENDS
"uf": {
//FRIEND USER ID
"$fuid": {
".write": "$uid === auth.uid &&
root.child('users').hasChild($fuid)",
}
},
},
And this is what I am trying to get working in the simulator
//Location /userA/uf/
//Data { "userC": "0" }
It seems that the security rule will always deny a write when the "key" for a data key value pair is a variable in my rules, in this case "$fuid". The simulator will return the messages "Simulated set denied" and "Write denied" but won't give me any additional details. I could get around this by writing the following.
//Simulation Method set
//Location /userA/uf/userC/
//Data { "0": "0" }
But this feels like it's writing unnecessary data to my database. What is the best practice here? Thanks.
Your rules give access to {uid}/uf/{fuid} but you're trying to write at {uid}/uf.
That {"0": "0"} is indeed unnecessary, you can just write "0".
If you want to write multiple friends at once, you can perform a multipath update, or modify your rules to allow writing directly at {uid}/uf and ".validate" the children.
Side note: if your users can be deleted, if user A has user B as a friend and user B is deleted, your rules won't allow user A to remove user B from the friends list. You should take care of that by changing the rules to allow the deletion of friends that do not exist, or by setting up an onDelete() triggered cloud function that would do the cleanup.

neo4jClient create node with dynamic label using paramters

I am building an app that give users the ability to construct there own graphs. I have been using parameters for all queries and creates. But when I want to give users the ability to create a node where they can also Label it anything they want(respecting neo4j restrictions on empty string labels). How would I parameterize this type of transaction?
I tried this:
.CREATE("(a:{dynamicLabel})").WithParams(new {dynamicLabel = dlabel})...
But this yields a syntax error with neo. I am tempted to concatenate, but am worried that this may expose an injection risk to my application.
I am tempted to build up my-own class that reads the intended string and rejects any type of neo syntax, but this would limit my users a bit and I would rather not.
There is an open neo4j issue 4334, which is a feature request for adding the ability to parameterize labels during CREATE.So, this is not yet possible.
That issue contains a comment that suggests generating CREATE statements with hardcoded labels, which will work. It is, unfortunately, not as performant as using parameters (should it ever be supported in this case).
I searched like hell and finally found it out.
you can do it like that:
// create or update nodes with dynamic label from import data
WITH "file:///query.json" AS url
call apoc.load.json(url) YIELD value as u
UNWIND u.cis as ci
CALL apoc.merge.node([ ci.label ], {Id:ci.Id}, {}, {}) YIELD node
RETURN node;
The JSON looks like that:
{
"cis": [
{
"label": "Computer",
"Id": "1"
},
{
"label": "Service",
"Id": "2"
},
{
"label": "Person",
"Id": "3"
}
],
"relations": [
{
"end1Id": "1",
"Id": "4",
"end2Id": "2",
"label": "USES"
},
{
"end1Id": "3",
"Id": "5",
"end2Id": "1",
"label": "MANAGED_BY"
}
]
}
If you are using a Java client, then you can do it like this.
Node node = GraphDatabaseService.createNode();
Label label = new Label() {
#Override
public String name() {
return dynamicLabelVal;
}
};
node.addLabel(label);
You can then have a LabelCache which will avoid Label object creation for every node.

Unable to create course via api

I am trying to create a course in a semester through the api in valence d2l. I keep getting a 404 not found error, both in my program and in the "getting started" application. The call I am making is to /d2l/api/lp/1.0/courses/ using post. I pass the following JSON object along with it:
{
"Name": "COMM291 - Test A",
"Code": "C-COMM291",
"Path": "/enforced/C-COMM291/",
"CourseTemplateId": 20992,
"SemesterId": 20993,
"StartDate": "2013-08-22T19:41:14.0983532Z",
"EndDate": "2013-08-27T19:41:14.0993532Z",
"LocaleId": 4105,
"ForceLocale": false,
"ShowAddressBook": false
}
I have also tried passing null for the fields that say they accept null values, but no luck. The course template and the semester ID are correct - I have tripled checked that they exist, I am enrolled in them and I am using the correct ID numbers.
Try reducing the precision in your start and end dates to three decimals after the final point (e.g., "2013-08-22T19:41:14.0983532Z" becomes "2013-08-22T19:41:14.098Z").
If your org is configured to automatically enforce, and generate, paths for course offerings, then you should not provide one in your CreateCourseOffering block at all. The following structure works on our test instance: notice the empty string for path (shouldn't be null, but an empty string, I believe):
{ "Name": "Extensibility 104",
"Code": "EXT-104",
"Path": "",
"CourseTemplateId": 8082,
"SemesterId": 6984,
"StartDate": "2013-09-01T19:41:14.098Z",
"EndDate": "2013-12-27T19:41:14.098Z",
"LocaleId": 1,
"ForceLocale": false,
"ShowAddressBook": false }
The other thing to note is that if your CreateCourse form doesn't have a form element to provide a Semester ID, then your API call should pass null for that property.
I found that part of my problem was with the call if I change it to /d2l/api/lp/1.3/courses/ instead of 1.0 it works, (1.0 will work but it seems that you can only pass null for the semester).
The dates were also picky and did prefer milliseconds to only 3 decimal places.
Then passing null for LocaleId also helped.

Returning a custom field where value depends on the query in elasticsearch

I have some data like so in elasticsearch:
account (http://localhost:9200/myapp/account/1)
========
name
state
groups //groups is an array containing objects like so {id: 1, starred: true}
//the id is the id of the group type
email (http://localhost:9200/myapp/email/1?parent=1)
========
email
primary //just a boolean to denote whether this email is primary or not
group
========
name
description
emails are children of account.
Based on imotov's excellent answer, I am able to run a search on account.name and email.email and return ALL accounts where the searched prefix matches the above 2 fields:
{
"query": {
"bool": {
"must": [
{
"term": {
"statuses": "active"
}
}
],
"should": [
{
"prefix": {
"name": "a"
}
},
{
"has_child": {
"type": "email",
"query": {
"prefix": {
"email": "a"
}
}
}
}
],
"minimum_number_should_match" : 1
}
}
}
What I would like to do now is to return 2 custom fields for each result:
For each result return a field called email, if the search was matched on the email type (which is a child of account), return that email, otherwise return the primary email linked to the account, if none, null can be returned.
For each result return a field called group. The value of the field should contain the name of the starred group whose id is stored in the groups array. Essentially: Find group.id where group.starred is true in each account.groups, then return the matching group.name from the group type base on the id we found.
I have been looking at script fields, but I am not sure if it is able to return fields for each hit. I am also not sure if the above is actually accomplishable in ES.
Could someone provide some pointers as to whether this is possible and how to get started?
Currently, there is simply no way to get to access the data in a has_child or nested clause.
The only solution is to get some data, make some decisions on the client and then get more data.
Here's what I did to achieve it:
Run the query above and get back the data.
To deal with showing the match emails or the primary email (run on the email type):
{"query":
{"bool":{
"should":{
{
"prefix":{
"email" : "the query"
}
},
{
"terms":{
"_parent" : ["list", "of", "account", "ids"]
}
}
}
}
}
}
Base on the above query, we can get any email addresses that were matched by the search term. Remember to set the fields in the above query to include _parent.
We can then use array_diff() or a similiar function in languages other than PHP to diff the parent ids from above and and original query. This should then give us a list of accounts where no email was matched. Simply then send another request to get the primary emails for those accounts.
For the groups, send a query to type account and:
Constrain _id to the list of account ids.
Constrain group.starred to true.
This should get you a list of starred groups. To get more information (name etc), send a query to type group and:
Constrain _id to the group ids above.
Finally, do some client side processing to put it together so that it is easier for the next part of your program to use.

Resources