Integrate Strava into Slack. Hosted at slava.playplay.io.
Copyright Daniel Doubrovkine, Vestris LLC, 2018-2020
(Re)Post Strava activities to Slack
Home Page: https://slava.playplay.io
License: MIT License
Integrate Strava into Slack. Hosted at slava.playplay.io.
Copyright Daniel Doubrovkine, Vestris LLC, 2018-2020
Hi Developers,
We have been working on some exciting API changes to improve transparency and give our users more control. Read on for a summary of the upcoming changes.
OAuth and Scopes Overhaul
We have overhauled our OAuth experience to make it easier for our users to understand and control how they share their data. The overhaul included introducing new scopes, some changes to existing scopes, and new, more user-friendly OAuth pages. In addition, the email field will be removed from all scopes and from the Athlete object effective January 15th, 2019.
Read more details on scope changes at https://developers.strava.com/docs/oauth-updates/
Refresh Tokens
Beginning on October 15, 2018, we will make available a new version of the Strava OAuth flow that uses short-lived access tokens and refresh tokens.
We want to make this change easier on you, so you will have from now through October 15, 2019, to migrate to the new version of OAuth using short-lived access tokens and refresh tokens. During the migration period, existing forever access tokens will continue to work.
However, on October 15th, 2019, forever tokens will be rejected by the server and any app that has not migrated to the short-lived access tokens will lose access to the Strava API until it is updated to the new token logic.
Read up on migration details and instructions at https://developers.strava.com/docs/oauth-updates/
If you have any questions, please email us at [email protected].
Thank you,
Strava API Team
Basically do member_joined_channel
for all users already in a channel when channel_joined
.
Maybe too spammy? Let admins do that manually?
Connect a club, (re)post club activities.
Prompt users to join a club. This would also create some potential for leaderboards and such.
W, [2018-05-12T22:32:47.262086 #237] WARN -- : Error in cron for team name=..., id=..., user user_id=..., user_name=..., {"message":"Rate Limit Exceeded","errors":[{"resource":"Application","field":"rate limit","code":"exceeded"}]} [HTTP 429], /app/vendor/bundle/ruby/2.3.0/gems/strava-api-v3-0.7.0/lib/strava/api/v3/common.rb:28:in `block in api_call'
For one don't try other team members or clubs. Display a better error on slash and other commands.
It's confusing that /slava set
doesn't work.
We can display a graph with detailed activity information similar to what the app shows, in slack.
E, [2018-11-21T02:36:57.172244 #236] ERROR -- : TypeError: can't convert nil into an exact number
/app/vendor/bundle/ruby/2.3.0/gems/activesupport-5.2.1/lib/active_support/core_ext/time/calculations.rb:53:in `at'
/app/vendor/bundle/ruby/2.3.0/gems/activesupport-5.2.1/lib/active_support/core_ext/time/calculations.rb:53:in `at_with_coercion'
/app/slack-strava/models/user.rb:99:in `connect!'
/app/slack-strava/api/endpoints/users_endpoint.rb:18:in `block (2 levels) in <class:UsersEndpoint>'
/app/vendor/bundle/ruby/2.3.0/gems/grape-1.1.0/lib/grape/endpoint.rb:57:in `call'
/app/vendor/bundle/ruby/2.3.0/gems/grape-1.1.0/lib/grape/endpoint.rb:57:in `block (2 levels) in generate_api_method'
We want a #running channel for runs, etc.
Just because http://pete.fit supports it :)
Update runs with reactions for each kudo from Strava
I, [2018-11-19T01:06:44.821293 #237] INFO -- : Bragging about strava_id=...
I, [2018-11-19T01:06:44.822439 #237] INFO -- : Posting ... on #cycling.
W, [2018-11-19T01:06:44.872607 #237] WARN -- : Error in team ..., account_inactive, /app/vendor/bundle/ruby/2.3.0/gems/slack-ruby-client-0.13.1/lib/slack/web/faraday/response/raise_error.rb:11:in `on_complete'
/app/vendor/bundle/ruby/2.3.0/gems/faraday-0.15.3/lib/faraday/response.rb:9:in `block in call'
/app/vendor/bundle/ruby/2.3.0/gems/faraday-0.15.3/lib/faraday/response.rb:61:in `on_complete'
/app/vendor/bundle/ruby/2.3.0/gems/faraday-0.15.3/lib/faraday/response.rb:8:in `call'
/app/vendor/bundle/ruby/2.3.0/gems/faraday-0.15.3/lib/faraday/response.rb:8:in `call'
/app/vendor/bundle/ruby/2.3.0/gems/faraday-0.15.3/lib/faraday/request/url_encoded.rb:15:in `call'
/app/vendor/bundle/ruby/2.3.0/gems/faraday-0.15.3/lib/faraday/request/multipart.rb:15:in `call'
/app/vendor/bundle/ruby/2.3.0/gems/faraday-0.15.3/lib/faraday/rack_builder.rb:143:in `build_response'
/app/vendor/bundle/ruby/2.3.0/gems/faraday-0.15.3/lib/faraday/connection.rb:387:in `run_request'
/app/vendor/bundle/ruby/2.3.0/gems/faraday-0.15.3/lib/faraday/connection.rb:175:in `post'
/app/vendor/bundle/ruby/2.3.0/gems/slack-ruby-client-0.13.1/lib/slack/web/faraday/request.rb:25:in `request'
/app/vendor/bundle/ruby/2.3.0/gems/slack-ruby-client-0.13.1/lib/slack/web/faraday/request.rb:10:in `post'
/app/vendor/bundle/ruby/2.3.0/gems/slack-ruby-client-0.13.1/lib/slack/web/api/endpoints/chat.rb:150:in `chat_postMessage'
/app/slack-strava/models/club_activity.rb:17:in `brag!'
/app/slack-strava/models/club.rb:39:in `brag!'
/app/slack-strava/models/brag.rb:21:in `block in sync_and_brag!'
/app/slack-strava/models/brag.rb:3:in `with_strava_error_handler'
/app/slack-strava/models/brag.rb:19:in `sync_and_brag!'
/app/vendor/bundle/ruby/2.3.0/gems/mongoid-7.0.2/lib/mongoid/contextual/mongo.rb:705:in `yield_document'
/app/vendor/bundle/ruby/2.3.0/gems/mongoid-7.0.2/lib/mongoid/contextual/mongo.rb:134:in `block in each'
/app/vendor/bundle/ruby/2.3.0/gems/mongo-2.6.2/lib/mongo/collection/view/iterable.rb:46:in `block in each'
/app/vendor/bundle/ruby/2.3.0/gems/mongo-2.6.2/lib/mongo/cursor.rb:121:in `block in each'
/app/vendor/bundle/ruby/2.3.0/gems/mongo-2.6.2/lib/mongo/cursor.rb:121:in `each'
/app/vendor/bundle/ruby/2.3.0/gems/mongo-2.6.2/lib/mongo/cursor.rb:121:in `each'
/app/vendor/bundle/ruby/2.3.0/gems/mongo-2.6.2/lib/mongo/collection/view/iterable.rb:45:in `each'
/app/vendor/bundle/ruby/2.3.0/gems/mongoid-7.0.2/lib/mongoid/query_cache.rb:222:in `each'
/app/vendor/bundle/ruby/2.3.0/gems/mongoid-7.0.2/lib/mongoid/contextual/mongo.rb:133:in `each'
/app/vendor/bundle/ruby/2.3.0/gems/mongoid-7.0.2/lib/mongoid/contextual.rb:20:in `each'
/app/slack-strava/app.rb:86:in `block in brag!'
/app/vendor/bundle/ruby/2.3.0/gems/mongoid-7.0.2/lib/mongoid/contextual/mongo.rb:705:in `yield_document'
/app/vendor/bundle/ruby/2.3.0/gems/mongoid-7.0.2/lib/mongoid/contextual/mongo.rb:134:in `block in each'
/app/vendor/bundle/ruby/2.3.0/gems/mongo-2.6.2/lib/mongo/collection/view/iterable.rb:46:in `block in each'
/app/vendor/bundle/ruby/2.3.0/gems/mongo-2.6.2/lib/mongo/cursor.rb:121:in `block in each'
/app/vendor/bundle/ruby/2.3.0/gems/mongo-2.6.2/lib/mongo/cursor.rb:121:in `each'
/app/vendor/bundle/ruby/2.3.0/gems/mongo-2.6.2/lib/mongo/cursor.rb:121:in `each'
/app/vendor/bundle/ruby/2.3.0/gems/mongo-2.6.2/lib/mongo/collection/view/iterable.rb:45:in `each'
/app/vendor/bundle/ruby/2.3.0/gems/mongoid-7.0.2/lib/mongoid/query_cache.rb:222:in `each'
/app/vendor/bundle/ruby/2.3.0/gems/mongoid-7.0.2/lib/mongoid/contextual/mongo.rb:133:in `each'
/app/vendor/bundle/ruby/2.3.0/gems/mongoid-7.0.2/lib/mongoid/contextual.rb:20:in `each'
/app/slack-strava/app.rb:82:in `brag!'
/app/slack-strava/app.rb:16:in `block (2 levels) in after_start!'
/app/slack-strava/app.rb:35:in `block (2 levels) in once_and_every'
/app/slack-strava/app.rb:34:in `loop'
/app/slack-strava/app.rb:34:in `block in once_and_every'
/app/vendor/bundle/ruby/2.3.0/gems/async-1.10.3/lib/async/task.rb:74:in `block in initialize'.
Inspired by https://github.com/mateus/strava-personal-analytics. Probably quite a bit of the features there can be useful in a bot. Definitely graphing for individuals and teams.
cc: @mateus
Into all the channels that have both the user and the bot.
From #35 (comment)
E, [2018-04-03T13:29:27.407353 #232] ERROR -- : cannot_dm_bot (Slack::Web::Api::Errors::SlackError)
/app/vendor/bundle/ruby/2.3.0/gems/slack-ruby-client-0.11.1/lib/slack/web/faraday/response/raise_error.rb:11:in `on_complete'
/app/vendor/bundle/ruby/2.3.0/gems/faraday-0.14.0/lib/faraday/response.rb:9:in `block in call'
/app/vendor/bundle/ruby/2.3.0/gems/faraday-0.14.0/lib/faraday/response.rb:61:in `on_complete'
/app/vendor/bundle/ruby/2.3.0/gems/faraday-0.14.0/lib/faraday/response.rb:8:in `call'
/app/vendor/bundle/ruby/2.3.0/gems/faraday-0.14.0/lib/faraday/response.rb:8:in `call'
/app/vendor/bundle/ruby/2.3.0/gems/faraday-0.14.0/lib/faraday/request/url_encoded.rb:15:in `call'
/app/vendor/bundle/ruby/2.3.0/gems/faraday-0.14.0/lib/faraday/request/multipart.rb:15:in `call'
/app/vendor/bundle/ruby/2.3.0/gems/faraday-0.14.0/lib/faraday/rack_builder.rb:143:in `build_response'
/app/vendor/bundle/ruby/2.3.0/gems/faraday-0.14.0/lib/faraday/connection.rb:387:in `run_request'
/app/vendor/bundle/ruby/2.3.0/gems/faraday-0.14.0/lib/faraday/connection.rb:175:in `post'
/app/vendor/bundle/ruby/2.3.0/gems/slack-ruby-client-0.11.1/lib/slack/web/faraday/request.rb:25:in `request'
/app/vendor/bundle/ruby/2.3.0/gems/slack-ruby-client-0.11.1/lib/slack/web/faraday/request.rb:10:in `post'
/app/vendor/bundle/ruby/2.3.0/gems/slack-ruby-client-0.11.1/lib/slack/web/api/endpoints/im.rb:91:in `im_open'
/app/slack-strava/models/user.rb:73:in `dm!'
/app/slack-strava/server.rb:17:in `block in <class:Server>'
/app/vendor/bundle/ruby/2.3.0/gems/slack-ruby-bot-0.11.0/lib/slack-ruby-bot/hooks/set.rb:33:in `block (2 levels) in register_callback'
/app/vendor/ruby-2.3.1/lib/ruby/2.3.0/set.rb:306:in `each_key'
/app/vendor/ruby-2.3.1/lib/ruby/2.3.0/set.rb:306:in `each'
/app/vendor/bundle/ruby/2.3.0/gems/slack-ruby-bot-0.11.0/lib/slack-ruby-bot/hooks/set.rb:32:in `block in register_callback'
/app/vendor/bundle/ruby/2.3.0/gems/slack-ruby-client-0.11.1/lib/slack/real_time/client.rb:199:in `block in run_callbacks'
/app/vendor/bundle/ruby/2.3.0/gems/slack-ruby-client-0.11.1/lib/slack/real_time/client.rb:198:in `each'
/app/vendor/bundle/ruby/2.3.0/gems/slack-ruby-client-0.11.1/lib/slack/real_time/client.rb:198:in `run_callbacks'
/app/vendor/bundle/ruby/2.3.0/gems/slack-ruby-client-0.11.1/lib/slack/real_time/client.rb:177:in `dispatch'
/app/vendor/bundle/ruby/2.3.0/gems/slack-ruby-client-0.11.1/lib/slack/real_time/client.rb:93:in `block (2 levels) in run_loop'
/app/vendor/bundle/ruby/2.3.0/gems/websocket-driver-0.7.0/lib/websocket/driver/event_emitter.rb:39:in `block in emit'
/app/vendor/bundle/ruby/2.3.0/gems/websocket-driver-0.7.0/lib/websocket/driver/event_emitter.rb:38:in `each'
/app/vendor/bundle/ruby/2.3.0/gems/websocket-driver-0.7.0/lib/websocket/driver/event_emitter.rb:38:in `emit'
/app/vendor/bundle/ruby/2.3.0/gems/websocket-driver-0.7.0/lib/websocket/driver/hybi.rb:398:in `emit_message'
/app/vendor/bundle/ruby/2.3.0/gems/websocket-driver-0.7.0/lib/websocket/driver/hybi.rb:381:in `emit_frame'
/app/vendor/bundle/ruby/2.3.0/gems/websocket-driver-0.7.0/lib/websocket/driver/hybi.rb:123:in `parse'
/app/vendor/bundle/ruby/2.3.0/gems/websocket-driver-0.7.0/lib/websocket/driver/client.rb:63:in `parse'
/app/vendor/bundle/ruby/2.3.0/gems/slack-ruby-client-0.11.1/lib/slack/real_time/concurrency/celluloid.rb:61:in `handle_read'
/app/vendor/bundle/ruby/2.3.0/gems/celluloid-0.17.3/lib/celluloid/calls.rb:28:in `public_send'
/app/vendor/bundle/ruby/2.3.0/gems/celluloid-0.17.3/lib/celluloid/calls.rb:28:in `dispatch'
/app/vendor/bundle/ruby/2.3.0/gems/celluloid-0.17.3/lib/celluloid/call/async.rb:7:in `dispatch'
/app/vendor/bundle/ruby/2.3.0/gems/celluloid-0.17.3/lib/celluloid/cell.rb:50:in `block in dispatch'
/app/vendor/bundle/ruby/2.3.0/gems/celluloid-0.17.3/lib/celluloid/cell.rb:76:in `block in task'
/app/vendor/bundle/ruby/2.3.0/gems/celluloid-0.17.3/lib/celluloid/actor.rb:339:in `block in task'
/app/vendor/bundle/ruby/2.3.0/gems/celluloid-0.17.3/lib/celluloid/task.rb:44:in `block in initialize'
/app/vendor/bundle/ruby/2.3.0/gems/celluloid-0.17.3/lib/celluloid/task/fibered.rb:14:in `block in create'
Pull in comments as Slack threads
Update posts with other athletes
The user would get a DM to invite them to connect their account.
Today inviting a user to a channel that includes the bot DMs them to connect their strava account, so this sort of exists.
W, [2018-04-18T13:37:11.584032 #234] WARN -- : Error in cron for team name=***, id=TA3P0B3RS, user user_id=UA88GCZ1Q, user_name=****, {"message":"Authorization Error","errors":[{"resource":"Athlete","field":"access_token","code":"invalid"}]} [HTTP 401], /app/vendor/bundle/ruby/2.3.0/gems/strava-api-v3-0.7.0/lib/strava/api/v3/common.rb:28:in `block in api_call'
And send a notification to the user that they were disconnected.
Add a slash command that works like a DM,
Add a leaderboard of Strava activities
@slava leaderboard
...
Who has the most miles, top speed, most elevation ...
Differentiate between runs, swims, cycling, etc.
For now manual, getting the user that installed the bot.
Team.active.each do |team|
next unless team.activated_user_id
client = Slack::Web::Client.new(token: team.token)
info = client.users_info(user: team.activated_user_id)
next unless info.user && info.user.profile
puts "#{info.user.profile.display_name} <#{info.user.profile.email}>"
end; nil
That would be more useful for biking.
If a user leaves a channel they don't want their activities in it anymore.
Needs a new logo and brand identity, maybe something Soviet-style.
I, [2018-05-12T01:02:23.601854 #237] INFO -- : Connected strava_id=43749, name=Orchard Street Runners, url=https://www.strava.com/clubs/OrchardStreetRunners, channel_id=CAE55SVT7, channel_name=running, name=playplay, id=T0H0YREAD, user_id=U0H0TU3NG, user_name=dblock, name=playplay, id=T0H0YREAD.
E, [2018-05-12T01:02:23.692868 #237] ERROR -- : Slack::Web::Api::Errors::SlackError: not_in_channel
/app/vendor/bundle/ruby/2.3.0/gems/slack-ruby-client-0.11.1/lib/slack/web/faraday/response/raise_error.rb:11:in `on_complete'
/app/vendor/bundle/ruby/2.3.0/gems/faraday-0.14.0/lib/faraday/response.rb:9:in `block in call'
/app/vendor/bundle/ruby/2.3.0/gems/faraday-0.14.0/lib/faraday/response.rb:61:in `on_complete'
/app/vendor/bundle/ruby/2.3.0/gems/faraday-0.14.0/lib/faraday/response.rb:8:in `call'
/app/vendor/bundle/ruby/2.3.0/gems/faraday-0.14.0/lib/faraday/response.rb:8:in `call'
/app/vendor/bundle/ruby/2.3.0/gems/faraday-0.14.0/lib/faraday/request/url_encoded.rb:15:in `call'
E, [2018-04-12T21:15:15.749146 #232] ERROR -- : E11000 duplicate key error collection: strava-bot.users index: user_id_1_team_id_1 dup key: { : "U02CZCQJC", : ObjectId('5abdc5a4afe25400ea863648') } (11000) (Mongo::Error::OperationFailure)
/app/vendor/bundle/ruby/2.3.0/gems/mongo-2.5.1/lib/mongo/operation/result.rb:256:in `validate!'
/app/vendor/bundle/ruby/2.3.0/gems/mongo-2.5.1/lib/mongo/operation/write/insert.rb:58:in `execute_write_command'
/app/vendor/bundle/ruby/2.3.0/gems/mongo-2.5.1/lib/mongo/operation/write/write_command_enabled.rb:48:in `execute'
/app/vendor/bundle/ruby/2.3.0/gems/mongo-2.5.1/lib/mongo/collection.rb:433:in `block (2 levels) in insert_one'
/app/vendor/bundle/ruby/2.3.0/gems/mongo-2.5.1/lib/mongo/retryable.rb:150:in `legacy_write_with_retry'
/app/vendor/bundle/ruby/2.3.0/gems/mongo-2.5.1/lib/mongo/retryable.rb:103:in `write_with_retry'
/app/vendor/bundle/ruby/2.3.0/gems/mongo-2.5.1/lib/mongo/collection.rb:422:in `block in insert_one'
/app/vendor/bundle/ruby/2.3.0/gems/mongo-2.5.1/lib/mongo/cluster.rb:515:in `with_session'
/app/vendor/bundle/ruby/2.3.0/gems/mongo-2.5.1/lib/mongo/client.rb:449:in `with_session'
/app/vendor/bundle/ruby/2.3.0/gems/mongo-2.5.1/lib/mongo/collection.rb:421:in `insert_one'
/app/vendor/bundle/ruby/2.3.0/gems/mongoid-7.0.0/lib/mongoid/query_cache.rb:182:in `insert_one_with_clear_cache'
/app/vendor/bundle/ruby/2.3.0/gems/mongoid-7.0.0/lib/mongoid/persistable/creatable.rb:81:in `insert_as_root'
/app/vendor/bundle/ruby/2.3.0/gems/mongoid-7.0.0/lib/mongoid/persistable/creatable.rb:27:in `block in insert'
/app/vendor/bundle/ruby/2.3.0/gems/mongoid-7.0.0/lib/mongoid/persistable/creatable.rb:120:in `block (2 levels) in prepare_insert'
/app/vendor/bundle/ruby/2.3.0/gems/activesupport-5.1.6/lib/active_support/callbacks.rb:131:in `run_callbacks'
/app/vendor/bundle/ruby/2.3.0/gems/mongoid-7.0.0/lib/mongoid/interceptable.rb:132:in `run_callbacks'
/app/vendor/bundle/ruby/2.3.0/gems/mongoid-7.0.0/lib/mongoid/persistable/creatable.rb:119:in `block in prepare_insert'
/app/vendor/bundle/ruby/2.3.0/gems/activesupport-5.1.6/lib/active_support/callbacks.rb:97:in `run_callbacks'
/app/vendor/bundle/ruby/2.3.0/gems/mongoid-7.0.0/lib/mongoid/interceptable.rb:132:in `run_callbacks'
/app/vendor/bundle/ruby/2.3.0/gems/mongoid-7.0.0/lib/mongoid/persistable/creatable.rb:118:in `prepare_insert'
/app/vendor/bundle/ruby/2.3.0/gems/mongoid-7.0.0/lib/mongoid/persistable/creatable.rb:23:in `insert'
/app/vendor/bundle/ruby/2.3.0/gems/mongoid-7.0.0/lib/mongoid/persistable/creatable.rb:180:in `block in create!'
/app/vendor/bundle/ruby/2.3.0/gems/mongoid-7.0.0/lib/mongoid/threaded/lifecycle.rb:161:in `_creating'
/app/vendor/bundle/ruby/2.3.0/gems/mongoid-7.0.0/lib/mongoid/persistable/creatable.rb:175:in `create!'
/app/slack-strava/models/user.rb:49:in `find_create_or_update_by_slack_id!'
/app/slack-strava/server.rb:10:in `block in <class:Server>'
/app/vendor/bundle/ruby/2.3.0/gems/slack-ruby-bot-0.11.0/lib/slack-ruby-bot/hooks/set.rb:33:in `block (2 levels) in register_callback'
/app/vendor/ruby-2.3.1/lib/ruby/2.3.0/set.rb:306:in `each_key'
/app/vendor/ruby-2.3.1/lib/ruby/2.3.0/set.rb:306:in `each'
/app/vendor/bundle/ruby/2.3.0/gems/slack-ruby-bot-0.11.0/lib/slack-ruby-bot/hooks/set.rb:32:in `block in register_callback'
/app/vendor/bundle/ruby/2.3.0/gems/slack-ruby-client-0.11.1/lib/slack/real_time/client.rb:199:in `block in run_callbacks'
/app/vendor/bundle/ruby/2.3.0/gems/slack-ruby-client-0.11.1/lib/slack/real_time/client.rb:198:in `each'
/app/vendor/bundle/ruby/2.3.0/gems/slack-ruby-client-0.11.1/lib/slack/real_time/client.rb:198:in `run_callbacks'
/app/vendor/bundle/ruby/2.3.0/gems/slack-ruby-client-0.11.1/lib/slack/real_time/client.rb:177:in `dispatch'
/app/vendor/bundle/ruby/2.3.0/gems/slack-ruby-client-0.11.1/lib/slack/real_time/client.rb:93:in `block (2 levels) in run_loop'
/app/vendor/bundle/ruby/2.3.0/gems/websocket-driver-0.7.0/lib/websocket/driver/event_emitter.rb:39:in `block in emit'
/app/vendor/bundle/ruby/2.3.0/gems/websocket-driver-0.7.0/lib/websocket/driver/event_emitter.rb:38:in `each'
/app/vendor/bundle/ruby/2.3.0/gems/websocket-driver-0.7.0/lib/websocket/driver/event_emitter.rb:38:in `emit'
/app/vendor/bundle/ruby/2.3.0/gems/websocket-driver-0.7.0/lib/websocket/driver/hybi.rb:398:in `emit_message'
/app/vendor/bundle/ruby/2.3.0/gems/websocket-driver-0.7.0/lib/websocket/driver/hybi.rb:381:in `emit_frame'
/app/vendor/bundle/ruby/2.3.0/gems/websocket-driver-0.7.0/lib/websocket/driver/hybi.rb:123:in `parse'
/app/vendor/bundle/ruby/2.3.0/gems/websocket-driver-0.7.0/lib/websocket/driver/client.rb:63:in `parse'
/app/vendor/bundle/ruby/2.3.0/gems/slack-ruby-client-0.11.1/lib/slack/real_time/concurrency/celluloid.rb:61:in `handle_read'
/app/vendor/bundle/ruby/2.3.0/gems/celluloid-0.17.3/lib/celluloid/calls.rb:28:in `public_send'
/app/vendor/bundle/ruby/2.3.0/gems/celluloid-0.17.3/lib/celluloid/calls.rb:28:in `dispatch'
/app/vendor/bundle/ruby/2.3.0/gems/celluloid-0.17.3/lib/celluloid/call/async.rb:7:in `dispatch'
/app/vendor/bundle/ruby/2.3.0/gems/celluloid-0.17.3/lib/celluloid/cell.rb:50:in `block in dispatch'
/app/vendor/bundle/ruby/2.3.0/gems/celluloid-0.17.3/lib/celluloid/cell.rb:76:in `block in task'
/app/vendor/bundle/ruby/2.3.0/gems/celluloid-0.17.3/lib/celluloid/actor.rb:339:in `block in task'
/app/vendor/bundle/ruby/2.3.0/gems/celluloid-0.17.3/lib/celluloid/task.rb:44:in `block in initialize'
/app/vendor/bundle/ruby/2.3.0/gems/celluloid-0.17.3/lib/celluloid/task/fibered.rb:14:in `block in create'
Strava has a webhook API, use that instead of polling.
We only want the one last activity and all future ones.
irb(main):013:0> User.asc(:_id).last.activities.count
=> 755
The map can look pretty big. Add a setting to decide whether the map should be a thumbnail or a full image.
Google maps URL is probably too long, so displaying the map in the notification doesn't work.
This probably requires a premium subscription for live tracking of Strava activities, but a cool idea via https://twitter.com/wpmark/status/952861998118854656?s=12
Strava API has a private
flag. I don't think the bot should post private activities.
The other direction of #15, give kudos directly from Slack.
Not everybody cares about your elevation.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.