Firebase Firestore rules path in production - firebase

Following the docs, I tried to debug the path
When I'm using the emulator locally, the path is like /databases/$(database)/documents/col1/doc1/col2/doc2/...
so this resource['__name__'][0] will be databases
and resource['__name__'][4] will be doc1
for example, this test function will return true (locally, using the emulator):
function test() {
return string(resource['__name__'][4]).matches('doc1');
}
Or:
function test() {
return string(resource['__name__'][0]).matches('databases');
}
But, when I deploy the rules, the test function becomes false.
Is it because the path in production is different? If so, how can I see it? is there any example for a production path..

Related

Edge browser Native File System removeEntry use

I'm working with the newest version of Edge (Canary release 86.0.615.0) and I can get the new Native File System API showOpenFilePicker to let me access files but I can't find a reference to the directoryHandle functions including the removeEntry function if the user elects to remove the file. Am I missing a special flag? I have an Origin-Tracker code and I also have the experimental flag set for the Native File System API.
If you have a directory handle, you can delete files or folders as in the example below:
// Delete a file.
await directoryHandle.removeEntry('Abandoned Projects.txt');
// Recursively delete a folder.
await directoryHandle.removeEntry('Old Stuff', { recursive: true });
You can obtain a directory handle from the picker:
const directoryHandle = await window.showDirectoryPicker();
To iterate over the entries of a directory, you can use the code snippet below:
for await (const entry of directoryHandle.values()) {
console.log(entry.kind, entry.name);
}

Getting TestCafe to recognize dotenv variables

I might be mixing up concepts, but I'd read that it's possible to get TestCafe to recognize variables of the form process.env.MY_COOL_VARIABLE. Also for my Vue.js frontend (built using Vue-CLI, which uses dotenv under the hood), I found I could make a file in .env.test for test values like so:
VUE_APP_MY_COOL_VARIABLE
which I would then access in my test code like so:
test('my fixture', async (t) => {
...
await t
.click(mySelector.find('.div').withText(process.env.VUE_APP_MY_COOL_VARIABLE));
...
}
However, I get the following error:
"text" argument is expected to be a string or a regular expression, but it was undefined.
Seems like my environment variables aren't getting picked up. I build my code like so: vue-cli-service build --mode test.
TestCafe doesn't provide support for .env files out of the box. You can create a test file that will require the dotenv module and load your configuration file:
// enable-dotenv.test.js
require('dotenv').config({ path: '.my.env' });
testcafe chrome enable-dotenv.test.js tests/
Here's how I solved my issue. When debugging, I did a console.log of process.env and noticed that the variable that vue recognizes wasn't visible during testcafe's run. From our package.json:
"test:ui:run": "VUE_APP_MY_COOL_VARIABLE=ui-test yarn build:test && testcafe -a ../ui-test-server.sh chrome",
Also this bit of javascript is run by both the test and mainline code, so I had to use a conditional.
import * as dotenv from 'dotenv';
if (process.env.npm_package_scripts_test_ui_run) { // are we running a testcafe script
dotenv.config({ path: '.env.test' });
}
Have you tried process.env[VUE_APP_MY_COOL_VARIABLE]? It's worth noting that everything in dotenv comes back as a string so you may need to do the casting yourself. For example:
function getEnvVariableValue(envVariable: string) {
// Cast to boolean
if (envVariableValue.toUpperCase() === "TRUE") {
return true;
} else if (envVariableValue.toUpperCase() === "FALSE") {
return false;
// Cast to number
} else if (!isNaN(Number(envVariableValue))) {
return Number(envVariableValue);
} else {
return envVariableValue;
}
}
You can also try creating a .env file in the root folder to see if it picks it that way. I use dotenv in my project directly by including it in the package.json as a dependency and it works this way.

Firebase Cloud Function .onWrite always logs null or undefined

I'm at a loss about why this won't log anything but "null" or "undefined" to the console. I'm testing this from the Google Cloud Platform testing browser interface. I've also tried logging EVENT (instead of CHANGE and CONTEXT) with the same result. I have also tried opening the security rules, but that also didn't help. Any advice is highly appreciated.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.fanOutLink = functions.database.ref('/userLink/BLAH584H5BLAH30BLA/link').onWrite((change, context) => {
console.log('value is:'+change.before.val());
});
And here is the JSON I'm using to test the code above:
{
"userLink": {
"BLAH584H5BLAH30BLA": {
"link": "https://blabla.com"
}
}
}
A Cloud Function must always return a Promise (or if you cannot, at least a value).
Your function should work as is but with a delay and an error in the log like "Function returned undefined, expected Promise or value". It may happen that the Cloud Functions instance running your function shuts down before your function successfully write the message in the log.
If you change your code as follow you will get a (quasi) instant reply:
exports.fanOutLink = functions.database.ref('/userLink/BLAH584H5BLAH30BLA/link').onWrite((change, context) => {
console.log('value is:'+change.before.val());
return true;
});
I would suggest you have a look at those 2 videos from the Firebase team: https://www.youtube.com/watch?v=7IkUgCLr5oA&t=511s and https://www.youtube.com/watch?v=652XeeKNHSk&t=37s
Following our "discussion" in the comments below, it appears that you use the new Cloud Functions syntax but with an old version of the library. Look at this documentation item: https://firebase.google.com/docs/functions/beta-v1-diff, and do as indicated, before redeploying:
Run the following in the functions folder:
npm install firebase-functions#latest --save
npm installfirebase-admin#5.11.0 --save

RequireJs Google maps google is not define

I have a simple nodejs project that should load asynchronously the google maps api javascript, i followed this answer https://stackoverflow.com/a/15796543
and my app.js is like this:
var express = require("express"),
app = express(),
bodyParser = require("body-parser"),
methodOverride = require("method-override");
https = require("https");
requirejs = require('requirejs');
requirejs.config({
waitSeconds : 500,
isBuild: true,
paths : {
'async': 'node_modules/requirejs-plugins/src/async',
}
});
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(methodOverride());
var router = express.Router();
router.get('/', function(req, res) {
res.send("Hello World!");
});
requirejs(["async!http://maps.google.com/maps/api/js?key=mykey&sensor=false"], function() {
console.log(google);
});
app.listen(3000, function() {
console.log("asd");
});
package.json:
{
"name": "rest-google-maps-api",
"version": "2.0.0",
"dependencies": {
"express": "^4.7.1",
"method-override": "^2.1.2",
"body-parser": "^1.5.1",
"requirejs": "2.3.3",
"requirejs-plugins": "1.0.2"
}
}
i've got always the same error:
ReferenceError: google is not defined
The main issue here is that you are trying to run in Node code that is really meant to be used in a browser.
The async plugin
This plugin needs to be able to add script elements to document and needs window. I see you set isBuild: true in your RequireJS configuration. It does silence the error that async immediately raises if you do not use this flag, but this is not a solution because:
isBuild is really meant to be set internally by RequireJS's optimizer (or any optimizer that is compatible with RequireJS), not manually like you are doing.
isBuild means to indicate to plugins that they are running as part of an optimization run. However, your code is using the plugin at run time rather than as part of an optimization. So setting isBuild: true is a lie and will result in undesirable behavior. The async plugin is written in such a way that it effectively does nothing if isBuild is true. Other plugins may crash.
Google's Map API
It also expects a browser environment. The very first line I see when I download its code is this:
window.google = window.google || {};
Later in the code there are references to window.document and window.postMessage.
I don't know if it is possible to run the code you've been trying to load from Google in Node. I suspect you'd most likely need something like jsdom to provide a browser-like environment to the API.
assuming you did everything else correctly, which I am not testing here. The reason you are getting the error is because you call console.log(google) and there is no google variable. You need to pass google in as a reference in your call back function. This will either get rid of the error, or change the error if you have set up requirejs incorrectly.
requirejs(["async!http://maps.google.com/maps/api/js?key=mykey&sensor=false"],
function( **google** ) {
console.log(google);
});
see the requirejs docs http://requirejs.org/docs/node.html#1

How to change ip to current url from subject in reset password email meteor

I have used the following code to set my reset email subject:
Accounts.emailTemplates.resetPassword.subject = function(user, url) {
var ul = Meteor.absoluteUrl();
var myArray = ul.split("//");
var array = myArray[1].split('/');
return "How to reset your password on "+array[0];
};
I want it to contain the current browser's url, but it's not happening.
This is what the subject looks like
How to reset your password on 139.59.9.214
but the desired outcome is:
How to reset your password on someName.com
where someName.com is my URL.
I would recommend handling this a bit differently. Your host name is tied to your environment, and depending on what your production environment looks like, deriving your hostname from the server might not always be the easiest thing to do (especially if you're behind proxies, load balancers, etc.). You could instead look into leveraging Meteor's Meteor.settings functionality, and create a settings file for each environment with a matching hostname setting. For example:
1) Create a settings_local.json file with the following contents:
{
"private": {
"hostname": "localhost:3000"
}
}
2) Create a settings.json file with the following contents:
{
"private": {
"hostname": "somename.com"
}
}
3) Adjust your code to look like:
Accounts.emailTemplates.resetPassword.subject = function (user, url) {
const hostname = Meteor.settings.private.hostname;
return `How to reset your password on ${hostname}`;
};
4) When working locally, start meteor like:
meteor --settings=settings_local.json
5) When deploying to production, make sure the contents or your settings.json file are taken into consideration. How you do this depends on how you're deploying to your prod environment. If using mup for example, it will automatically look for a settings.json to use in production. MDG's Galaxy will do the same.

Resources