UNPKG

5.41 kBtext/coffeescriptView Raw
1# Description:
2# Fitbit leaderboards
3#
4# Dependencies:
5# "fitbit-node": "^2.0.2"
6# "moment": "^2.14.1"
7#
8# Configuration:
9# FITBIT_CLIENT_ID
10# FITBIT_CLIENT_SECRET
11# FITBIT_OAUTH_TOKEN
12#
13# Commands:
14# hubot fitbit leaders - Show table of leaders
15# hubot fitbit register - Show how to friend the bot
16# hubot fitbit approve - Approve all pending requests
17#
18# Notes:
19# To obtain/set the FITBIT_OAUTH_TOKEN, you will need to visit the "Implicit"
20# authorization URL. This will grant you a non-refreshable token for a year.
21#
22# Authors:
23# stephenyeargin, hogepodge
24
25Util = require 'util'
26moment = require 'moment'
27
28module.exports = (robot) ->
29 FitbitApiClient = require 'fitbit-node'
30 Fitbit = new FitbitApiClient(
31 clientId: process.env.FITBIT_CLIENT_ID,
32 clientSecret: process.env.FITBIT_CLIENT_SECRET,
33 apiVersion: '1.2'
34 )
35 accessToken = process.env.FITBIT_OAUTH_TOKEN
36
37 # Default action
38 robot.respond /fitbit$/i, (msg) ->
39 getLeaderboard(msg)
40
41 # Set up or renew the token
42 robot.respond /fitbit (?:token|setup)$/i, (msg) ->
43 url = "" +
44 "https://www.fitbit.com/oauth2/authorize?response_type=token" +
45 "&client_id=#{process.env.FITBIT_CLIENT_ID}" +
46 "&redirect_uri=<YOUR REDIRECT URL>" +
47 "&scope=profile%20social&expires_in=31536000"
48 msg.send """
49 1) Go to: #{url}
50 2) Save the URL token in the bot's configuration
51 3) Restart Hubot to load configuration
52 """
53
54 # Show the top five users
55 robot.respond /fitbit (steps|leaderboard|leaders)/i, (msg) ->
56 getLeaderboard(msg)
57
58 # Who are my friends?
59 robot.respond /fitbit friends/i, (msg) ->
60 Fitbit.get('/friends.json', accessToken)
61 .then (res) ->
62 responseBody = getResponseBody(res)
63 responseHeaders = getResponseHeaders(res)
64 return displayErrors(responseBody, msg) if responseHeaders.statusCode != 200
65 friends = responseBody.friends
66 if friends.length > 0
67 list = []
68 for own key, friend of friends
69 list.push "#{friend.user.displayName}"
70 msg.send list.join(", ")
71 else
72 msg.send "You have no friends on Fitbit. :("
73 .catch (error) ->
74 displayErrors(error, msg)
75
76 # See how to friend the bot
77 robot.respond /fitbit register/i, (msg) ->
78 Fitbit.get('/profile.json', accessToken)
79 .then (res) ->
80 responseBody = getResponseBody(res)
81 responseHeaders = getResponseHeaders(res)
82 return displayErrors(responseBody, msg) if responseHeaders.statusCode != 200
83 user = responseBody.user
84 unless user.fullName
85 user.fullName = 'the bot'
86 userId = user.encodedId
87 msg.send """
88 1) Add #{user.fullName} as a friend - http://fitbit.com/user/#{userId}
89 2) Type `#{robot.name} fitbit approve`
90 """
91 .catch (error) ->
92 displayErrors(error, msg)
93
94 # Approve existing friend requests
95 robot.respond /fitbit approve/i, (msg) ->
96 Fitbit.get('/friends/invitations.json', accessToken)
97 .then (res) ->
98 responseBody = getResponseBody(res)
99 responseHeaders = getResponseHeaders(res)
100 return displayErrors(responseBody, msg) if responseHeaders.statusCode != 200
101 if responseBody.friends.length is 0
102 msg.send "No pending requests."
103 return
104 for own key, friend of getResponseBody(res).friends
105 params =
106 accept: true
107 Fitbit.post(
108 "/friends/invitations/#{friend.user.encodedId}.json",
109 accessToken,
110 params
111 )
112 .then (res) ->
113 robot.logger.debug getResponseBody(res)
114 msg.send "Approve: #{friend.user.displayName}"
115 .catch (error) ->
116 displayErrors(error, msg)
117 .catch (error) ->
118 displayErrors(error, msg)
119
120 getLeaderboard = (msg) ->
121 try
122 Fitbit.get('/friends/leaderboard.json', accessToken)
123 .then (res) ->
124 responseBody = getResponseBody(res)
125 responseHeaders = getResponseHeaders(res)
126 return displayErrors(responseBody, msg) if responseHeaders.statusCode != 200
127 leaders = responseBody.friends
128 finalLeaders = []
129 for own key, leader of leaders
130 robot.logger.debug leader
131 if leader.summary.steps > 0
132 # Show a time-ago if user hasn't synced
133 if moment(leader.lastUpdateTime) < moment().subtract(1, 'days')
134 lastSync = " (#{moment(leader.lastUpdateTime).fromNow()})"
135 else
136 lastSync = ''
137 rank = leader.rank.steps * 1 # force conversion to a number
138 displayName = leader.user.displayName || 'Unknown'
139 steps = formatThousands(leader.summary.steps) || 0
140 finalLeaders[rank] = "##{rank} #{displayName} - #{steps}#{lastSync}"
141 msg.send finalLeaders.join("\n")
142 .catch (error) ->
143 displayErrors(error, msg)
144 catch err
145 msg.send "Unable to retrieve leaderboard."
146
147 getResponseBody = (res) ->
148 return res[0]
149
150 getResponseHeaders = (res) ->
151 return res[1]
152
153 displayErrors = (err, msg) ->
154 for own key, error of err.errors
155 if error.errorType == 'expired_token'
156 msg.send "Your Fitbit token has expired! See `#{robot.name} fitbit token` to set up a new one."
157 else
158 robot.logger.error err
159 msg.send error.message
160
161 formatThousands = (num) ->
162 return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")