I am using Node JS with express and I want to create a new user in my db with a REST call if the user logs in successfully with facebook. This code is just a slight modification of the heroku node.js facebook app : https://github.com/heroku/facebook-template-nodejs/blob/master/web.js
Here's what i've tried
//create Parse Object
var parse_app_id = process.env.PARSE_APP_ID;
var parse_master_key = process.env.PARSE_MASTER_KEY;
var nodeParse = new Parse(parse_app_id, parse_master_key);
function handle_facebook_request(req, res) {
// if the user is logged in
if (req.facebook.token) {
async.parallel([
function(cb) {
// query 4 friends and send them to the socket for this socket id
req.facebook.get('/me/friends', { limit: 4 }, function(friends) {
req.friends = friends;
cb();
});
},
function(cb) {
// query 16 photos and send them to the socket for this socket id
req.facebook.get('/me/photos', { limit: 16 }, function(photos) {
req.photos = photos;
cb();
});
}
], function() {
render_page(req, res);
nodeParse.signUp('',{ username: 'tajmahal', password: 'stuff'}, function(err, response) {
console.log(response);
});
});
}
}
app.get('/', handle_facebook_request);
app.post('/', handle_facebook_request);
handle_facebook_request is executed when the app is requested...everything works fine besides the user creation.
signUp creates a user when its outside of the conditional (so the function works)
How can I fix this?
Related
I'm new to node
I have a PHP/Laravel cms and I have a simple Nodejs game server which is basically a loop generating some numbers
I connect my PHP backend to Nodejs via Socketio and use Socketio-JWT to identify the user
my client side (php/laravel)
PHP
$userToken = JWTAuth::customClaims(['userid' => Auth::user()->id, 'name' => Auth::user()->name, 'avatar' => asset_url('image/avatar-default.png')])->fromUser(Auth::user() );
html/js
var socket = io.connect("http://localhost:666");
socket.on('connect', function () {
socket.emit('authenticate', {token: '{{$userToken}}'});
});
socket.on('authenticated', function () {
console.log('Authenticated');
});
socket.on('unauthorized', function (data) {
console.log('Unauthorized, error msg: ' + data.message);
});
my serverside
const _online_users = { };
io.sockets
.on('connection', socketioJwt.authorize({
secret: JWT_SECRET,
timeout: 15000
}))
.on('authenticated', function(socket) {
_online_users[socket.decoded_token.userid] = {
name : socket.decoded_token.name ,
avatar : socket.decoded_token.avatar ,
}
io.sockets.emit('update_online_users' , _online_users );
socket.on('disconnect', function() {
console.log(`----- ##disconnect -----`)
});
}) ;
as you can see I have an object called _online_users and I store authenticated users in this object and then I send it to the clients so they know who is online
io.sockets.emit('update_online_users' , _online_users );
here is the problem, when the user gets disconnected
socket.on('disconnect', function() {
console.log(`----- ##disconnect -----`)
});
I have to update my _online_users object and remove disconnected user .... how should I go about this? I was thinking maybe I can store the token itself in the _online_users
_online_users[socket.decoded_token.userid] = {
token : socket.token ,
name : socket.decoded_token.name ,
avatar : socket.decoded_token.avatar ,
}
and when the user gets disconnected I get the disconnected token from the socket and remove the user from an object by that token
of course, this is all theory! I'm not sure if that's the way to go .... first of all, I can't access the token itself from the socket !
or let's say one of the users sends another request to node server, how can I identify the user sending the request?
.on('authenticated', function(socket) {
socket.on('somaction', function() {
console.log(` who is this guy ? `)
});
})
is there anything unique insocket.decoded_token that I can use as id? if so I can store it in the online users send it back and forth when the user requests something
basically I'm lost and appreciate any pointers
You can use a middleware now in the newer versions of socket-io. So you can check if the user is logged in by the jwt token that is sent with the request. If decoded successfully you can assign the user info to the current socket and call next() and go to the event you are listening for. Here is the example provided in the socket-io docs slightly modified for your case.
io.use(function(socket, next) {
const handshakeData = socket.request;
// make sure the handshake data looks good as before
// if error do this:
// next(new Error('not authorized'));
// else decode jwt token here and append the user to the socket.request
// and call next
// pseudo code here
const {
authorization
} = handshakeData.header
let token;
if (authorization && authorization.split(" ")[0] === "Bearer") {
token = authorization.split(" ")[1]
}
let user = jwt.decode(token, secret);
socket.request.user = user;
next();
});
You are doing well!
Since you are adding socket event handlers in the 'authenticated' handler you still have access to socket.decoded_token.userid.
This should be enough:
const _online_users = {};
io.sockets
.on('connection', socketioJwt.authorize({
secret: JWT_SECRET,
timeout: 15000
}))
.on('authenticated', function(socket) {
_online_users[socket.decoded_token.userid] = {
name: socket.decoded_token.name,
avatar: socket.decoded_token.avatar,
};
io.sockets.emit('update_online_users', _online_users);
socket.on('disconnect', function() {
console.log(`----- ##disconnect -----`);
delete _online_users[socket.decoded_token.userid];
io.sockets.emit('update_online_users', _online_users);
});
});
or to be a little more concise:
const _online_users = {};
io.sockets
.on('connection', socketioJwt.authorize({
secret: JWT_SECRET,
timeout: 15000
}))
.on('authenticated', function(socket) {
const { avatar, name, userid } = socket.decoded_token;
_online_users[userid] = { name, avatar };
io.sockets.emit('update_online_users', _online_users);
socket.on('disconnect', function() {
delete _online_users[userid];
io.sockets.emit('update_online_users', _online_users);
});
socket.on('any other event...', function() {
// ... still have access to userid
});
});
Edit: About unauthenticated socket I don't know; doc says nothing. You could try something like:
io.socket.on('connection', socket => {
socket.emit('update_online_users', _online_users);
// I'm afraid this closes the socket if unauthorized, you could check by yourself
socketioJwt.authorize({
secret: JWT_SECRET,
timeout: 15000
})(socket);
}).on('authenticated', socket => {
//...
});
Hope this helps.
I am new to mongodb and Hapi.js. I am trying to create an API for read requests, but am not sure how to write the handler method in server.route.
Here's how I have my mongoclient configured with hapi:
'use strict';
var MongoClient = require('mongodb').MongoClient; //using version 3.x
var Hapi = require('hapi');//using v16
var url = 'mongodb://****:****#ds131687.mlab.com:31687/learning_mongo';
var db;
var server = new Hapi.Server();
server.connection({
port:8080
});
server.route( [
// Get tour list
{
method: 'GET',
path: '/api/tours',
handler: function(request, reply){
collection.find().toArray(function(err,tours){
reply(tours);
});
}
},
// Home page
{
method: 'GET',
path: '/',
handler: function(request, reply) {
reply( "Hello world from Hapi/Mongo example.");
}
}
]);
var tours = function(db, callback) {
var collection = db.collection('tours');
collection.find().toArray(function(err, docs){
console.log(docs);
callback;
});
};
MongoClient.connect(url, function(err,client) {
server.start(function(err) {
tours(client.db('learning_mongo'), function(){
console.log('Hapi is listening to http://localhost:8080');
client.close();
});
});//end server
})
Going to the homepage path works fine, but when I go to ./api/tours path, I get the following error in terminal:
Debug: internal, implementation, error
ReferenceError: Uncaught error: collection is not defined
at handler (/home/ubuntu/workspace/index.js:22:13)
at Object.internals.handler (/home/ubuntu/workspace/node_modules/hapi/lib/handler.js:101:51)
at request._protect.run (/home/ubuntu/workspace/node_modules/hapi/lib/handler.js:32:23)
at module.exports.internals.Protect.internals.Protect.run (/home/ubuntu/workspace/node_modules/hapi/lib/protect.js:60:12)
at exports.execute (/home/ubuntu/workspace/node_modules/hapi/lib/handler.js:26:22)
at each (/home/ubuntu/workspace/node_modules/hapi/lib/request.js:401:16)
at iterate (/home/ubuntu/workspace/node_modules/items/lib/index.js:36:13)
at done (/home/ubuntu/workspace/node_modules/items/lib/index.js:28:25)
at module.exports.internals.Auth.internals.Auth._authenticate (/home/ubuntu/workspace/node_modules/hapi/lib/auth.js:222:16)
at internals.Auth.authenticate (/home/ubuntu/workspace/node_modules/hapi/lib/auth.js:197:17)
How do I correctly define the collection ? Thank you.
Your error message means that collection is out of scope inside the handler. You declare it inside the tours function.
But you also got have a minor error how you approach the database and the collection with the Mongoclient.
Let me show you how it would work while keeping your general set-up. There you can see that db can be accessed by the handler now.
'use strict';
var MongoClient = require('mongodb').MongoClient; //using version 3.x
var Hapi = require('hapi'); //using v16
var url = 'mongodb://****:****#ds131687.mlab.com:31687/';
var db;
var server = new Hapi.Server();
server.connection({
port: 8080
});
server.route([
// Get tour list
{
method: 'GET',
path: '/api/tours',
handler: function(request, reply) {
db.collection('tours').find().toArray(function(err, tours) {
reply(tours);
});
}
},
// Home page
{
method: 'GET',
path: '/',
handler: function(request, reply) {
reply("Hello world from Hapi/Mongo example.");
}
}
]);
var tours = function(db, callback) {
db.collection('tours').find().toArray(function(err, docs) {
console.log(docs);
callback;
});
};
new MongoClient.connect(url, function(err, client) {
db = client.db('learning_mongo')
server.start(function(err) {
tours(db, function() {
console.log('Hapi is listening to http://localhost:8080');
client.close();
});
}); //end server
})
I understand that this is only a learning example from your side. But maybe you want to consider starting with the latest hapijs version: 17. There are some bigger changes involved and it makes your life easier starting with that version now. Your short code has already lot of nested callbacks. Version 17 will support using await/async.
Following is the Server.js File, here I am Fetching The Details From Table which working Good. I need to Get a Variable From k.php which is in the Same Folder.Iam using npm exec-php module to get the Values From Php File. But The Variable is Showing Undefined.
var app = require('http').createServer(handler),
io = require('socket.io').listen(app),
fs = require('fs'),
express=require('express'),
session=require('express-session'),
mysql = require('mysql'),
execPhp = require('exec-php'),
connectionsArray = [],
connection = mysql.createConnection({
host: 'localhost',
user: 'root',
password: '',
database: 'test',
port: 3306
}),
POLLING_INTERVAL = 3000,
pollingTimer;
// If there is an error connecting to the database
connection.connect(function(err) {
// connected! (unless `err` is set)
if (err) {
console.log(err);
}
});
// creating the server ( localhost:8000 )
app.listen(8000);
// on server started we can load our client.html page
function handler(req, res) {
fs.readFile(__dirname + '/client.php', function(err, data) {
if (err) {
console.log(err);
res.writeHead(500);
return res.end('Error loading client.php');
}
res.writeHead(200);
res.end(data);
});
}
execPhp('k.php', function(error, php, outprint){
// Here I expected The outprint Will be 'One' but it print undefined
console.log(outprint);
php.my_function(1, 2, function(err, result, output, printed){
//this my_function is also showing Error
});
});
var pollingLoop = function() {
// Doing the database query
var query = connection.query('SELECT * FROM users where user_id=1'),
users = []; // this array will contain the result of our db query
// setting the query listeners
query
.on('error', function(err) {
// Handle error, and 'end' event will be emitted after this as well
console.log(err);
updateSockets(err);
})
.on('result', function(user) {
// it fills our array looping on each user row inside the db
users.push(user);
})
.on('end', function() {
// loop on itself only if there are sockets still connected
if (connectionsArray.length) {
pollingTimer = setTimeout(pollingLoop, POLLING_INTERVAL);
updateSockets({
users: users
});
} else {
console.log('The server timer was stopped because there are no more socket connections on the app')
}
});
};
// creating a new websocket to keep the content updated without any AJAX request
io.sockets.on('connection', function(socket) {
console.log('Number of connections:' + connectionsArray.length);
// starting the loop only if at least there is one user connected
if (!connectionsArray.length) {
pollingLoop();
}
socket.on('disconnect', function() {
var socketIndex = connectionsArray.indexOf(socket);
console.log('socketID = %s got disconnected', socketIndex);
if (~socketIndex) {
connectionsArray.splice(socketIndex, 1);
}
});
console.log('A new socket is connected!');
connectionsArray.push(socket);
});
var updateSockets = function(data) {
// adding the time of the last update
data.time = new Date();
console.log('Pushing new data to the clients connected ( connections amount = %s ) - %s', connectionsArray.length , data.time);
// sending new data to all the sockets connected
connectionsArray.forEach(function(tmpSocket) {
tmpSocket.volatile.emit('notification', data);
});
};
console.log('Please use your browser to navigate to http://localhost:8000');
the main Problem is in these Lines
execPhp('k.php', function(error, php, outprint){
// Here I expected The outprint Will be 'One' but it print undefined
console.log(outprint);
php.my_function(1, 2, function(err, result, output, printed){
//this my_function is also showing Error
});
});
The Following is k.php in the same folder
<?php
echo "One";
function my_function($arg1, $arg2){
echo "Two";
return $arg1 + $arg2;
}
?>
This is the Error
I'm trying to register TAKE_A_NOTE with the 'mirror-api-subscription' event listener. I'm not having any luck: I can launch take a note with "my app", however, there's no console log that the event has been recognized.
I would like to recognize when the TAKE_A_NOTE function has occurred or finished, and handle the response afterwards. I do not know whether the subscription should be on a stream or if I am implementing the EventListener in a faulty manner. Your help would be greatly appreciated.
The code I am utilizing is:
// references
// http://www.recursiverobot.com/post/57348836217/getting-started-with-the-mirror-api-using-node-js
// https://www.npmjs.org/package/mirror-api-subscription
var express = require('express')
, http = require('http')
, https = require('https')
, fs = require('fs')
, googleapis = require('googleapis')
, OAuth2Client = googleapis.OAuth2Client;
var app = express();
var oauth2Client = new OAuth2Client(process.env.MIRROR_DEMO_CLIENT_ID,
process.env.MIRROR_DEMO_CLIENT_SECRET, process.env.MIRROR_DEMO_REDIRECT_URL);
// all environments
app.set('port', 8888);
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(app.router);
var gotToken = function () {
googleapis
.discover('mirror', 'v1')
.execute(function (err, client) {
if (!!err) {
failure();
return;
}
insertContact(client, failure, success);
insertSubscription(client, failure, success);
});
};
var insertContact = function (client, errorCallback, successCallback) {
client
.mirror.contacts.insert({
"id": "myapp",
"displayName": "myApp",
"priority": 100,
"acceptCommands": [
{"type": "TAKE_A_NOTE"}
],
"speakableName":"my app"
})
.withAuthClient(oauth2Client)
.execute(function (err, data) {
if (!!err)
errorCallback(err);
else
successCallback(data);
});
};
var insertSubscription = function (client, errorCallback, successCallback) {
client.mirror.subscriptions.insert({
"callbackUrl":"https://localhost:7777/notification",
"collection":"timeline",
"userToken":"001",
"verifyToken":"secret",
"operation":["INSERT"]
});
}
var subscription = require('mirror-api-subscription')(
function () {
})
subscription.on('locations#UPDATE',
function (notification, user, payload) {
console.log('location of user %s updated', user.id)
})
subscription.on('timeline#INSERT:LAUNCH',
function (notification, user, payload) {
console.log('subscription timeline#INSERT:LAUNCH')
})
subscription.on('timeline#UPDATE:CUSTOM',
function (notification, user, payload) {
console.log('subscription timeline#UPDATE:CUSTOM')
})
app.post('/notification', subscription.dispatcher())
app.get('/', function (req, res) {
if (!oauth2Client.credentials) {
// generates a url that allows offline access and asks permissions
// for Mirror API scope.
var url = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: 'https://www.googleapis.com/auth/glass.timeline'
});
res.redirect(url);
} else {
gotToken();
}
res.write('Glass Mirror API with Node');
res.end();
});
app.get('/oauth2callback', function (req, res) {
// if we're able to grab the token, redirect the user back to the main page
grabToken(req.query.code, failure, function () {
res.redirect('/');
});
});
app.post('/reply', function(req, res){
console.log('replied',req);
res.end();
});
var options = {
key: fs.readFileSync('./ssl/key.pem'),
cert: fs.readFileSync('./ssl/cert.pem'),
};
https.createServer(options, app).listen(7777, function() {
console.log('https listening on 7777');
});
http.createServer(app).listen(app.get('port'), function () {
console.log('Express server listening on port ' + app.get('port'));
});
There are at least two potential problems with your code:
The callbackUrl must be an internet accessible HTTPS address. "Localhost" isn't good enough, since Google's servers need to be able to resolve it. You can provide an IP address, if you have a public IP address, or use a tunnel.
You don't do anything with the result of the call to client.mirror.subscriptions.insert(). Typically, you should call it the same way you call client.mirror.contacts.insert(), which is to chain it with withAuthClient() and execute(). You'll need to call execute() if you expect it to register with the Mirror service. See https://github.com/google/google-api-nodejs-client/ for documentation about the "googleapis" package and discovery service
Possibly related to #2, but I'm not familiar with the package you're including with require('mirror-api-subscription'), which seems to handle things differently than the "googleapis" package and discovery service it offers. From the reference documentation for it, however, it isn't clear that it actually sets up the callback anywhere and is just there to verify the callbacks and dispatch to functions that do the work.
var insertSubscription = function (client, errorCallback, successCallback) {
client.mirror.subscriptions.insert({
"callbackUrl":"https://mirrornotifications.appspot.com/forward?url=callbackURL",
"collection":"timeline",
"userToken":"001",
"verifyToken":"secret",
"operation":["INSERT"]
}).withAuthClient(oauth2Client).execute(function (err, data) {
if (!!err)
errorCallback(err);
else
successCallback(data);
});
};
I am using Node.js, Express, MongoDB, and Mongoose. I have a function that fetches the largest id number of a document in my MongoDB database and returns it to the program. I have begun modularizing my code, and have migrated that function to another module. I have successfully accessed the function in my main module, but it involves an asynchronous database query. As the function returns a value, I want to assign it to a variable. Unfortunately, When the returned value is assigned to the variable, the variable is actually set to undefined. I was thinking about using event emitters to signal that the query is finished, but that presents two issues as well:
1) I don't think you can do anything in a program AFTER a return statement, which would be what is required.
2) Event Emitters between modules seem very finicky.
Please help me get the variable to be assigned to the correct value. Code for both the main function and the module is below:
(main file) app.js:
//requires and start up app
var express = require('express');
var mongoose = require('mongoose')
, dbURI = 'localhost/test';
var app = express();
var postmodel = require('./models/post').postmodel;
//configures app for general stuff needed such as bodyParser and static file directory
app.configure(function () {
app.use(express.bodyParser());
app.use(express.static(__dirname + '/static'));
});
//configures app for production, connects to mongoLab databse rather than localhost
app.configure('production', function () {
dbURI = 'mongodb://brad.ross.35:lockirlornie#ds037387.mongolab.com:37387/heroku_app6901832';
});
//tries to connect to database.
mongoose.connect(dbURI);
//once connection to database is open, then rest of app runs
mongoose.connection.on('open', function () {
var PostModel = new postmodel();
var Post = PostModel.setupPostSchema();
var largest_id = PostModel.findLargestID(Post);
(module) post.js:
var mongoose = require('mongoose');
module.exports.postmodel = function () {
this.setupPostSchema = function () {
var postSchema = new mongoose.Schema({
title: String,
body: String,
id: Number,
date_created: String
});
var Post = mongoose.model('Post', postSchema);
return Post;
};
this.findLargestID = function (Post) {
Post.find(function (err, posts) {
if (err) {
console.log("error finding largest ID!");
} else {
var largest_id = 0;
for (var post in posts) {
if (posts[post].id >= largest_id) largest_id = posts[post].id;
}
console.log(largest_id);
return largest_id;
}
});
};
};
You need to have findLargestID accept a callback parameter that it will call once largest_id is available:
this.findLargestID = function (Post, callback) {
Post.find(function (err, posts) {
if (err) {
console.log("error finding largest ID!");
callback(err);
} else {
var largest_id = 0;
for (var post in posts) {
if (posts[post].id >= largest_id) largest_id = posts[post].id;
}
console.log(largest_id);
callback(null, largest_id);
}
});
};