Skip to content
This repository has been archived by the owner on Nov 15, 2022. It is now read-only.

Commit

Permalink
Added support for filter expressions from database paths to flashlight (
Browse files Browse the repository at this point in the history
googlearchive/flashlight#149) and added filter for invalid users
  • Loading branch information
Christian Opitz committed Mar 25, 2017
1 parent 1db090c commit 6a19b99
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 1 deletion.
137 changes: 137 additions & 0 deletions flashlight.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,143 @@ const fbrc = JSON.parse(fs.readFileSync('.firebaserc'));
}
});

// That's so ugly but as flashlight doesn't export anything ¯\_(ツ)_/¯
fs.appendFileSync('./lib/PathMonitor.js', '\n\nexports.PathMonitor = PathMonitor;');

const vm = require('vm');
require('colors');
const PathMonitor = require('./lib/PathMonitor').PathMonitor;
PathMonitor.prototype._process = function(fn, snap) {
const snVal = snap.val();
const snKey = snap.key;

if (fn === this._childRemoved) {
this._childRemoved(snKey, snVal);
if (this.filterRefs) {
const filterRefs = this.filterRefs;
Object.keys(filterRefs).forEach((path) => {
delete filterRefs[path].keys[key];
if (!Object.keys(filterRefs[path].keys).length) {
filterRefs[path].ref.off('value');
delete filterRefs[path];
}
});
}
return;
}

if (typeof this.filter === 'string') {
if (!this.filterScript) {
try {
this.filterScript = new vm.Script('RESULT = ' + this.filter, {
filename: this.ref.toString() + '/filter',
displayErrors: true
});
} catch (e) {
console.error('Error in filter expression:'.red);
console.error(e);
this.filter = () => false;
return;
}
this.filterRefs = {};
}

const filterRefs = this.filterRefs;
let load = {};
const invalidPathErrors = [];
const paths = {};
const context = vm.createContext({
ref: function (path) {
if (typeof path !== 'string' || !path) {
throw new Error('INVALID_PATH');
}
if (filterRefs[path]) {
paths[path] = true;
return filterRefs[path].val;
}
load[path] = true;
throw new Error('LOADING_REF');
},
data: snVal,
$id: snKey,
RESULT: false
});
const run = () => {
try {
this.filterScript.runInContext(context);
} catch (e) {
if (e.message === 'INVALID_PATH') {
if (invalidPathErrors.indexOf(e.toString()) < 0) {
invalidPathErrors.push(e.toString());
} else {
console.error('Invalid path at %s'.red, this.filter);
console.error(e);
return;
}
} else if (e.message !== 'LOADING_REF') {
console.error('Error at %s'.red, this.filter);
console.error(e);
return;
}
}
const promises = [];
Object.keys(load).forEach((path) => {
promises.push(new Promise((resolve, reject) => {
const ref = this.ref.root.child(path);
let initial = true;
ref.on('value', (sn) => {
if (initial) {
initial = false;
filterRefs[path] = { ref, keys: {}, val: sn.val() };
resolve();
} else {
filterRefs[path].val = sn.val();
Object.keys(filterRefs[path].keys).forEach((key) => {
this.ref.child(key).once('value', this._process.bind(
this, filterRefs[path].keys[key] ? this._childChanged : this._childAdded
));
});
}
}, (e) => {
console.error('Firebase error at %s'.red, this.filter);
console.error(e);
if (initial) {
initial = false;
reject();
}
});
}));
});
load = {};
if (promises.length) {
Promise.all(promises).then(run, () => {});
} else {
Object.keys(paths).forEach((path) => {
filterRefs[path].keys[snKey] = context.RESULT;
});
if (context.RESULT) {
fn.call(this, snKey, this.parse(snVal));
} else if (fn === this._childChanged) {
this._childRemoved(snKey, snVal);
}
}
};
run();
} else if (this.filter(snVal)) {
fn.call(this, snKey, this.parse(snVal));
}
};
PathMonitor.prototype._oldStop = PathMonitor.prototype._stop;
PathMonitor.prototype._stop = function () {
this._oldStop();
if (this.filterRefs) {
Object.keys(this.filterRefs).forEach((path) => {
this.filterRefs[path].ref.off('value');
});
this.filterRefs = {};
}
};

module.exports = {
paths: appConfig.flashlight.paths.paths || [],

Expand Down
2 changes: 1 addition & 1 deletion src/models/Config.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ const Config = {
flashlight: {
timeout: 3000,
paths: {
paths: '/flashlight/paths',
paths: '/flashlight-test',
queries: '/flashlight/queries',
results: '/flashlight/results'
}
Expand Down
1 change: 1 addition & 0 deletions src/models/Flashlight.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ module.exports = class Flashlight {
path: '/users/organizations/' + orgKey,
index: orgKey,
type: 'users',
filter: "['?', '!'].indexOf(ref('security/organizations/" + orgKey + "/users/' + $id)) < 0"
};
}
return paths;
Expand Down

0 comments on commit 6a19b99

Please sign in to comment.