How do i restrict the user without passing the middleware - node.js

const restricted = async (x, myID) => {
try {
const i = x.posts.forEach((a, b, c, d) => {
let lol = x.PrivacySettings.restricted.some(x => { return x; })
let lole = a.comments.some(x => { return x; }).postedBy;
if (lol === lole && myID !== lol || a.postBy) {
const FU = a.comments.filter((a, b, c, d) => {
return a.postedBy === lol;
});
return FU;
} else {
return;
}
});
return i;
} catch (ex) {
console.log(ex.message);
res.status(200).json('something went wrong');
}
}
So i have this function above, now how do i check if the user is restricted or not?
i have to implement this function in all the comment routes so how can i do it other than
making it a middleware

Related

How can I compare data from two maps

I tried comparing data from each table from my data base but i failed
I'm not too familiar with react, I'm still working on it, I'm trying to compare the data from recommendation and customization and if they are the same I display them.
const getRecommendation = () => {
Axios.get("http://localhost:5000/recommendations").then((response) => {
setRecomList(response.data);
});
};
const getCostumization = () => {
Axios.get("http://localhost:5000/customizations").then((response) => {
setCustomList(response.data);
});
};
const getRecById = async (id) => {
Axios.get(`http://localhost:5000/recommendations/${id}`).then((res) => {
setRecById(
recById.filter((val) => {
return val._id === id;
})
);
});
};
useEffect(() => {
{
recommendation.map((rec, i) => {
customization.map((cus, j) => {
if (
rec.type === cus.type &&
rec.violonBody === cus.violonBody &&
rec.violonStick === cus.violonStick &&
rec.violonChincrest === cus.violonChincrest
) {
getCostumization();
}
});
});
}
});
Thank you!
You can use like below
const compare = (obj1, obj2) => {
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length) return false;
return keys1.every((key) => obj1[key] === obj2[key]);
};
console.log(compare({ a: 1, b: 2 }, { a: 1, b: 2}));
console.log(compare({ a: 1, b: 2 }, { a: 1, b: 2, c:3 }));
Comparing objects & array is not an easy task to do by ourselves since it involves doing deep comparison.
One of the popular and convenient way is to use the _.isEqual from the lodash library.
You could use it like this:
var object = { 'a': 1 };
var other = { 'a': 1 };
_.isEqual(object, other);
// => true
object === other;
// => false
Could you do something like this? This should return an array of objects that are found in both arrays:
function compareArrays(arr1, arr2) {
const same = [];
for (const i = 0; i < arr1.length; i++) {
for (const j = 0; j < arr2.length; j++) {
if (arr1[i].name === arr2[j].name) {
same.push(arr1[i]);
}
}
}
return same;
}
So using your example it would look like this:
const getRecommendation = () => {
Axios.get("http://localhost:5000/recommendations").then((response) => {
setRecomList(response.data);
});
};
const getCostumization = () => {
Axios.get("http://localhost:5000/customizations").then((response) => {
setCustomList(response.data);
});
};
const getRecById = async (id) => {
Axios.get(`http://localhost:5000/recommendations/${id}`).then((res) => {
setRecById(
recById.filter((val) => {
return val._id === id;
})
);
});
};
useEffect(() => {
const equalPairArray = compareArrays(recommendation, customization)
if(equalPairArray.length > 0){
getCostumization();
}
});

Detect cycle in directed Graph

Recently had to detect recursions in a directed graph in code logic. My nodejs implementation feels complex and I am now wondering:
Are there any problems with the code?
Can we simplify it / make it more readable?
const checkCyclic = (graph) => {
const nodes = new Set(Object.keys(graph));
const searchCycle = (trace, node) => {
const cycleStartIdx = trace.indexOf(node);
if (cycleStartIdx !== -1) {
throw new Error(`Cycle detected: ${trace
.slice(cycleStartIdx).concat(node).join(' <- ')}`);
}
if (nodes.delete(node) === true) {
const nextTrace = trace.concat(node);
graph[node].forEach((nextNode) => searchCycle(nextTrace, nextNode));
}
};
while (nodes.size !== 0) {
searchCycle([], nodes.values().next().value);
}
};
checkCyclic({
p1: ['p3'],
p2: ['p1'],
p3: ['p2']
});
// => Recursion detected: p1 <- p3 <- p2 <- p1
checkCyclic({
p0: ['p1'],
p1: ['p3'],
p2: ['p1'],
p3: ['p2']
});
// => Recursion detected: p1 <- p3 <- p2 <- p1
checkCyclic({
p0: ['p0']
});
// => Cycle detected: p0 <- p0
For the curious, this is being used in promise-pool-ext, which also contains tests.
Thank you very much for your feedback!
Edit: Played around and did the iterative implementation (looks even uglier!)
module.exports = (G) => {
const pending = new Set(Object.keys(G));
while (pending.size !== 0) {
const trace = [pending.values().next().value];
const parentIdx = [0];
pending.delete(trace[0]);
while (trace.length !== 0) {
const c = trace.length - 1;
const parent = G[trace[c]][parentIdx[c]];
if (parent !== undefined) {
if (trace.includes(parent)) {
throw new Error(`Cycle detected: ${trace
.slice(trace.indexOf(parent)).concat(parent).join(' <- ')}`);
}
parentIdx[c] += 1;
if (pending.delete(parent)) {
trace.push(parent);
parentIdx.push(0);
}
} else {
trace.pop();
parentIdx.pop();
}
}
}
};
I usually prefer iterative to recursive, but in this case it might not worth the readability trade-off. Any idea how to improve this implementation?
We may shorten it a bit:
function getCycle (G, n, path) {
if (path.includes(n)) {
throw `cycle ${path.slice(path.indexOf(n)).concat(n).join('<-')}`
}
path.push(n)
return G[n].forEach(next => getCycle(G, next, path.slice(0)))
}
function validate (G) {
Object.keys(G).forEach(n => getCycle(G, n, []))
}
validate({
p1:['p2','p3','p4'],
p2:['p3'],
p3:['p0'],
p0:[],
p4:[]
})
console.log('ok')
validate({
p1:['p2','p3','p4'],
p2:['p3'],
p3:['p0'],
p0:[],
p4:['p1']
})
Now this is not the most efficient since we:
find on path which is an array and not a set (idem O(k) instead of O(1))
do revisit vertices even though they have already been visited
Below a slightly more optimized version at the sake of readability?
function getCycle (G, n, path, visited) {
if (path.has(n)) {
const v = [...path]
throw `cycle ${v.slice(v.indexOf(n)).concat(n).join('<-')}`
}
visited.add(n)
path.add(n)
return G[n].forEach(next => getCycle(G, next, new Set(path), visited))
}
function validate (G) {
const visited = new Set()
Object.keys(G).forEach(n => {
if (visited.has(n)) return
getCycle(G, n, new Set(), visited)
})
}
validate({
p1:['p2','p3','p4'],
p2:['p3'],
p3:['p0'],
p0:[],
p4:[]
})
console.log('ok')
validate({
p1:['p2','p3','p4'],
p2:['p3'],
p3:['p0'],
p0:[],
p4:['p1']
})
Regarding perfs, I have (cheaply) tried to reproduce and compare algos on the same graph G (generated by random-dag) with 50 nodes.
They seem to be equivalent.
function checkCyclic (G) {
const pending = new Set(Object.keys(G));
while (pending.size !== 0) {
const trace = [pending.values().next().value];
const parentIdx = [0];
pending.delete(trace[0]);
while (trace.length !== 0) {
const lastIdx = trace.length - 1;
const parent = G[trace[lastIdx]][parentIdx[lastIdx]];
if (parent === undefined) {
trace.pop();
parentIdx.pop();
} else {
if (trace.includes(parent)) {
throw new Error(`cycle ${trace
.slice(trace.indexOf(parent)).concat(parent).join('<-')}`);
}
parentIdx[lastIdx] += 1;
if (pending.delete(parent)) {
trace.push(parent);
parentIdx.push(0);
}
}
}
}
};
function grodzi1(G) {
function getCycle (G, n, path) {
if (path.includes(n)) {
throw `cycle ${path.slice(path.indexOf(n)).concat(n).join('<-')}`
}
path.push(n)
return G[n].forEach(next => getCycle(G, next, path.slice(0)))
}
Object.keys(G).forEach(n => getCycle(G, n, []))
}
function grodzi2(G) {
function getCycle (G, n, path, visited) {
if (path.has(n)) {
const v = [...path]
throw `cycle ${v.slice(v.indexOf(n)).concat(n).join('<-')}`
}
visited.add(n)
path.add(n)
return G[n].forEach(next => getCycle(G, next, new Set(path), visited))
}
const visited = new Set()
Object.keys(G).forEach(n => {
if (visited.has(n)) return
getCycle(G, n, new Set(), visited)
})
}
// avoid copying the set
function grodziNoCopy(G) {
function getCycle (G, n, path, visited) {
if (path.has(n)) {
const v = [...path]
throw `cycle ${v.slice(v.indexOf(n)).concat(n).join('<-')}`
}
visited.add(n)
path.add(n)
return G[n].forEach(next => {
getCycle(G, next, path, visited)
path.delete(next)
})
}
const visited = new Set()
Object.keys(G).forEach(n => {
if (visited.has(n)) return
getCycle(G, n, new Set(), visited)
})
}
// avoid visiting the already visited set of nodes
function grodziStopVisit(G) {
function getCycle (G, n, path, visited) {
if (path.has(n)) {
const v = [...path]
throw `cycle ${v.slice(v.indexOf(n)).concat(n).join('<-')}`
}
if (visited.has(n)) return
visited.add(n)
path.add(n)
return G[n].forEach(next => {
getCycle(G, next, path, visited)
path.delete(next)
})
}
const visited = new Set()
Object.keys(G).forEach(n => {
if (visited.has(n)) return
getCycle(G, n, new Set(), visited)
})
}
// same but iterative
function grodziIter(G) {
function dfs (G, n, visited) {
let stack = [{ path: [], n }]
let x
while (x = stack.pop()) {
const {n, path} = x
if (path.includes(n)) {
const v = [...path]
throw `cycle ${v.slice(v.indexOf(n)).concat(n).join('<-')}`
}
if (visited.has(n)) continue
visited.add(n)
path.push(n)
G[n].forEach(next => stack.push({ path: path.slice(0), n: next }))
}
}
const visited = new Set()
Object.keys(G).forEach(n => visited.has(n) || dfs(G, n, visited))
}
const G = {"0":["5","6","12","15","18","30","31","32","33","35","39","41","52","54"],"1":["12","17","29","30","34","35","38","39","40","43","53"],"2":["5","7","12","13","14","15","16","19","21","31","35","36","37","40","41","53"],"3":["14","16","15","30","32","40","52","55"],"4":["5","6","13","15","17","18","32","35","40","41","42","51"],"5":["16","15","30","33","52","53","55"],"6":["11","16","18","33","36","37","42","51","53"],"7":["14","15","16","22","30","33","35","36","39","41","43","49","53","54","55"],"8":["31","36","41","51"],"9":["18","30","36","37","39","40","50","52"],"10":["15","17","18","19","31","32","33","35","37","40","41","48","54","55"],"11":["15","17","19","31","32","35","38","41","40","43","48","52"],"12":["17","21","32","33","35","52","54","55"],"13":["18","19","20","29","33","35","36","38","41","43","52"],"14":["16","17","19","35","39","55"],"15":["20","22","30","33","35","38","39","41","42","43","49","50","54"],"16":["20","32","34","36","37","39","40","42","44","53"],"17":["28","31","36","35","38","41","43","44","48"],"18":["19","31","34","36","35","38","41","49","52","53","55"],"19":["29","36","48","51"],"20":["29","32","33","36","37","49"],"21":["30","31","33","34","35","36","39","48"],"22":["30","31","32","34","36","37","41","43","48"],"23":["33","34","35","36","37","40","44","50"],"24":["28","34","35","36","38","41","42","48","52"],"25":["28","29","31","32","36","41","43","53"],"26":["29","35","37","38","39","41","43","50"],"27":["31","35","36","37","41","42","48","51","53"],"28":["35","37","38","40","41","50","55"],"29":["38","39","40","42","44","51","54"],"30":["37","38","40","41","42","43","49","50","53"],"31":["36","39","40","50","52","54"],"32":["37","38","39","41","44","48","49","52","55"],"33":["41","40","42","44","52","53"],"34":["35","36","41","42","49","52","54"],"35":["44","55"],"36":["41","50","52","53","54"],"37":["52","55"],"38":["55"],"39":["40","41","51"],"40":["48","49","52"],"41":["49","52","53"],"42":["53"],"43":["48","50","52","55"],"44":["48","52","54"],"45":["49","53","54"],"46":["49","50","52"],"47":["48","50","52","53","55"],"48":[],"49":[],"50":[],"51":[],"52":[],"53":[],"54":[],"55":[]}
function bench (fn, label) {
console.time(label)
for (let idx = 0; idx < 50; idx += 1) { fn(G) }
console.timeEnd(label)
}
function shouldThrow (...fns) {
const cyc = {"p1":["p2","p3","p4"],"p2":["p3"],"p3":["p0"],"p0":[],"p4":["p1"]}
fns.forEach(fn => {
let ok = false
try { fn(cyc) } catch (e) {
ok = e.toString().includes('cycle p1<-p4<-p1')
if(!ok){
throw new Error('failzed ', e)
}
}
if (!ok){ throw 'should have thrown' }
})
}
shouldThrow(checkCyclic, grodzi1, grodzi2, grodziNoCopy, grodziStopVisit, grodziIter)
for(let i = 0; i < 3; ++i) {
bench(checkCyclic, 'cyclic')
bench(grodzi1, 'grodzi1')
bench(grodzi2, 'grodzi2')
bench(grodziNoCopy, 'grodziNoCopy')
bench(grodziStopVisit, 'grodziStopVisit')
bench(grodziIter, 'grodziIter')
console.log('next')
}

Is it possible to bind this in bluebird map?

So I've tried to write up an example as best I could of what I'm trying to do, this isn't a very practical example but I tried to simplify it, but I feel like I may have complicated this in trying to make an example.
class add {
constructor(baseValue) {
this.base = baseValue;
return new Promise((resolve, reject) => {
resolve(this);
});
}
addBase(num) {
return new Promise((resolve, reject) => {
resolve(this.base + num);
});
}
}
const values = [1,2,3,4,5];
Promise.try(() => {
return new add(5);
}).then((add) => {
// we want to find if a 5 exists in the results
const addPromise = Promise.resolve(values).map(add.addBase, {concurrency: 1});
return Promise.try(() => {
return addPromise;
}).then((results) => {
for(let i = 0; i < results.length; i++) {
if(results[i] === 10) {
return i;
}
}
// doesn't exist
return null;
});
}).then((result) => {
if(result === null) {
console.log('10 does not exist');
} else {
console.log('10 is at position ' + result);
}
})
<script src="https://cdn.jsdelivr.net/bluebird/latest/bluebird.min.js"></script>
If you run this you'll get an error that you can't get base of undefined, this is because of the mapping in bluebird. const addPromise = Promise.resolve(values).map(add.addBase, {concurrency: 1}); Is there a way on this line to bind the add object to this when making these calls?
This is actually a little simpler than you're making it I think. You are passing the raw function into map(), but you should probably be passing an arrow function instead. Consider this simple class and code that tries to use map() by passing add():
class Test{
constructor(n) {
this.n = n
}
add(k) {
return this.n + k
}
}
let t = new Test(10)
let arr = [1, 2, 3]
// error TypeError: undefined is not an object (evaluating 'this.n')
arr.map(t.add)
This throws an error because map isn't calling add() from the object, it just thinks it's a function. An easy fix is to call map like this:
class Test {
constructor(n) {
this.n = n
}
add(k) {
return this.n + k
}
}
let t = new Test(10)
let arr = [1, 2, 3]
let mapped = arr.map((n) => t.add(n))
console.log(mapped)
You could also use:
let mapped = arr.map(t.add.bind(t))
but to me that's harder to read and understand quickly. I'm not sure what's going on with all the immediately resolved promises in your code, but changing the way you call map() makes that error go away. (there's another error later where you reference i that's not in scope.)
You've pretty much answered your own question…
class add {
constructor(baseValue) {
this.base = baseValue;
return new Promise((resolve, reject) => {
resolve(this);
});
}
addBase(num) {
return new Promise((resolve, reject) => {
resolve(this.base + num);
});
}
}
const values = [1,2,3,4,5];
Promise.try(() => {
return new add(5);
}).then((add) => {
// we want to find if a 5 exists in the results
const addPromise = Promise.resolve(values).map(add.addBase.bind(add), {concurrency: 1});
return Promise.try(() => {
return addPromise;
}).then((results) => {
for(let i = 0; i < results.length; i++) {
if(results[i] === 10) {
return i;
}
}
// doesn't exist
return null;
});
}).then((result) => {
if(result === null) {
console.log('10 does not exist');
} else {
console.log('10 is at position ' + result);
}
})
<script src="https://cdn.jsdelivr.net/bluebird/latest/bluebird.min.js"></script>

How to traverse all files, and support pause and continue

I have created a NodeJS (electron) code for read all the files in a specific directory and subdirectories.
I don't want to use too much HD resources, that why I use a delay of 5ms between folders.
Now my question. I want the if my NODE process stop? I want to be able to continue from when it is stopped. How should I do that?
In other words: How to keep index of current state while walking in all files and folder, so I can continue the traversing from when it has stopped.
Thank you
My Code:
var walkAll=function(options){
var x=0
walk(options.dir,function(){})
function walk(dir,callback) {
var files=fs.readdirSync(dir);
var stat;
async.eachSeries(files,function(file,next){
file=dir +'/' + file
if (dir.match(/Recycle/)) return next()
if (dir.match(/.git/)) return next()
if (dir.match(/node_modules/)) return next()
fs.lstat(file,function(err,stat){
if(err) return next()
if(stat.mode==41398) return next()
if (stat.isDirectory()) {
setTimeout(function(file){
walk(file,next)
}.bind(null,file),5)
}
else{
x++
if(false || x % 1000===0) console.log((new Date().valueOf()-start)/1000,x,file)
next()
}
})
},function(){
callback()
})
}
}
walkAll({
dir:'c:/',
delay:1000
});
Keep a list of sub directories to be visited, and update the list every iteration.
The walk function in the following example takes a previous state, and returns files of next sub directory with next state.
You can save the state before stopping the process, then load the saved state to continue the traversal when restarting.
function walk(state, readdir) {
let files = [], next = [];
while (state.length > 0) {
try {
const current = state.shift()
files = readdir(current).map(file => current + '/' + file)
next = state.concat(files)
break
} catch(e) {}
}
return [next, files]
}
function main() {
const {writeFileSync: writeFile, readdirSync: readdir} = require('fs')
const save = './walk.json'
let state
try {
state = require(save)
} catch(e) {}
if (!state || state.length < 1) state = ['.']
const [nextState, files] = walk(state, readdir)
console.log(files)
writeFile(save, JSON.stringify(nextState, null, 2))
}
main()
an alternate idea,
var miss = require('mississippi')
var fs = require("fs")
var through2 = require("through2")
var path = require("path")
function traverseDir(dirPath) {
var stack = [path.resolve(dirPath)];
var filesStack = []
return miss.from.obj(function(size, next) {
if (filesStack.length) {
return next(null, filesStack.shift())
}
var self = this;
try {
while(stack.length) {
readADir(stack.pop()).forEach(function (f) {
if (f.t=="d") {
stack.push(f.p)
}
filesStack.push(f)
})
if (filesStack.length) {
return next(null, filesStack.shift())
}
}
return next(null, null)
}catch(ex) {
return next(ex)
}
})
}
function readADir (dir) {
return fs.readdirSync(dir)
.map(function (f) {return path.join(dir, f)})
.filter(function (f) { return !f.match(/\.git/) })
.filter(function (f) { return !f.match(/Recycle/)})
.filter(function (f) { return !f.match(/node_modules/)})
.map(function (p) {
try {
var stat = fs.lstatSync(p);
if(stat.mode==41398) return null
var t = stat.isDirectory() ? "d":"f"
return { t: t, p: p }
}catch (ex) {}
return null
})
.filter(function (o) {return o!==null})
}
function loadState(base){
base = path.resolve(base)
var state = {base: base, last:null}
if (fs.existsSync("state.json")) {
state = JSON.parse(fs.readFileSync("state.json"))
} else {
saveState(state)
}
return state
}
function saveState(state){
fs.writeFileSync("state.json", JSON.stringify(state))
}
var state = loadState("..")
var sincePath = state.last;
var filesStream = traverseDir(state.base)
.on('end', function () {
console.log("end")
})
.pipe(through2.obj(function (chunk, enc, next) {
if(!sincePath) this.push(chunk)
if(chunk.p===sincePath) {
sincePath=null
}
next()
}))
var tr = through2.obj(function (chunk, enc, next) {
state.last = chunk.p
saveState(state)
console.log("data %v %j", chunk.t, chunk.p)
this.push(chunk)
setTimeout(next, 500)
}).resume()
require('keypress')(process.stdin);
process.stdin.on('keypress', function (ch, key) {
if(!key) return
if (key.name == "c") {
console.log("continue")
filesStream.pipe(tr)
} else if (key.name=="p") {
console.log("pause")
filesStream.unpipe(tr)
}
});
console.log("Press 'c' to start")

How to avoid require avalanches with node.js?

I want to cache some data in node server:
rpc data provider like this:
var cnt = 0;
function rpcDataProvider(areaId) {
return Q.delay(100).then(() => {
cnt += 1
console.log("I am rpcDataProvider and I am not so fast. I am requested " + cnt + " times.");
const base = areaId * 10;
var arr = [];
for (var i = 0; i < 10; i ++) {
arr.push(base + i);
}
return arr;
})
}
http server
// cache data
var provinceList;
var cityList;
var countyList;
function getProvinceList() {
if (provinceList && provinceList.length > 0) return Q.resolve(provinceList);
return rpcDataProvider(1).then((rv) => {
provinceList = rv;
return rv;
});
}
function getCityList() {
if (cityList && cityList.length > 0) return Q.resolve(cityList);
return getProvinceList().then((provinceList) => {
return Q.all(provinceList.map((item) => rpcDataProvider(item))).then(rvs => {
cityList = rvs.reduce((prev, cur) => prev.concat(cur));
return cityList;
});
});
}
function getCountyList() {
if (countyList && countyList.length > 0) return Q.resolve(countyList);
return getCityList().then((cityList) => {
return Q.all(cityList.map((item) => rpcDataProvider(item))).then(rvs => {
countyList = rvs.reduce((prev, cur) => prev.concat(cur));
return countyList;
})
})
}
function api1() {
console.log("I am http api1");
return getProvinceList();
}
function api2() {
console.log("I am http api2");
return getCityList();
}
function api3() {
console.log("I am http api3");
return getCountyList();
}
function api4() {
console.log("I am http api4");
return getCountyList();
}
function api5() {
console.log("I am http api5");
return getCountyList();
}
client request:
function httpRequest() {
console.log("I am client.");
Q.all([api1(), api2(), api3(), api4(), api5()]);
}
httpRequest();
the problem is that parallel requests, the cache doest not work!
Don't cache the promise value. Cache the promise.
// cache data
var provinceList;
var cityList;
var countyList;
function rpcReduceAndConcat(list) {
return Q.all(list.map(rpcDataProvider)).then(rvs => {
return rvs.reduce((prev, cur) => prev.concat(cur));
});
}
function getProvinceList() {
if (!provinceList) provinceList = rpcDataProvider(1);
return provinceList;
}
function getCityList() {
if (!cityList) cityList = getProvinceList().then(rpcReduceAndConcat);
return cityList;
}
function getCountyList() {
if (!countyList) countyList = getCityList().then(rpcReduceAndConcat);
return countyList;
}

Resources