Skip to content
This repository has been archived by the owner on Aug 22, 2023. It is now read-only.

Commit

Permalink
First (pre-)release version, login works, only shows list of runs, no…
Browse files Browse the repository at this point in the history
… export yet.
  • Loading branch information
eagereyes committed Jul 9, 2012
1 parent dbdaf2b commit 5aceb9c
Show file tree
Hide file tree
Showing 10 changed files with 177 additions and 77 deletions.
7 changes: 7 additions & 0 deletions ReadMe.md
@@ -0,0 +1,7 @@
# Dependencies

* [express](http://expressjs.com/)
* [jade](http://jade-lang.com/)
* [connect-memcached](https://github.com/balor/connect-memcached)
* [queue-async](https://github.com/mbostock/queue)
* [mysql](https://github.com/felixge/node-mysql)
20 changes: 11 additions & 9 deletions app.js
Expand Up @@ -4,7 +4,7 @@
*/

var express = require('express')
, jog = require('jog')
, queue = require('queue-async')
, mysql = require('mysql')
, user = require('./user.js')
, run = require('./run.js')
Expand All @@ -15,8 +15,6 @@ var MemcachedStore = require('connect-memcached')(express);

var dbClient = mysql.createClient(dbConf);

var log = jog(new jog.FileStore('status.log'));

var app = module.exports = express.createServer();

var PORT = 5555;
Expand Down Expand Up @@ -48,15 +46,19 @@ app.configure('production', function(){

app.get('/', routes.index);

app.get('/index-login', routes.index_login);

app.get('/nike-login', function(req, res){
req.session.userID = user.newUser(dbClient, req.session.userID || -1,
req.query.nuid, req.query.oauth_token, req.query.access_token).userID;
// res.end(JSON.stringify(req.query)+'\n'+JSON.stringify(req.session));
app.get('/nike-login', function(req, res) {
req.session.userID = user.login(dbClient, req.query.nuid, req.query.oauth_token, req.query.access_token);
routes.redirectLogin(req, res);
});

app.get('/export', function(req, res) {
if (req.session.userID == undefined) {
res.render('redirect', { title: 'Redirecting ...', redirectURL: 'http://eagerfeet.org/'})
} else {
user.getActivities(req.session.userID, res);
}
});

user.loadUsers(dbClient);

app.listen(PORT, function(){
Expand Down
5 changes: 2 additions & 3 deletions package.json
Expand Up @@ -4,10 +4,9 @@
, "private": true
, "dependencies": {
"express": ">= 2.5.9"
, "jade": ">= 0.0.1"
, "jade": ">= 0.26.0"
, "mysql": ">= 0.9.6"
, "jog": ">= 0.3.0"
, "connect-memcached": ">= 0.0.3"
, "node-runkeeper": ">= 0.1.4"
, "queue-async": ">= 0.0.2"
}
}
12 changes: 6 additions & 6 deletions routes.js
Expand Up @@ -4,13 +4,13 @@
*/

exports.index = function(req, res){
res.render('index', { title: 'eagerfeet 2', login: false, userID: req.session.userID || 'nobody' })
};

exports.index_login = function(req, res){
res.render('index', { title: 'eagerfeet 2', login: true, userID: req.session.userID || 'nobody' })
if (req.session.userID != undefined) {
res.render('redirect', { title: 'Redirecting ...', redirectURL: 'http://eagerfeet.org/export'})
} else {
res.render('index', { title: 'eagerfeet'})
}
};

exports.redirectLogin = function(req, res) {
res.render('login-redirect', { title: 'Login successful', redirectURL: 'http://eagerfeet.org/index-login' })
res.render('redirect', { title: 'Login successful!', redirectURL: 'http://eagerfeet.org/export'})
}
4 changes: 4 additions & 0 deletions static/css/style.css
Expand Up @@ -9,4 +9,8 @@ div.logo {

div.nike-login {
padding-top: 10px;
}

li.run {
margin-top: .5em;
}
84 changes: 77 additions & 7 deletions user.js
Expand Up @@ -3,6 +3,37 @@ var users = {};

var maxUserID = 1000;

var https = require('https');

function serverRequest(path, params, resultFunc) {

var queryString = '';
var numParams = 0;

for (var key in params) {
if (params.hasOwnProperty(key)) {
queryString += ((numParams == 0) ? '?' : '&');
queryString += key+'='+params[key];
numParams += 1;
}
}

var options = {
host: 'api.nike.com',
path: path + queryString
};

https.get(options, function(response) {
var body = '';
response.on('data', function(chunk) {
body += chunk;
});
response.on('end', function() {
resultFunc(body);
});
});
}

exports.loadUsers = function(dbClient) {
dbClient.query('select * from Users', function(err, results, fields) {
if (err) {
Expand All @@ -17,14 +48,53 @@ exports.loadUsers = function(dbClient) {
});
}

exports.newUser = function(dbClient, userID, nikeUID, nikeOAuthToken, nikeAccessToken) {
if (userID < 0) {
userID = maxUserID;
exports.login = function(dbClient, nikeUID, nikeOAuthToken, nikeAccessToken) {
var user = null;
for (var userID in users) {
if (users[userID].nikeUID == nikeUID) {
user = users[userID];
}
}
if (user == null) {
userID = maxUserID+1;
maxUserID += 1;
var user = {userID: userID, nikeAccessToken: nikeAccessToken, nikeOAuthToken: nikeOAuthToken, nikeUID: nikeUID};
dbClient.query('insert into Users (userID, nikeUID, nikeOAuthToken, nikeAccessToken) values (?,?,?,?);',
[userID, nikeUID, nikeOAuthToken, nikeAccessToken]);
users[userID] = user;
}
var user = {userID: userID};
dbClient.query('replace into Users values (?,?,?,?);', [user.userID, nikeUID, nikeOAuthToken, nikeAccessToken]);
users[userID] = user;
return user;
return user.userID;
}

function getUser(userID) {
return users[userID];
}

exports.getUser = getUser;

function pad(num) {
return (num < 10) ? ('0' + num) : ('' + num);
}

exports.getActivities = function(userID, res) {
var user = getUser(userID);
serverRequest('/partner/sport/run/activities', {access_token: user.nikeAccessToken, start: 0, end: 100}, function(data) {
var activities = JSON.parse(data).activities;
activities.reverse();
activities.forEach(function(run) {
var seconds = run.activity.metrics.totalDuration/1000;
if (seconds < 60 * 60) {
var minutes = Math.floor(seconds/60);
seconds -= minutes*60;
run.time = pad(minutes)+':'+pad(seconds);
} else {
var hours = Math.floor(seconds/3600);
seconds -= hours*3600;
var minutes = Math.floor(seconds/60);
seconds -= minutes*60;
run.time = pad(hours)+':'+pad(minutes)+':'+pad(seconds);
}
});
res.render('export', {activities: activities});
});
}
20 changes: 20 additions & 0 deletions views/export.jade
@@ -0,0 +1,20 @@
extends layout

block append main
div.row
div.span8
h1 Export

p A list of your runs on Nike+ (only shows the 100 most recent for now):
div#runs
ul
each run in activities
li.run #{run.activity.name},
- var miles = (run.activity.metrics.totalDistance/1.609344).toFixed(2)
- var kms = run.activity.metrics.totalDistance.toFixed(2)
| #{miles} mi / #{kms} km in #{run.time}, #{run.activity.metrics.totalCalories} calories
if run.activity.metrics.averageHeartRate > 0
i.icon-heart
// p Checking for new runs ...
// div#progressbar.progress.progress-striped.active
// div.bar(style="width: 100%;")
46 changes: 20 additions & 26 deletions views/index.jade
@@ -1,28 +1,22 @@
extends layout

block append content
div.container
div.row
div.logo.span12
img(src='/img/header.png', width='820', height='110')
div.row
div.span8
h1 Welcome to #{title}!
if (login)
if (userID != 'nobody')
p User #{userID}
div.nike-login
script(id="nikeoauth",
data-clientid="54dff1e61f4ac4a56c98ad57ef3ed377",
data-userid="#{userID}",
src="https://www.nike.com/profile/assets/oauth/js/nikeoauth.min.js")
div#runs
else
p This site is currently being rewritten from scratch to work with Nike's new authenticaton scheme and to make it easier to add more features later. Please
a(href='http://blog.eagerfeet.org/')
| check out the blog
| or
a(href='http://twitter.com/eagerfeet')
| follow me on twitter
| for updates.
p The login issues are largely solved, but I am struggling with some other parts of the site's backend right now (and lack of time). I will post on the blog and on Twitter when the new site is ready for you to test. Please bear with me a few more days, the site will be back soon.
block append main
div.row
div.logo.span12
img(src='/img/header.png', width='820', height='110')
div.row
div.span8
h1 Welcome to eagerfeet, Limited Preview Edition!
p Please use the button below to log in using your Nike+ credentials. Once logged in, you will see a list of your most recent runs. You will not be able to actually export those runs at this point, but you will be in a few days.
p For more details and updates,
a(href='http://blog.eagerfeet.org/')
| check out the blog
| or
a(href='http://twitter.com/eagerfeet')
| follow me on twitter
| .
div.nike-login
script(id="nikeoauth",
data-clientid="54dff1e61f4ac4a56c98ad57ef3ed377",
data-userid="nobody",
src="https://www.nike.com/profile/assets/oauth/js/nikeoauth.min.js")
51 changes: 27 additions & 24 deletions views/layout.jade
@@ -1,12 +1,12 @@
!!! html
doctype html
html(lang="en")
head
meta(charset='utf-8')
title= title
block head
title eagerfeet
link(rel='stylesheet', href='/css/bootstrap-2.0.4.min.css')
link(rel='stylesheet', href='/css/style.css')
block header
meta(name='viewport', content='width=device-width, initial-scale=1.0')
link(rel='stylesheet', href='/css/bootstrap-2.0.4.min.css')
link(rel='stylesheet', href='/css/style.css')
//- Le HTML5 shim, for IE6-8 support of HTML5 elements
//if lt IE 9
script(src='http://html5shim.googlecode.com/svn/trunk/html5.js')
Expand All @@ -28,22 +28,25 @@ html(lang="en")
a(href='/') Home
li
a(href='http://blog.eagerfeet.org/') blog
//- Tracking code, please remove if you use this somewhere else!
script(src='http://static.getclicky.com/js', type='text/javascript')
script(type='text/javascript') try{ clicky.init(66409777); }catch(e){}
noscript
p
img(alt='Clicky', width='1', height='1', src="http://in.getclicky.com/66409777ns.gif')
script(type='text/javascript')
| var _gauges = _gauges || [];
| (function() {
| var t = document.createElement('script');
| t.type = 'text/javascript';
| t.async = true;
| t.id = 'gauges-tracker';
| t.setAttribute('data-site-id', '4ef430c8613f5d6715000004');
| t.src = '//secure.gaug.es/track.js';
| var s = document.getElementsByTagName('script')[0];
| s.parentNode.insertBefore(t, s);
| })();
//- End of tracking code
div.container
block main

//- Tracking code, please remove if you use this somewhere else!
script(src='http://static.getclicky.com/js', type='text/javascript')
script(type='text/javascript') try{ clicky.init(66409777); }catch(e){}
noscript
p
img(alt='Clicky', width='1', height='1', src="http://in.getclicky.com/66409777ns.gif')
script(type='text/javascript').
var _gauges = _gauges || [];
(function() {
var t = document.createElement('script');
t.type = 'text/javascript';
t.async = true;
t.id = 'gauges-tracker';
t.setAttribute('data-site-id', '4ef430c8613f5d6715000004');
t.src = '//secure.gaug.es/track.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(t, s);
})();
//- End of tracking code
5 changes: 3 additions & 2 deletions views/login-redirect.jade → views/redirect.jade
@@ -1,7 +1,8 @@
extends layout

block head
block header
meta(http-equiv='Refresh', content='0; url=#{redirectURL}')

block content
h1 Login successful, hooray!
div.container
h1 #{title}

0 comments on commit 5aceb9c

Please sign in to comment.