I was just going through a model code HERE. and i see certain the following in a route file (line of code can be found HERE) :
router.get('/departments/', function(req, res){
// Add JS that is specific only to current page
res.locals.custom_java_script.push('/js/departments.js');
var company_for_template,
model = req.app.get('db_model');
req.user.getCompany({
scope : ['with_active_users', 'order_by_active_users'],
})
.then(function(company){
company_for_template = company;
return company.getDepartments({
scope : ['with_simple_users', 'with_boss'],
order : [[ model.Department.default_order_field() ]],
});
})
.then(function(departments){
res.render('departments_overview', {
title : 'Departments settings',
departments : departments,
allowance_options : generate_all_department_allowances(),
company : company_for_template,
});
});
});
What i don't understand is a single line of code I.E. req.user.getCompany. Where is the getCompany method being attached to the user object. I have a bit of a fuzzy understanding. I'll list out my understanding below.
So basically the user object is being attached by passport.js is what i believe, but where and how exactly is the getCompany being attached to the user object ?
The only partial clue i have is this answer HERE I.E. the deserializeUser, when i see that i only see the below (code can be found HERE, on the repo.) :
passport.deserializeUser(function(id, done) {
model.User.find({where : {id : id}}).then(function(user){
return user.reload_with_session_details();
})
.then(function(user){
done(null, user);
})
.catch(function(error){
console.error('Failed to fetch session user '+id+' with error: '+error);
done(null, false, { message : 'Failed to fetch session user' });
});
});
And from here on i am a bit lost for clues. Any suggestions on where and how the getCompany method is being attached would be really appreciated.
This timeoff-management lib is using Sequelize for the User model and if you look at here https://github.com/timeoff-management/timeoff-management-application/blob/master/lib/model/db/user.js#L561, the User model has an association to Company model.
When the association is defined between two models, Sequelize will create a couple of mixins which is available on an instance.
With the as option is presented, these mixins will be generated on the User instance. (Some plural forms will be also generated but I couldn't confirm.)
userInstance.getCompany()
userInstance.countCompany()
userInstance.hasCompany()
userInstance.setCompany()
userInstance.addCompany()
userInstance.removeCompany()
userInstance.createCompany()
For more detail about Sequelize mixins, please check it out here https://sequelize.org/v6/manual/assocs.html#special-methods-mixins-added-to-instances.
Related
I am kinda new in node. recently I decided to create a blog system and it has an authorization system which is created by passport module and local strategy.
I used passport documentation and some video tutorials to design it but I can't understand how does it work, I don't understand the logic.
I have a login form which has two fields (username,password) and a submit button.
you can see my login.jade code here. it is written in jade templating language and used semantic-UI(something like bootstrap).
form.ui.form(method="POST",action="")
div.field
label Username
div.ui.left.icon.input
i.user.icon
input(type="text",name="username",placeholder="username")
div.field
label Password
div.ui.left.icon.input
i.lock.icon
input(type="password",name="password",placeholder="password")
button.ui.primary.button(type="submit") log-in
and here is my passport local strategy
passport.use(new localStrategy(function(username,password,done){
User.checkUserName(username,function(err,user){
if (err) throw err;
if (!user) {
console.log('unknown user');
return done(null,false,{message:'user not found'});
}
if(user.password!=password){
return done(null,false , {message : 'password is wrong'});
}
return done (null,user);
});
}));
checkUserName is a function in my models (user.js) which finds the username in the database.
module.exports.checkUserName= function(username,callback){
User.findOne({username:username},callback);
}
now I don't understand how does the localstrategy work. how does it understand which field in my login form is for username and which field is for the password? it only accepts two arguments (username, password) but I don't know how it specifies where are these arguments come from and how it understands that these must be my login form credentials.
I would be very thankful if someone explains to me what is happening here.
If you're using username / password authentication, by default localStrategy() uses input fields with name="username" and name="password". So, your form is correct.
If you want to use other field names, you can change the defaults. Read this. http://www.passportjs.org/docs/username-password/#parameters
I'd like to point out that you should use a hashing scheme for your passwords, rather than storing them in plain text in your database. Because, Ashley Madison.
This is a well-designed robust hashing scheme. There are others.
Looking at the implementation of the strategy in github it looks at both query of the request and its body and by default will look for username and password keys for their respective values.
This matches the name values in the login form.
If you want to use different name values for your inputs you can specify what values you want it to use by providing a usernameField or passwordField value like follows
passport.use(new localStrategy(function(username,password,done){
User.checkUserName(username,function(err,user){
if (err) throw err;
if (!user) {
console.log('unknown user');
return done(null,false,{message:'user not found'});
}
if(user.password!=password){
return done(null,false , {message : 'password is wrong'});
}
return done (null,user);
});
},
{
usernameField: 'user',
passwordField: 'pass'
}
));
Then you can update the login form name values to match
form.ui.form(method="POST",action="")
div.field
label Username
div.ui.left.icon.input
i.user.icon
input(type="text",name="user",placeholder="username")
div.field
label Password
div.ui.left.icon.input
i.lock.icon
input(type="password",name="pass",placeholder="password")
button.ui.primary.button(type="submit") log-in
I am new to express js. I am currently building a todo list web app. I have been following the tutorials and is able to perform basic CRUD operation. I have two models.
Users - (name, email, password hash, password salt, todo_items - which reference to the second model).
Todo_items - (title, description, due_date, user - which reference to the first model).
When a user log in, I am able to read his user_id. However, how can i filter the todo_items that only belongs to the user? My current code looks like this and is returning all the todo_items from all the users.
router.get('/api/todo_items', function(req, res, next){
Todo_items.find(function(err,todo_items){
if(err){return next(err); }
res.json(todo_items);
})
});
Currently, I am using a front end framework, Angularjs to filter the results that get displayed. But I thought this is inefficient as the user base gets big. How do I create a filtering system from the backend?
You can query the collection on the user field, assuming it references the User model on the _id field so you could have something like the following:
router.get('/api/todo_items', function(req, res, next){
Guest.find({ "user": user_id }).exec(function(err, todo_items){
if(err) { return next(err); }
res.json(todo_items);
});
});
I'm trying to render a template when i check the link for view a profile (for example going to http://localhost:3000/user/testuser`), all ok going to the routes but the values don't being showed on the page. This is my code:
Account.find({ username: req.params.username }, function(err, userWatch){
res.render('account/profile',{
title : userWatch.username,
user : req.user,
watchUser : userWatch,
});
You are using Account.find() that returns the array of objects. You should use Account.findOne() to fetch data, if you want either one or none objects.
I have a node js function:
function func() {
USER.find({},function(err, users){
user = users[0];
console.log(user); // {"name":"mike", "age":15, "job":"engineer"}
user.name = "bob"; //{"name":"bob", "age":15, "job":"engineer"}
delete user.name;
console.log(user); // {"name":"mike", "age":15, "job":"engineer"} name still there??
});
}
Here USER is a mongoose data model and find is to query the mongodb. The callback provide an array of user if not err. The user data model looks like
{"name":"mike", "age":15, "job":"engineer"}.
So the callback is invoked and passed in users, I get the first user and trying to delete the "name" from user. The wired part is I can access the value correctly and modify the value. But if I 'delete user.name', this element is not deleted from json object user. Why is that?
As others have said, this is due to mongoose not giving you a plain object, but something enriched with things like save and modifiedPaths.
If you don't plan to save the user object later, you can also ask for lean document (plain js object, no mongoose stuff):
User.findOne({})
.lean()
.exec(function(err, user) {
delete user.name; // works
});
Alternatively, if you just want to fetch the user and pay it forward without some properties, you can also useselect, and maybe even combine it with lean:
User.findOne({})
.lean()
.select('email firstname')
.exec(function(err, user) {
console.log(user.name); // undefined
});
Not the best workaround, but... have you tried setting to undefined?
user.name = undefined;
I'm working with sails.js and mongo.db following some tutorials and creating a custom application and things are going well. Largely I'm using the built in, backbone I believe, scrud functions, I'm wondering how I could create a database entry from scratch. For example, the following works great from form data in my Student Controller:
create: function (req, res, next) {
Student.create(req.params.all(), function studentCreated(err, student) {
if (err) {
console.log(err);
req.session.flash = {
err: err
}
return res.redirect('/');
}
res.redirect('/');
});
},
For simplicity my Student model currently just has a first name and a one way association with a schools model.
module.exports = {
attributes: {
school: {
model: 'school'
},
first_name: {
type: 'string'
},
},
};
Say I wanted to, for the sake of understanding, just create a student with a fixed first name "Bob" and fixed school Id "xyz" in another action, without using the built in backbone create functions, nor using defaultTo in the model, nor using any form data. I would like to just code creating a database entry in an action, for example a test action in my Student controller. How would I go about this? I tried googling this a little, but given it's beginner nature I'm sure my query parameters were not particularly good.
If I correctly understand the question, I think you've already done most of the work. In the Student.create() call, replace req.params.all() by {first_name:'Bob', school:'xyz'}.
If you want to mix it with values from the request params, you could use {first_name:'bob', school: req.param('school')}