MEANJS Server controller list function - meanjs

i have some problems changing my list function in the server controller of my MEANJS app. This is the export.list function in the server controller of my module:
exports.list = function(req, res) {
Wordset.find({ 'user':req.user._id }).sort('-created').populate('user', 'displayName').exec(function(err, wordsets) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.jsonp(wordsets);
}
});
};
What it does is that it lists all the items from this module in the listview. In this case it shows all Wordset fromt this user. What i would like to change is that it should show Wordsets not depending on the user, but depending on another module (a user can create persons and each person should have his own wordsets). Lets say i have stored the person._id already, what changes do i need to do here to show only the Worsets for this specific person?

May be something like this (ofc. if Wordset has person field):
Wordset.find({ 'person': person._id })

Related

Having multiple get routes on a NodeJS / Express REST API?

I'm creating a JS web app using NodeJS and Express (with SQL/MySQL for the database), pretty much directly implementing this API tutorial: https://www.bezkoder.com/node-js-rest-api-express-mysql/ (just replacing 'tutorials' with 'Employees').
I'm trying to write API functions to get all Employees with certain attributes (in the SQL table), for example all employees with lastName = "Garcia" or all employees with teamID = 43682, etc.
In my routes.js file I have this:
module.exports = app => {
const employees = require("../controllers/employee.controller.js");
const router = require("express").Router();
// Create a new Employee
router.post("/", employees.create);
// Retrieve all Employees
router.get("/", employees.findAll);
// Retrieve all Employees with lastName
router.get('/', employees.findLastName);
... a bunch more CRUD functions ...
app.use('/api/employees', router);
};
And this is the corresponding Controller function:
exports.findLastName = (req, res) => {
const lastName = req.query.lastName; // tried changing req.query.lastName to req.params.lastName
Employee.getLastName(lastName, (err, data) => {
if (err)
res.status(500).send({
message:
err.message || "Error occurred while retrieving by last name."
});
else {
console.log(`Employees with lastName ${lastName} were found!` );
res.send(data);
}
});
};
exports.findAll = (req, res) => {
const title = req.query.title;
Employee.getAll(title, (err, data) => {
if (err)
res.status(500).send({
message:
err.message || "Some error occurred while retrieving employees."
});
else {
console.log(`Employee with ${title} title was found!` );
res.send(data);
}
});
};
The findAll route/function (just copied from that tutorial) works by finding all Employees with a certain ID number (the primary key in the DB) and I know that works from testing it through Postman. I wrote the findLastName route/function by copying the findAll function and changing it to search by lastName, and making the corresponding functions in the model and controller classes.
The new function, findLastName, doesn't work... unless I put the route before the findAll route (or comment it out). Then it correctly calls all my functions and returns all employees with the lastName param.
What's actually happening here? Are you not allowed to have multiple .get() routes or something? If so, how would I implement a search API like this? This is my first time building a web app like this so admittedly I'm still a little hazy on how routing and all that works. Thank you for any help though!
In Express whenever the first route matches second will be ignored, so in your scenario you have two route.get with same path /
router.get('/', employees.findAll);
//Since route with path `/` is matched above already this will be ignored
router.get('/', properties.findLastName);
In order to find Employees with last name you will need to create a new route with param (param will contain the last name)
router.get('/:lastName', properties.findLastName);
You can access the param value like this req.params.lastName in controller

How to separate login credentials from user data in mysql and nodejs?

I was curious when I been using Django and found that the user data and authentication credentials were in different tables. Unfortunately I never understood how this worked, but I imagine through relationships.
My database is in MySQL and I have created the users table with the user data, then I have created another table called auth with its respective field, id, salt and hash which is what I am interested in saving. I have also created a field called user_id to relate to the user in the users table with the id (I don't know if it's fine like that).
Now, I have a function in my NodeJS code that is responsible for saving the data received by the network layer:
function insert (table, data) {
return new Promise((resolve, reject) => {
connection.query(`INSERT INTO ${table} SET ?`, data, (err, data) => {
if (err) return reject(err)
resolve(data)
})
})
}
has that structure so that it is reusable at all times.
On the other hand I have the controller that handles the business logic of the data received by the network layer:
function insert (user) {
if (!user) {
throw dataMissed
}
bcrypt.genSalt(1000, function(err, salt) {
if (err) throw err
bcrypt.hash(user.password, salt, function (err, hash) {
if (err) throw err
user = {
name: user.name,
email: user.email,
position: user.position,
hash,
salt
}
return store.insert(collection, user)
})
})
}
Unlike the function that is dedicated to saving the data in the database, this one is unique since the logic will depend on the data, obviously.
And the problem I have is that I don't know how to save the generated salt and the hash in the corresponding table. As you can see, I use the same function to save both but it gives me an error, since it is a logic that does not work.
How do I save a value that will later be referenced by another table?
I think the problem is that your 2nd insert function expect user and it also expects user to have password when in reality user should not have password. You need to have 2 DALs, one to control user table and the other to control the credentials Then in your service layer you do your logic using waterfall since credentials DAL depends on user's id
Here is pseudo code of what I mean
Userdal.js
/*
* User should look something like
* {
* name: "xyz",
* age: 40,
* email: "test#test.com"
* etc...
* }
* Basically it has non sensitive information nothing has to do with credentials.
*/
function insert(user) {
/// does insert logic
return store.insert(collection, user) //or resolve, whatever works for you
}
CredentialsDal.js
/*
* creds should look something like
* {
* username: "aaaa",
* password: "asfa",
* userId: "1234567"
* }
*/
function insert(creds) {
// Do your logic here for creds, for example
bcrypt.genSalt(1000, function(err, salt) {
if (err) throw err
bcrypt.hash(creds.password, salt, function (err, hash) {
if (err) throw err
const sanitizedCreds = {
username: creds.username,
salt: salt,
hash: hash
// Literally anything you can credential goes here.
}
return store.insert(collection, sanitizedCreds)
})
})
}
UserService.js
// This is a nice library this gives things such as waterfall, series, etc... (you dont need to use it though)
const asyncx = require('async')
const credsDals = require('./dals/CredentialsDal')
const userDal = require('./dals/UserDal')
function register(userData, credsData) {
asyncx.waterfall([
// Create user
(callback) => {
let user = userDal.insert(userData)
callback(null, user.id)
},
// Create credentials
(userId, callback) => {
let creds = credsDal.insert(credsData)
callback(null, true)
}
], (err, res) => {
// Handle your result here
})
}
Controller.js
const UserService = require('./Services/UserService')
function register(req, res) {
const userData = req.body.user
const credsData = req.body.credentials
UserService.register(userData, credsData)
res.status(200).end()
}
finally your router
const controllers = require('./controllers')
router.post('/user', controllers.register)
The above code is missing some pieces I left for you to fill, such as actual logic implementation, callbacks and returns, promises, etc...
Note: such separation is really important and nice to have since it create a secure code. whenever you request a specific user you don't want to send all of their sensitive information with the response. For example, imagine you tap on your friend's user profile on facebook and all of the sudden that facebook frontend request will bring back even the user's credentials even if they are not rendered they are still being requested and can be sniffed! so these sensitive information are stored on a separate table if not separate server all together. In cases such as credit cards, etc... they have different servers that can only accept requests from the same network and bans all other requests, this way it makes it harder for anyone to make any request to those servers, basically you have to be inside the server's network to make that request.
Link to repl.it: https://repl.it/repls/BlindCuddlyUserinterface#index.js

Loopback autoupdate not creating custom models

I'm trying to create an app using Loopback (V3) and i've encountered a weird error.
I'm trying to create my Mysql tables using autoupdate(), but for my custom models it is not working.
This is what i've tried so far ->
var server = require('../server');
var ds = server.dataSources.db;
var models = ['test','Post','User', 'AccessToken', 'ACL', 'RoleMapping', 'Role'];
ds.isActual(models, function(err, actual) {
if (!actual) {
ds.autoupdate(null, function(err,result){
console.log("DONE!");
console.log(result);
});
};
});
The script works. If the database is empty it will create tables for all EXCEPT test and Post. Those are my custom models, the others are built into loopback.
Is it because of model type? (tried Model and PersistedModel) or is it something else? I even tried without the isActual check and still nothing.
I would recommend that you keep two separate arrays for built-in models and custom models and write code like following, that way you could know where the issue is. also, I think there is an error in your code near ds.autoupdate(null, fun.....
please follow according to the below code
var builtInModels = ['AccessToken', 'ACL', 'RoleMapping','Role'];
var userDefinedModels = ['Post','test'];
// migrate built-in models
dataSource.isActual(builtInModels, function (err, actual) {
if (!actual) {
dataSource.autoupdate(builtInModels, function (err, result) {
if(err) console.log(err);
console.log('Datasource Synced: Built in models');
});
}
});
// migrate userdefined models
dataSource.isActual(userDefinedModels, function (err, actual) {
if (!actual) {
dataSource.autoupdate(userDefinedModels, function (err, result) {
if (err) console.log(err);
console.log('Datasource Synced: User defined models');
});
}
});

Mongoose Populate with express res.json() breaks

So I'm selecting Activities from the mongodb and populating User for each.
var query = Activity.find(query).populate("user");
return query.sort({created:"desc"}).exec(function(err, activities) {
debugger;
if (!err) {
return res.json(activities);
} else {
res.status(400).json(err);
}
});
As you can see I have a debugger; breakpoint is there, When I'm pring activities it prints an array of activities with the user object populated.
Also when I'm calling something like activities[0].toJSON() I get everything good!
But the response comes back with the user property empty !
I looked into the source of express.response.json(OBJ) and saw this line:
var body = JSON.stringify(val, replacer, spaces);
val is my activities
When calling JSON.stringify(activities) it will create a json with an empty user field.. any suggestions ?
Try the lean option. That gives back plain JS objects with no mongoose weirdness. Also, your error handling seems a little awkward, can be simplified.
var query = Activity.find(query).populate("user");
query.sort({created:"desc"}).lean().exec(function(err, activities) {
if (err) return res.status(400).json(err);
res.json(activities);
});
I would go even further, not hard-coding error sending in routes but simply passing along via if (err) return next(err) to error-handling middleware defined elsewhere in your app. You can still set the status, then use detection in your middleware, something like this:
app.use(function(err, req, res, next){
err.status = err.status || 500;
res.status(err.status).json(err);
});

sails.js: how to update model

Forgive my noob question. I'm using angularjs to send a user model (json) with varying fields. It works well with sails.js default PUT. I overrode the PUT, the problem is that I wish to update the model with the received JSON and do some processing on the modified model. Now I can't update the model with
User.update({
id: req.body.id
},{
req.body
}, function(err, users) {
// Error handling
if (err) {
return console.log(err);
// Updated users successfully!
} else {
console.log("Users updated:", users);
}
});
Please help
EDIT:
After knocking my head on the wall for days, problem solved! I know, my code formatting here is not the best..
changed this:
{
req.body
}
to just:
req.body
(without the braces)
full snippet becomes:
User.update({
id: req.body.id
},
req.body
, function(err, users) {
// Error handling
if (err) {
return console.log(err);
// Updated users successfully!
} else {
console.log("Users updated:", users);
}
});
Thanks.
So you figured out your problem, sort of. req.body is already an object. But you really should sanitize it before you put it into your update and then save the object. There's a lot of reasons for this but with Mongo when you get only a partial object you'll replace the object in the collection which, in your example with a user, could be bad. When I send users to the frontend I cull off things I don't want transmitted all over like passwords. The other reason is the golden rule of web application development - never trust the client! I'd start with something like:
var user = User.findOne(req.body.id).done(function(error, user) {
if(error) {
// do something with the error.
}
if(req.body.email) {
// validate whether the email address is valid?
// Then save it to the object.
user.email = req.body.email;
}
// Repeat for each eligible attribute, etc.
user.save(function(error) {
if(error) {
// do something with the error.
} else {
// value saved!
req.send(user);
}
});
});