Extend CRUD functions - sails.js

I want to add some functionality to the built-in create function.
I have a model called user, and I know I can override the create function by declaring my own create function in the UserController:
module.exports = {
create: function(req, res) {
// Logic here for checking if everything is okay
if (everything_okay) {
// call super.create() ? <--
}
else{
res.josn({ error: err });
}
},
};
I read through the docs, but couldn't find out how to implement the indicated <-- line.

// call super.create() ? <-- means this is the place where you call:
User.create(userObject, function (err, cretaedUserObj) {
if(err) {
//handle err
} else {
//user succesfully created.
}
});
So basically, if all the parameters are OK i.e. if(everything_okay), you create the User, else you handle that which is Not Ok.
Hope this helps.

Related

.find() returning nothing even when data exists

I've a mongo database with 3 collections for 3 different kind of users as User,Partner,Admin. Whenever a new user of any type signup I'm searching all three collections to check if username and email exist already. I'm trying to achieve this by calling a function as:
function checkAttribute(attr,val,callback){
User.find({attr: val},function(err,user){
if(err){
console.log(err);
}else{
if(user.length === 0){
Partner.find({attr: val},function(err,partner){
if(err){
console.log(err);
}else{
if(partner.length === 0){
Admin.find({attr: val},function(err,admin){
if(err){
console.log(err);
}else{
if(admin.length === 0){
return callback(null,true);
}else{
return callback(null,false);
}
}
});
}else{
return callback(null,false);
}
}
});
}else{
return callback(null,false);
}
}
});
};
Calling function line:
checkAttribute("username",newUser.username,function(error,response){
.......
});
But this is not working as it returns true always even when users with passed username/email exists already. I am unable to find the problem. Any one knows why this is happening?
Thanks in advance.
Since you are passing in the attribute as a variable in the function parameters, the query document
{ attr: val } is an object with the key "attr", not the dynamic attribute you pass in.
To fix this, you need to use computed property names in your query object as
{ [attr]: val }
Also, the function can use async/await pattern to be more readable and for the purpose of finding if a document exist findOne does the job so
well as it returns a document if it exists and null otherwise.
So your function can be refactored as
async function checkAttribute(attr, val, callback) {
try {
const query = { [attr]: val }
const user = await User.findOne(query).exec()
const partner = await Partner.findOne(query).exec()
const admin = await Admin.findOne(query).exec()
const found = (user || partner || admin) ? true: false
return callback(null, found)
} catch (err) {
console.error(err)
return callback(err, null)
}
};
attr: in your queries will search for a db field called attr. If you want to use the function parameter attr, use [attr]: as the key.
Example:
attr = 'username'
User.find({ [attr]: val }, function (err, user) {
if (err) {
console.log(err);
}
})
This is a feature available since ES6 so should work fine. See the docs here for more info

How to retrieve value from Storage and user it somewhere else in Ionic 2

I am new to Ionic 2 and Promises and having some issues.
My Ionic 2 app saves an auth_token to the local storage:
this.storage.set('auth_token', auth_token);
Then later in my secured component I want to check if a token is set, but I don't know how to do this.
I tried this:
authenticate() {
var auth_token = this.storage.get('auth_token').then((val) => {
return val;
});
}
Then from somewhere else I called:
console.log(this.auth.authenticate);
But it won't work, it just returns the function itself.
How do I return the token from my authenticate method?
Check here for chaining of promises.
In your authenticate() function return the original promise call and use then in the function in the other location
authenticate() {
return this.storage.get('auth_token').then((val) => {
return val;
});
}
When caling authenticate...
this.auth.authenticate().then((val)=>{
console.log(val);
}).catch(error=>{
//handle error
});
You just want to check or do you need to return it?
If it's only checking you can do this:
authenticate() {
this.storage.get('auth_token').then((val) => {
if(val){ ... } // or console.log it if it's just what you need.
}
}
If you need to return, create a promise like this:
authenticate = (): Promise<{exists: boolean, auth: any}> =>{
return new Promise<{exists: boolean, auth: any}>(res =>{
this.storage.get('auth_token').then((val) => {
if(val){
res({exists: true, auth: val});
} else {
res({exists: false, auth: val});
}
}
})
}
and later call authenticate().then(res =>{}) and access the object returned in res.
EDIT
As commented by Suraj and tested now, it doesn't need to be encapsulated inside a new promise, so if you need to return it just use the method Suraj suggested.

Is there a reason why the local strategy for sails-generate-auth does not set req.session.authenticated to true

When I login using the local strategy subsequent requests having the sessionAuth policy on them fail because req.session.authenticated is undefined. I've excerpted a portion of the login function from api/services/protocols/local.js. I've inserted a comment for the code I believe is missing.
passport.validatePassword(password, function (err, res) {
if (err) {
return next(err);
}
if (!res) {
req.flash('error', 'Error.Passport.Password.Wrong');
return next(null, false);
} else {
///// Shouldn't authenticated get set true here?
///// req.session.authenticated = true;
return next(null, user);
}
});
As suggested by Alberto Souza the local strategy works if you change sessionAuth.js from:
module.exports = function(req, res, next) {
if (req.session.authenticated) {
return next();
}
return res.forbidden('You are not permitted to perform this action.');
};
to:
module.exports = function(req, res, next) {
if (req.isAuthenticated()) {
return next();
}
return res.forbidden('You are not permitted to perform this action.');
};
So the answer to my question seems to be sessionAuth.js is part of the default sails app generation and not created when you run sails generate auth and therefore is a change you need to make manually that the documentation neglects to tell you about.

Sails inconsistent record creation

I use the following piece of code to create some records. If I provide incorrect values, say(password and passwordConfirmation does not match), then sometimes an institute record is created without a rollback and sometimes, rollback happens properly.
I would appreciate any help. Is there a better way to do this?
create: function (req, res) {
User.query("BEGIN TRANSACTION", function(result){
if(result) {
sails.log.info(result);
return res.serverError(result);
} else {
Institute.create({
name: req.param('name'),
shortName: req.param('shortName'),
phoneNumber: req.param('phoneNumber'),
subdomain: req.param('subdomain'),
managerEmail: req.param('email')
}, function(error, institute){
if(error) {
sails.log.info(error);
Institute.query("ROLLBACK", function(result) {
sails.log.info(result);
return res.badRequest(error);
});
} else {
User.create({
email: req.param('email'),
password: req.param('password'),
passwordConfirmation: req.param('passwordConfirmation'),
account: institute.id
}, function(error, user) {
if(error) {
sails.log.info(error);
Institute.query("ROLLBACK", function(result) {
sails.log.info(result);
return res.badRequest(error);
});
} else {
User.query("COMMIT", function(result){
sails.log.info(result);
return res.created(user);
});
}
});
}
});
}
});
}
You have a few of options, in no particular order.
1. Write a function that makes all the possible security checks before creation occurs, or use the beforeCreate life cycle call for your models.
For example, you could write a function verifyParams(params) that makes checks such as password comparison (and any other checks you want) for your user creation parameters before you create the institution, or you could just include these checks in your institution creation's beforeCreate method.
2. Delete if there is an error during your user creation
Delete theInstitute model instance in your error case of user creation:
...
User.create(..., function (error, user) {
if (error) {
Institute.destroy(institute.id, function instDestroyed(err) {
...
});
} else {
...
}
});
3. Create a user in your institute model's beforeCreate method.
module.exports = {
attributes: { ... },
beforeCreate: function(values, next) {
User.create(..., function (err, user) {
if (err) { return next(err) }
return next();
});
}
}
Personally, I use method #2 in my own apps.

Call controller on afterCreate

I have the following code for my Sessions model:
module.exports = {
attributes: {
},
afterCreate: function(value,next) {
next();
}
};
And the following Sessions Controller:
module.exports = {
saveSession: function(res,req) {
console.log('in save');
}
};
I want to save a value to a user's session afterCreate
How can I call the saveSession function from my model? I tried Sessions.saveSession() but it doesn't work.
I don't think you need a session model and it's not a good idea to call a controller method directly.
I'd recommend just set req.session when you're trying to save the session and it'll be auto-saved when you respond from that controller action.
afterCreate will never have access to req unless you pass it down which I wouldn't recommend.
The pattern is something like:
{
// …
login: function (req,res) {
User.findOne({
username: req.param('username'),
password: req.param('password')
}).exec(function (err, user) {
if (err) return res.serverError(err);
if (!user) return res.view('/login');
req.session.user = user.toJSON();
return res.redirect('/dashboard');
});
}
// ...
I think that you want to save a value to a cookie or create another database record am i correct?
If so, you dont need to call a controller action from the model (not recommended), you just need to create a new record or save the value to the cookie, here are some alternatives that i see possible in your scenario.
creating another record:
// on models/YourModel
module.exports = {
attributes: {
},
afterCreate: function(newlyInsertedRecord,next) {
ModelOrResource.create({
param1: newlyInsertedRecord.attributeYouWant,
param2: value2
// and so on
}).exec(function(err, recordCreated){
if(err) return next(err);
// do somethign with recordCreated if you need to
// ...
next();
})
}
};
Saving a value to a cookie:
module.exports = {
attributes: {
},
afterCreate: function(newlyInsertedRecord, next) {
// do some other stuff not related to calling a controller action ;)
next();
}
};
This code was retrived from snippets from my own projects, so it should work on sails 0.9.x
Hope it helps!