Skip to content

Commit

Permalink
Feature: #1 Other types of graphs (#27)
Browse files Browse the repository at this point in the history
* Created /api/graph endpoint for Interactive Slack Messages.
Updated Market model to include buttons in formatted Slack object.
Added condition to Market model to render stock quote's correct graph.

* Updated model and endpoint spec to account for new slack message structure, which now includes interactive buttons and a callback id.
Refactored Market model per RuboCop.

* downgraded firefox to version 46.01 for selenium-webdriver tests

* created spec to slack_endpoint test for parsing a good payload and non-matching verification tokens.
Updated README with animated GIF and styling.
Added parameter validation to slack_endpoint and renamed class to GraphEndpoint.

* refactored slack_endpoint_spec

* Changed slack_endpoint to be called graph_endpoint
  • Loading branch information
ddruker authored and dblock committed Jul 2, 2016
1 parent 5516364 commit 3baf5fb
Show file tree
Hide file tree
Showing 18 changed files with 336 additions and 6 deletions.
1 change: 1 addition & 0 deletions .ruby-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2.3.1
Empty file added 1m,
Empty file.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
### Changelog

* 7/2/2016: [#1](https://github.com/dblock/slack-market/issues/1): Display other types of graphs - [@ddruker](https://github.com/ddruker).
* 6/21/2016: [#24](https://github.com/dblock/slack-market/issues/24): Added support for FX rates - [@dblock](https://github.com/dblock).
* 6/20/2016: [#18](https://github.com/dblock/slack-market/issues/18): Fix: bought/sold rounding errors - [@dblock](https://github.com/dblock).
* 6/20/2016: [#22](https://github.com/dblock/slack-market/issues/22): Fix: robots.txt - [@dblock](https://github.com/dblock).
Expand Down
Empty file added D1L98DGBS,
Empty file.
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ DEPENDENCIES
yahoo-finance

RUBY VERSION
ruby 2.2.4p230
ruby 2.2.3p173

BUNDLED WITH
1.12.5
Empty file added LNKD- 1m
Empty file.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ Announce that you sold a symbol.

Display current positions. Optionally specify a user to display someone else's current positions.

#### Interactive Chart Buttons

Update a message to render charts for a stock's value over the course of one day, one month and one year.

![](public/img/interactive-chart.gif)

### Settings

#### set dollars on|off
Expand Down
Empty file added directmessage
Empty file.
4 changes: 4 additions & 0 deletions logfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
LOG: database system was shut down at 2016-06-30 17:56:55 EDT
LOG: MultiXact member wraparound protections are now enabled
LOG: database system is ready to accept connections
LOG: autovacuum launcher started
Binary file added public/img/interactive-chart.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions slack-market/api/endpoints.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require 'slack-market/api/endpoints/teams_endpoint'
require 'slack-market/api/endpoints/subscriptions_endpoint'
require 'slack-market/api/endpoints/status_endpoint'
require 'slack-market/api/endpoints/graph_endpoint'
require 'slack-market/api/endpoints/root_endpoint'
41 changes: 41 additions & 0 deletions slack-market/api/endpoints/graph_endpoint.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
require 'pp'
module Api
module Endpoints
class GraphEndpoint < Grape::API
format :json

namespace :graph do
desc 'Select graph.'

params do
requires :payload, type: String
end

post do
payload = JSON.parse(params[:payload])
button_name = payload['actions'][0]['name']
button_value = payload['actions'][0]['value']
stock_symbol = button_value.scan(/^[^\-]*/)
channel = payload['channel']['id']
token = payload['token']
ts = payload['original_message']['ts']
chart = true
quotes = Market.quotes([stock_symbol])

slack_attachment = Market.to_slack_attachment(quotes[0], charts: chart, button: button_name)

error! 'Message token is not coming from Slack.', 401 unless token == ENV['SLACK_VERIFICATION_TOKEN']
# formatted Slack message response
{
as_user: true,
channel: channel,
ts: ts,
token: token,
text: "Below is the #{button_name} chart",
attachments: [slack_attachment]
}
end
end
end
end
end
1 change: 1 addition & 0 deletions slack-market/api/endpoints/root_endpoint.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class RootEndpoint < Grape::API
end

mount Api::Endpoints::StatusEndpoint
mount Api::Endpoints::GraphEndpoint
mount Api::Endpoints::TeamsEndpoint
mount Api::Endpoints::SubscriptionsEndpoint

Expand Down
2 changes: 1 addition & 1 deletion slack-market/commands/quote.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class Quote < SlackRubyBot::Commands::Base

quotes.each do |quote|
logger.info "#{client.owner}, user=#{data.user} - #{quote.name} (#{quote.symbol}): $#{quote.last_trade_price}"
message[:attachments] << Market.to_slack_attachment(quote, client.owner.charts?)
message[:attachments] << Market.to_slack_attachment(quote, charts: client.owner.charts?)
end

client.web_client.chat_postMessage(message)
Expand Down
40 changes: 38 additions & 2 deletions slack-market/models/market.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,52 @@ def quotes(stocks, fields = [:name, :symbol, :last_trade_price, :change, :change
end
end

# render the correct chart
def render_chart(charts, slack_attachment, button, quote)
# the actions array below contains formatted slack buttons
actions = [
{
name: '1d',
text: '1d',
type: 'button',
value: "#{quote.symbol}- 1d"
},
{
name: '1m',
text: '1m',
type: 'button',
value: "#{quote.symbol}- 1m"
},
{
name: '1y',
text: '1y',
type: 'button',
value: "#{quote.symbol}- 1y"
}]

if charts && !button
slack_attachment[:image_url] = "http://chart.finance.yahoo.com/z?s=#{quote.symbol}&z=l"
slack_attachment[:actions] = actions
slack_attachment[:callback_id] = "#{quote.name}"
elsif charts && button
slack_attachment[:image_url] = "http://chart.finance.yahoo.com/z?s=#{quote.symbol}&z=l&t=#{button}&z=l"
slack_attachment[:actions] = actions
slack_attachment[:callback_id] = "#{quote.name}"
end
end

# returns a stock formatted as a Slack message
def to_slack_attachment(quote, charts = false)
def to_slack_attachment(quote, opts = { charts: false, button: nil })
attachment = {
fallback: "#{quote.name} (#{quote.symbol}): $#{quote.last_trade_price}",
title_link: "http://finance.yahoo.com/q?s=#{quote.symbol}",
title: "#{quote.name} (#{quote.symbol})",
text: "$#{quote.last_trade_price} (#{quote.change_in_percent})",
color: quote.change.to_f > 0 ? '#00FF00' : '#FF0000'
}
attachment[:image_url] = "http://chart.finance.yahoo.com/z?s=#{quote.symbol}&z=l" if charts

render_chart(opts[:charts], attachment, opts[:button], quote)

attachment
end
end
Expand Down
2 changes: 1 addition & 1 deletion spec/api/documentation_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
JSON.parse(last_response.body)
end
it 'documents root level apis' do
expect(subject['paths'].keys).to eq ['/api/status', '/api/teams/{id}', '/api/teams', '/api/subscriptions']
expect(subject['paths'].keys).to eq ['/api/status', '/api/graph', '/api/teams/{id}', '/api/teams', '/api/subscriptions']
end
end

Expand Down
30 changes: 30 additions & 0 deletions spec/api/endpoints/graph_endpoint_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
require 'spec_helper'

describe Api::Endpoints::GraphEndpoint do
include Api::Test::EndpointTest

context 'graph' do
it 'parses a good payload', vcr: { cassette_name: 'msft' } do
post '/api/graph', payload: {
'actions': [{ 'name' => '1m', 'value' => 'MSFT- 1m' }],
'channel': { 'id' => '424242424', 'name' => 'directmessage' },
'token': ENV['SLACK_VERIFICATION_TOKEN'],
'original_message': {
'ts': '1467321295.000010'
}
}.to_json
expect(last_response.status).to eq 201
end
it 'returns an error with a non-matching verification token', vcr: { cassette_name: 'msft' } do
post '/api/graph', payload: {
'actions': [{ 'name' => '1m', 'value' => 'MSFT- 1m' }],
'channel': { 'id' => '424242424', 'name' => 'directmessage' },
'token': 'invalid-token',
'original_message': {
'ts': '1467321295.000010'
}
}.to_json
expect(last_response.status).to eq 401
end
end
end
Loading

0 comments on commit 3baf5fb

Please sign in to comment.