Skip to content

Instantly share code, notes, and snippets.

@nikcorg
Last active December 14, 2015 00:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nikcorg/4997311 to your computer and use it in GitHub Desktop.
Save nikcorg/4997311 to your computer and use it in GitHub Desktop.
The produce of a HelsinkiJS mini-workshop. Pulls in the profile images of members of the HelsinkiJS group and renders them as a webpage.
// Import the required modules
var fs = require("fs");
var parseUrl = require("url").parse;
var http = require("http");
var express = require("express");
var handlebars = require("handlebars");
var Q = require("q");
var FB = require('fb');
// Read the template file from disk
var index = fs.readFileSync("index.html", "utf-8");
// Pre-compile the Handlerbars template
var template = handlebars.compile(index);
// Create an Expres.JS app
var app = express();
// Application settings
var helsinkiJSGroupId = "208755712538736";
var FBApp = {
ID: "<fb app id>",
secret: "<fb app secret>"
};
/**
* Helper for doing HTTP requests in Node.js
* @param {string} method The HTTP request method
* @param {string} url The URL to fetch
* @return {promise} Returns a (Q.js) promise/deferred
*/
function requestWithPromise(method, url) {
var def = Q.defer();
var parsed = parseUrl(url);
var opts = {
method: method,
hostname: parsed.hostname,
port: parsed.port,
path: parsed.path,
headers: {}
};
var data = "";
var req =
http.request(opts).
on("response", function (res) {
res.
on("data", function (chunk) {
data += String(chunk);
}).
on("end", function () {
def.resolve([res.statusCode, res]);
});
}).
on("error", function () {
def.reject();
}).
end();
return def.promise;
}
/**
* Request an access token from FB
* @return {promise} Returns a (Q.js) promise/deferred
*/
function getAccessToken() {
var defer = Q.defer();
FB.api('oauth/access_token', {
client_id: FBApp.ID,
client_secret: FBApp.secret,
grant_type: 'client_credentials'
}, function (res) {
if(!res || res.error) {
defer.reject(res);
return;
}
var accessToken = res.access_token;
FB.setAccessToken(accessToken);
defer.resolve();
});
return defer.promise;
}
/**
* Fetch the group member data from FB
* @return {promise} Returns a (Q.js) promise/deferred
*/
function getGroupMembers() {
var defer = Q.defer();
FB.api(helsinkiJSGroupId + "/members", function (fbres) {
if(!fbres || fbres.error) {
console.log(!fbres ? 'error occurred' : fbres.error);
defer.reject(fbres.error);
}
defer.resolve(fbres);
});
return defer.promise;
}
/**
* Returns the user id's of an array of user objects
* @param {array} res Array of user object
* @return {array} Array of user id's
*/
function extractUserIds(res) {
return res.data.map(function (user) { return user.id; });
}
/**
* Fetch a URL to a single users profile image
* @param {string} userId The user's id
* @return {string} The URL to the profile image
*/
function fetchUserProfileImage(userId) {
var defer = Q.defer();
// Not using the FB.api, because it chokes on the redirect to the image as
// it attempts to parse it as JSON. Also, we're really only interested in
// the location header in the response.
requestWithPromise("GET", "http://graph.facebook.com/" + userId + "/picture").
spread(function (status, res) {
defer.resolve(res.headers.location);
}, function () {
defer.reject("graph request failed");
});
return defer.promise;
}
/**
* Fetch URL's to a user's profile image
* @param {String} ids Array of user id's
* @return {array} Array of URL's
*/
function fetchProfileImages(ids) {
var defer = Q.defer();
var promises = ids.map(function (id) {
return fetchUserProfileImage(id);
});
Q.all(promises).
then(function (images) {
defer.resolve(images);
}, function (err) {
console.log("single profile fetch error", err);
}).
done();
return defer.promise;
}
/**
* Returns a dumb input echoing function, with a prefix message
* @param {string} msg Message to prepend
* @return {function}
*/
function makeErrH(msg) {
return function () {
console.log(msg, arguments);
};
}
// Bind a handler for the / URL (on localhost)
app.get("/", function (req, res) {
getAccessToken().
then(getGroupMembers, makeErrH("access token failed")).
then(extractUserIds, makeErrH("group data failed")).
then(fetchProfileImages, makeErrH("profile images failed")).
then(function (images) {
// Send the response
res.send(
// Render the template
template({ images: images })
);
}, function () {
res.send("Sorry, there was an error :(");
}).
done();
});
// Bind the express.js app on port 8080 on localhost
app.listen(8080);
<!doctype html>
<html>
<head>
<title>HelsinkiJS Group Members</title>
</head>
<body>
<h1>Members of the HelsinkiJS Facebook Group</h1>
{{#images}}
<img src="{{.}}">
{{/images}}
</body>
</html>
{
"name": "HSJS Workshop",
"version": "0.0.0",
"description": "HelsinkiJS Pair Programming",
"dependencies": {
"q": "*",
"handlebars": "*",
"express": "*",
"facebook-node-sdk": "Thuzi/facebook-node-sdk"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment