Mongoose "Create" method - Is there no callback? (Using passport and angular) - angularjs

I am using mongoose to create a user object on register. This works fine and any errors are returned as expected.
However, I want to log the user on right after they register (so registering logs you on if there are no errors).
I have the following for the register.
register_controller:
$scope.submitRegister = function() {
AuthenticationService.register(this.details).success(function() {
$log.debug('/POST to /api/register worked');
});
}
services.js:
.service('AuthenticationService', function($http, $timeout, $q, $session, $flash) {
...
this.register = function(details) {
var register = $http.post('/api/register', details);
register.success(function() {
console.log("User added fine");
}).error(function() {
console.log("error!!!");
});
return register;
};
...
users.js:
app.post('/api/register', authentication.register);
passport's authenticate.js:
module.exports = {
...
register: function(req, res){
var User = require('./controllers/api/login_api');
User.create({name: req.body.name, email: req.body.email, password: req.body.password}, function(err){
if (err) {
console.log(err);
return;
}
console.log("User added");
return res.send(200);
});
},
...
The error is reported back fine, no troubles, but I would have thought it would report something else back (like the created object?) which I could use down the line so my register_controller can have in the success function(object) {... login(object);...}.
Is this a limitation in the .create method or am I missing something obvious?
Thank you.

Two things to change in your server code:
passport's authenticate.js:
module.exports = {
...
register: function(req, res){
var User = require('./controllers/api/login_api');
User.create({name: req.body.name, email: req.body.email, password: req.body.password}, function(err, user){
if (err) {
console.log(err);
return;
}
console.log("User added");
return res.send(200, user);
});
},
...
I've added user to your callback Mongoose model.create api - return the created object to the CB
And to change the catch in your client:
.service('AuthenticationService', function($http, $timeout, $q, $session, $flash) {
...
this.register = function(details) {
var register = $http.post('/api/register', details);
register.success(function(user) {
console.log(user);
}).error(function() {
console.log("error!!!");
});
return register;
};
...
Now you can do with the created user object whatever you need

Related

Save and display comment in real-time using angularjs and socket.io

I have problem with socket.io. In my code router.post(/comment,...) saving user comments in database (using mongoose) and I am trying emit this save. In controller function readMoreCourse is to get and display all comments from database (and question how use socket to this function that using ng-reapat display comment in real-time). Function AddComment is on client side chceck valid form and next post comment to database.
My question: How in real-time save and display user comment using angular (ng-repeat?) and socket.io? Honestly I making this first time, and I have short time, thanks for any help.
Server
io.on('connection', function(socket){
socket.emit('comment', function(){
console.log('Comment emitted')
})
socket.on('disconnect', function(){
})
})
API
router.post('/comment', function(req, res) {
Product.findOne({ _id: req.body._id }, function(err, product){
if(err) {
res.json({ success:false, message: 'Course not found' })
} else {
User.findOne({ username: req.decoded.username }, function(err, user){
if(err){
res.json({ success:false, message: 'Error'})
} else {
product.comments.push({
body: req.body.comment,
author: user.username,
date: new Date(),
});
product.save(function(err){
if(err) throw err
res.json({ success: true, message: 'Comment added })
**io.emit('comment', msg);**
})
}
})
}
})
})
controller
Socket.connect();
User.readMoreCourse($routeParams.id).then(function(data){
if(data.data.success){
app.comments = data.data.product.comments;
} else {
$window.location.assign('/404');
}
});
app.AddComment = function(comment, valid) {
if(valid){
var userComment = {};
userComment.comment = app.comment;
Socket.on('comment', User.postComment(userComment).then(function(data){
if(data.data.success){
$timeout(function(){
$scope.seeMore.comment = '';
},2000)
} else {
app.errorMsg = data.data.message;
}
}));
} else {
app.errorMsg = 'Error';
}
}
$scope.$on('$locationChangeStart', function(event){
Socket.disconnect(true);
})
factory
userFactory.readMoreCourse = function(id) {
return $http.get('/api/seeMore/' + id)
}
userFactory.postComment = function(comment){
return $http.post('/api/comment', comment);
}
.factory('Socket', function(socketFactory){
return socketFactory()
})
In your socket factory, initialize socket.io emit and on events.
app.factory('socket', ['$rootScope', function($rootScope) {
var socket = io.connect();
return {
on: function(eventName, callback){
socket.on(eventName, callback);
},
emit: function(eventName, data) {
socket.emit(eventName, data);
}
};
}]);
and call this from controller
app.controller('yourController', function($scope, socket) {
User.postComment(userComment).then(function(data){
if(data.data.success){
$timeout(function(){
$scope.seeMore.comment = '';
},2000);
// Emit new comment to socket.io server
socket.emit("new comment", userComment);
} else {
app.errorMsg = data.data.message;
}
});
// other clients will listen to new events here
socket.on('newComment', function(data) {
console.log(data);
// push the data.comments to your $scope.comments
});
from socket.io server
io.on('connection', function(socket) {
// listen for new comments from controller and emit it to other clients
socket.on('new comment', function(data) {
io.emit('newComment', {
comment: data
});
});
});
EDIT:
If you just want to push from server side,
io.on('connection', function(socket) {
// after saving your comment to database emit it to all clients
io.emit('newComment', {
comment: data
});
});
and remove this emit code from controller:
socket.emit("new comment", userComment);
But this method can be tricky because the user who posts the comment should immediately see the comment added to the post. If you let socket.io to handle this there will be a few seconds lag for the guy who posted the comment.

Check if a user has isAdmin true

I'm trying to make an isAdmin() function that will check if the current user has "isAdmin: true" in the mongodb.
server.js
app.get('/api/isadmin', function (req, res) {
User.findById(req.user, function (err, user) {
if (req.user.isAdmin == true) {
res.send(user);
} else {
return res.status(400).send({ message: 'User is not Admin' });
}
});
});
AdminCtrl.js
angular.module('App')
.controller('AdminCtrl', function ($scope, $http, $auth) {
$http.get('http://localhost:3000/api/isadmin')
.then(function (res) {
$scope.isAdmin = res.data;
}
});
when I access the page /admin it throws "cannot read property 'isAdmin' of null" in the if inside app.get. Why is this occuring, and what is the optimal way for me to make this isAdmin function?
You are not using the variable sent back to you, but still the req.
app.get('/api/isadmin', function (req, res) {
User.findById(req.user, function (err, user) {
if (user.isAdmin == true) {
res.send(user);
} else {
return res.status(400).send({ message: 'User is not Admin' });
}
});
});
Maybe this should work (assuming you are returned if the user isAdmin)
try following
angular.module('App')
.controller('AdminCtrl',['$scope','$http','$auth', function ($scope, $http, $auth) {
$http.get('http://localhost:3000/api/isadmin')
.then(function (res) {
$scope.isAdmin = res.data;
}
}]);

satellizer then not called after authentication

I'm very new to angular, so my knowledge is based on tutorials and even then I don't succeed.
I need to authenticate using a google account. That works, I get a token where my api calls could be authorized with. But after login the pop up window should dismiss and I should be redirected to the homepage. This doesn't work.
this is my controller
angular.module('MyApp').controller('loginController', ['$scope', '$auth', '$location','loginService', loginController]);
function loginController($scope, $auth, $location, loginService) {
$scope.authenticate = function(provider) {
$auth.authenticate(provider).then(function(data) {
loginService.saveToken(data.data.token);
console.log('You have successfully signed in with ' + provider + '!');
$location.path('http://localhost/#/home');
});
};
};
in app.js I have my configuration. this is not my work but a friend who is an intern as wel as me, he is responsible for a mobile application, where he uses the same function to get his token, and it works.
authProvider.google({
clientId: CLIENT_ID,
redirectUri: 'http://localhost:3000/api/users/signIn'
});
$authProvider.storage = 'localStorage'; // or 'sessionStorage'
$authProvider.loginRedirect = 'http://localhost/#/home';
This is the controller in node where the url is redirected to (google developer console)
router.get('/signIn', function(req, res) {
//console.log(req);
var code = req.query.code;
oauth2Client.getToken(code, function(err, tokens) {
if (!err) {
https.get("https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=" + tokens.access_token, function(response) {
// Continuously update stream with data
var body = '';
response.setEncoding('utf8');
response.on('data', function(d) {
body += d;
});
// Data fetched
response.on('end', function() {
var parsed = JSON.parse(body);
// Check if client_id is from the right app
if (parsed.issued_to == '343234242055-vd082vo0o8r8lmfvp1a973736fd98dht.apps.googleusercontent.com') {
User.getGoogleId(parsed.user_id, function(err, user) {
if (err) {
res.status(500).send({
message: 'not authorized app'
});
}
// No user returned, create one
if (!user) {
// Request user info
oauth2Client.setCredentials(tokens);
plus.people.get({
userId: 'me',
auth: oauth2Client
}, function(err, plusUser) {
if (err) res.status(500).send({
message: 'not authorized app'
});
else {
// Create new user
User.create(plusUser.name.givenName, plusUser.name.familyName, (plusUser.name.givenName + "." + plusUser.name.familyName + "#cozmos.be").toLowerCase(), parsed.user_id, function(err, newUser) {
if (err) res.status(500).send({
message: 'not authorized app'
});
else {
res.statusCode = 200;
return res.send({
response: 'Success',
id: user._id,
firstName: user.firstName,
lastName: user.lastName,
email: user.email,
token: tokens.access_token
});
}
});
}
});
} else {
// Return user
res.statusCode = 200;
return res.send({
response: 'Success',
id: user._id,
firstName: user.firstName,
lastName: user.lastName,
email: user.email,
token: tokens.access_token
});
}
});
}
// if not right app, return unauthorized response
else {
res.status(500).send({
message: 'not authorized app'
});
}
});
});
}
});
});
So I login, I get asked to give permission to the application to use my account info, I get a json response where I can see my name, email and token, and that's it
Even within the company where I work, no one could find an answer. So I came with a solution myself. I don't use satellizer anymore.
.when('/access_token=:access_token', {
template: '',
controller: function($window, $http, $location, $rootScope) {
var hash = $location.path().substr(1);
var splitted = hash.split('&');
var params = {};
for (var i = 0; i < splitted.length; i++) {
var param = splitted[i].split('=');
var key = param[0];
var value = param[1];
params[key] = value;
$rootScope.accesstoken = params;
}
console.log(params.access_token);
var json = {
Token: params.access_token
};
$window.localStorage['token'] = params.access_token;
$http.post('http://localhost:3000/api/users/signIn', json).success(function(data, status) {
console.log(data);
}).error(function(err) {
console.log(err);
});
$location.path("/home");
}
/*controller: 'createNewsFeed',
templateUrl: 'homepage.html'*/
}).
So redirect the page by itself. Because the authentication works on the backend side, I can get a access token, which is the only thing I really need for future use of my rest api. I defined a route where, after receiving the json with the token, my browser is manually redirected to with $window.location. So when that page is loaded (not visible for the user, it goes too fast to notice) I analyse the token, save the token, analyse authentication, when that is successful I manually redirect to the homepage.

Mongodb CRUD operation with Angularjs and nodejs - How to get message from database if data is already exist?

In controller.js:
angular.module('CRUD').controller('myController',['$scope','$http', function($scope,$http){
$scope.sendData = function(){
console.log($scope.data1);
var formData = {
"username" :$scope.username,
"email" :$scope.email
};
$http({
url:'/formData',
method:'POST',
data:formData
}).success(function(data){
console.log(data);
});
}
}]).directive("myFirstDirective",function(){
return
{
template:"<b>custom directive</b>",
restrict:'E';
}
});
In your nodeJS route API
//User Schema
'use strict';
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var UserSchema = new Schema({
username: String,
email: {
type: String,
unique: true //means the email has to be unique across all documents
}
});
UserSchema.path('email').validate(function(value, done) {
this.model('User').count({ email: value }, function(err, count) {
if (err) {
return done(err);
}
// If `count` is greater than zero, "invalidate"
done(!count);
});
}, 'Email already exists');
module.exports = mongoose.model('User', UserSchema);
...
//API
app.post('/formData', function(req, res){
User.create(req.body, function(err){
if (!err){
res.send(200); //user created
}
else {
if (err.name === 'ValidationError') res.send(409); //stands for form validation error
else res.send(500);
}
});
});
Good practice to put your requests in the service. For example
angular.module('CRUD').controller('myController',['$scope','$http', 'CRUDService', function($scope,$http, CRUDService){
$scope.sendData = function(){
CRUDService.createUser({
username: $scope.username,
email: $scope.email
}).then(function(res){
//all good user was created
}, function(err){
//error, failed to create user
if (err.status === 409){
//email already exists
}
});
}
}]).service('CRUDService', ['$http', function($http){
this.createUser = function(postData){
return $http.post('/formData', postData);
}
}]);

GET route isn't being hit in angular app

I am trying to implement a persistent login for an angular application. By persistent I mean I am able to redirect to a new page or refresh without being logged out.
Looking at the debugger it does not appear that my /api/users route is ever being hit. api/sessions is and im not sure why the other one wouldn't be.
my code is:
routes.js
app.post('/api/sessions', function(req, res, next) {
User.findOne({username: req.body.username})
.select('password').select('username')
.exec( function(err, user){
if (err) {return next(err)}
if (!user) {return res.send(401)}
bcrypt.compare(req.body.password, user.password, function (err, valid){
if (err) {return next(err)}
if (!valid) {return res.send(401)}
var token = jwt.encode({username: user.username}, config.secret)
res.send(token)
})
})
})
app.get('/api/users', function(req, res, next) {
if(!req.headers['x-auth']){
return res.send(401)
}
var auth = jwt.decode(req.headers['x-auth'], config.secret)
User.findOne({username: auth.username}, function (err,user){
if (err) {return next(err)}
res.json(user)
})
})
app.post('/api/users', function(req, res, next) {
var user = new User({username: req.body.username})
bcrypt.hash(req.body.password, 10, function (err, hash){
if (err) {return next (err)}
user.password = hash
user.save(function (err){
res.send(201)
})
})
})
angular.js
app.service('UserSvc', function($http, $window){
var svc = this;
svc.getUser = function() {
return $http.get('/api/users',{
headers: { 'X-Auth': this.token }
})
}
svc.login = function(username, password){
return $http.post('/api/sessions', {
username: username, password: password
}).then(function(val){
svc.token = val.data
// window.localStorage.token = val.data
return svc.getUser()
})
}
svc.logout = function() {
$http.post('/api/sessions', {
username: null, password: null
}).then(function(val){
svc.token = null
// window.localStorage.token = val.data
})
}
})
app.controller('LoginCtrl', function($scope, $location, UserSvc){
$scope.login = function(username, password) {
UserSvc.login(username, password)
.then(function(response) {
$scope.$emit('login', response.data)
$location.path('/dashboard');
})
}
$scope.logout = function() {
UserSvc.logout();
$scope.$emit('logout')
}
});
app.controller('ApplicationCtrl', function($scope, UserSvc) {
angular.element(document).ready(function () {
$scope.currentUser = UserSvc.getUser();
})
$scope.modalShown = true;
$scope.$on('login', function (_, user){
$scope.currentUser = user;
})
$scope.$on('logout', function (){
$scope.currentUser = null;
})
});
if anyone has any pointers please let me know! I have spent way to much time on this :(
I believe the problem is rather simple here.
Services need to be instantiated (with new UserSvc).
Factories do not. So if you wanted it to use it the way you are, change UserSvc to be a factory and have it return svc.
Other thing to note would be that Factories/Services are singletons, so returning the svc, along with a variable holding the resultant user object will persist through angular router traversal but not on a page refresh. For that you would want to store the user in sessionStorage on the client (or in localStorage with some sort of timeout).

Resources