Skip to content

Commit

Permalink
Added premium info, allow users to change credit cards. Closes #149.
Browse files Browse the repository at this point in the history
  • Loading branch information
dblock committed Aug 5, 2017
1 parent 96098a8 commit 2a31b5e
Show file tree
Hide file tree
Showing 16 changed files with 300 additions and 11 deletions.
19 changes: 10 additions & 9 deletions .rubocop_todo.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2016-08-12 21:46:09 -0400 using RuboCop version 0.34.2.
# on 2017-08-04 20:36:10 -0400 using RuboCop version 0.34.2.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
Expand Down Expand Up @@ -28,7 +28,7 @@ Lint/HandleExceptions:
Exclude:
- 'slack-gamebot/commands/matches.rb'

# Offense count: 48
# Offense count: 51
Metrics/AbcSize:
Max: 69

Expand All @@ -41,25 +41,25 @@ Metrics/BlockNesting:
Metrics/ClassLength:
Max: 203

# Offense count: 15
# Offense count: 17
Metrics/CyclomaticComplexity:
Max: 19

# Offense count: 715
# Offense count: 746
# Configuration parameters: AllowURI, URISchemes.
Metrics/LineLength:
Max: 208
Max: 213

# Offense count: 34
# Offense count: 36
# Configuration parameters: CountComments.
Metrics/MethodLength:
Max: 48

# Offense count: 12
# Offense count: 14
Metrics/PerceivedComplexity:
Max: 20

# Offense count: 71
# Offense count: 74
# Configuration parameters: Exclude.
Style/Documentation:
Enabled: false
Expand All @@ -70,7 +70,8 @@ Style/FileName:
Exclude:
- 'slack-gamebot.rb'

# Offense count: 2
# Offense count: 3
Style/MultilineBlockChain:
Exclude:
- 'spec/api/endpoints/credit_cards_endpoint_spec.rb'
- 'spec/api/endpoints/subscriptions_endpoint_spec.rb'
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
### Changelog

* [#149](https://github.com/dblock/slack-gamebot/issues/149): Added `premium` info and a way to change team cc - [@dblock](https://github.com/dblock).
* [#138](https://github.com/dblock/slack-gamebot/issues/138): Fix: reset season with matches lost and no challenges - [@dblock](https://github.com/dblock).
* [#113](https://github.com/dblock/slack-gamebot/issues/113): Store elo history - [@dblock](https://github.com/dblock).
* [#129](https://github.com/dblock/slack-gamebot/issues/129): Added longest winning and losing streaks in leaderboard - [@dblock](https://github.com/dblock).
Expand Down
73 changes: 73 additions & 0 deletions public/update_cc.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<html>
<head>
<title>PlayPlay.io - Update Credit Card</title>
<%= partial 'public/partials/_head.html' %>
<%
game = Game.where(name: request['game']).first
team = game && game.teams.where(team_id: request['team_id']).first
stripe_token = request['stripeToken']
stripe_token_type = request['stripeTokenType']
stripe_email = request['stripeEmail']
%>
</head>
<body style='text-align: center'>
<p style='margin: 50px;'>
<a href='/'><img src='img/<%= game ? game.name : 'pong' %>.png' width='120px'></a>
</p>
<p>
<h3>PlayPlay.io: Update Credit Card Info</h3>
</p>
<p id='messages' />
<p id='update_cc'>
<form action="" method="POST">
<script
src="https://checkout.stripe.com/checkout.js" class="stripe-button"
data-key="<%= ENV['STRIPE_API_PUBLISHABLE_KEY'] %>"
data-image='/img/<%= game ? game.name : 'pong' %>.png'
data-name="Playplay.io"
data-panel-label="Update Credit Card"
data-label="Update Credit Card"
data-allow-remember-me=false
data-locale="auto">
</script>
</form>
<p>
<img src='/img/stripe.png' width='119' height='26'></img>
<div class='small'>
Questions? Contact dblock[at]dblock[dot]org or DM <a href='https://twitter.com/playplayio'>@playplayio</a>.
</div>
</p>
<%= partial 'public/partials/_scripts.html' %>
<script>
$(document).ready(function() {
var data = {
stripe_token: "<%= stripe_token %>",
stripe_token_type: "<%= stripe_token_type %>",
stripe_email: "<%= stripe_email %>",
team_id: "<%= team.id %>"
};

if (data.stripe_token) {

var team = {
id: <%= team ? "'#{team._id}'" : 'null' %>,
game: <%= game ? "'#{game.name}'" : 'null' %>,
name: <%= team ? "'#{team.name}'" : 'null' %>
};

$.ajax({
type: 'POST',
url: '/api/credit_cards',
data: data,
success: function(data) {
PlayPlay.message('Successfully updated team <b>' + team.name + '</b> credit card for <b>' + team.game + '</b>.<br><br>Thank you for your support!');
$('form').remove();
},
error: PlayPlay.error
});
}
});
</script>
</p>
</body>
</html>
1 change: 1 addition & 0 deletions slack-gamebot/api/endpoints.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@
require 'slack-gamebot/api/endpoints/teams_endpoint'
require 'slack-gamebot/api/endpoints/games_endpoint'
require 'slack-gamebot/api/endpoints/status_endpoint'
require 'slack-gamebot/api/endpoints/credit_cards_endpoint'
require 'slack-gamebot/api/endpoints/root_endpoint'
26 changes: 26 additions & 0 deletions slack-gamebot/api/endpoints/credit_cards_endpoint.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module Api
module Endpoints
class CreditCardsEndpoint < Grape::API
format :json

namespace :credit_cards do
desc 'Updates a credit card.'
params do
requires :stripe_token, type: String
optional :stripe_token_type, type: String
optional :stripe_email, type: String
requires :team_id, type: String
end
post do
team = Team.find(params[:team_id]) || error!('Not Found', 404)
error!('Not a Premium Customer', 400) unless team.stripe_customer_id
customer = Stripe::Customer.retrieve(team.stripe_customer_id)
customer.source = params['stripe_token']
customer.save
Api::Middleware.logger.info "Updated credit card for team #{team}, email=#{params[:stripe_email]}."
present team, with: Api::Presenters::TeamPresenter
end
end
end
end
end
1 change: 1 addition & 0 deletions slack-gamebot/api/endpoints/root_endpoint.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class RootEndpoint < Grape::API
mount Api::Endpoints::TeamsEndpoint
mount Api::Endpoints::GamesEndpoint
mount Api::Endpoints::SubscriptionsEndpoint
mount Api::Endpoints::CreditCardsEndpoint

add_swagger_documentation
end
Expand Down
4 changes: 4 additions & 0 deletions slack-gamebot/api/presenters/root_presenter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ module RootPresenter
"#{base_url(opts)}/api/subscriptions"
end

link :credit_cards do |opts|
"#{base_url(opts)}/api/credit_cards"
end

[:challenge, :match, :user, :season, :team, :game].each do |model|
link model do |opts|
{
Expand Down
1 change: 1 addition & 0 deletions slack-gamebot/commands.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@
require 'slack-gamebot/commands/team'
require 'slack-gamebot/commands/set'
require 'slack-gamebot/commands/sucks'
require 'slack-gamebot/commands/premium'
1 change: 1 addition & 0 deletions slack-gamebot/commands/help.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class Help < SlackRubyBot::Commands::Base
Premium
-------
premium: show subscription info (captains also see payment data)
seasons: show all seasons
reset <team>: reset all stats, start a new season
unregister <player>: remove a player from the leaderboard
Expand Down
27 changes: 27 additions & 0 deletions slack-gamebot/commands/premium.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
module SlackGamebot
module Commands
class Premium < SlackRubyBot::Commands::Base
include SlackGamebot::Commands::Mixins::Premium

premium_command 'premium' do |client, data, _match|
user = ::User.find_create_or_update_by_slack_id!(client, data.user)
customer = Stripe::Customer.retrieve(client.owner.stripe_customer_id)
customer_info = "Customer since #{Time.at(customer.created).strftime('%B %d, %Y')}."
customer.subscriptions.each do |subscription|
customer_info += "\nSubscribed to #{subscription.plan.name} (#{ActiveSupport::NumberHelper.number_to_currency(subscription.plan.amount.to_f / 100)})"
end
if user.captain?
customer.invoices.each do |invoice|
customer_info += "\nInvoice for #{ActiveSupport::NumberHelper.number_to_currency(invoice.amount_due.to_f / 100)} on #{Time.at(invoice.date).strftime('%B %d, %Y')}, #{invoice.paid ? 'paid' : 'unpaid'}."
end
customer.sources.each do |source|
customer_info += "\nOn file #{source.brand} #{source.object}, #{source.name} ending with #{source.last4}, expires #{source.exp_month}/#{source.exp_year}."
end
customer_info += "\n#{client.owner.update_cc_text}"
end
client.say(channel: data.channel, text: customer_info)
logger.info "PREMIUM: #{client.owner} - #{data.user}"
end
end
end
end
4 changes: 4 additions & 0 deletions slack-gamebot/models/team.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ def upgrade_text
"Upgrade your team to premium for $29.99 a year at #{SlackGamebot::Service.url}/upgrade?team_id=#{team_id}&game=#{game.name}."
end

def update_cc_text
"Update your credit card info at #{SlackGamebot::Service.url}/update_cc?team_id=#{team_id}&game=#{game.name}."
end

def captains
users.captains
end
Expand Down
53 changes: 53 additions & 0 deletions spec/api/endpoints/credit_cards_endpoint_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
require 'spec_helper'

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

context 'credit cards' do
it 'requires stripe parameters' do
expect { client.credit_cards._post }.to raise_error Faraday::ClientError do |e|
json = JSON.parse(e.response[:body])
expect(json['message']).to eq 'Invalid parameters.'
expect(json['type']).to eq 'param_error'
end
end
context 'premium team without a stripe customer id' do
let!(:team) { Fabricate(:team, premium: true, stripe_customer_id: nil) }
it 'fails to update credit_card' do
expect do
client.credit_cards._post(
team_id: team._id,
stripe_token: 'token')
end.to raise_error Faraday::ClientError do |e|
json = JSON.parse(e.response[:body])
expect(json['error']).to eq 'Not a Premium Customer'
end
end
end
context 'existing premium team' do
include_context :stripe_mock
let!(:team) { Fabricate(:team) }
before do
stripe_helper.create_plan(id: 'slack-playplay-yearly', amount: 2999)
customer = Stripe::Customer.create(
source: stripe_helper.generate_card_token,
plan: 'slack-playplay-yearly',
email: '[email protected]'
)
expect_any_instance_of(Team).to receive(:inform!).once
team.update_attributes!(premium: true, stripe_customer_id: customer['id'])
end
it 'updates a credit card' do
new_source = stripe_helper.generate_card_token
client.credit_cards._post(
team_id: team._id,
stripe_token: new_source,
stripe_token_type: 'card'
)
team.reload
customer = Stripe::Customer.retrieve(team.stripe_customer_id)
expect(customer.source).to eq new_source
end
end
end
end
3 changes: 2 additions & 1 deletion spec/api/endpoints/root_endpoint_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
get '/api/'
expect(last_response.status).to eq 200
links = JSON.parse(last_response.body)['_links']
expect(links.keys.sort).to eq(%w(self status team teams user users challenge challenges match matches current_season season seasons subscriptions game games).sort)
expect(links.keys.sort).to eq(%w(self status team teams user users challenge challenges credit_cards match matches current_season season seasons subscriptions game games).sort)
end
it 'follows all links' do
get '/api/'
Expand All @@ -17,6 +17,7 @@
href = h['href']
next if href.include?('{') # templated link
next if href == 'http://example.org/api/subscriptions'
next if href == 'http://example.org/api/credit_cards'
get href.gsub('http://example.org', '')
expect(last_response.status).to eq 200
expect(JSON.parse(last_response.body)).to_not eq({})
Expand Down
3 changes: 2 additions & 1 deletion spec/api/swagger_documentation_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
'/api/teams',
'/api/games/{id}',
'/api/games',
'/api/subscriptions'
'/api/subscriptions',
'/api/credit_cards'
]
end
end
Expand Down
44 changes: 44 additions & 0 deletions spec/integration/update_cc_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
require 'spec_helper'

describe 'Update cc', js: true, type: :feature do
let!(:game) { Fabricate(:game, name: 'pong') }

shared_examples 'updates cc' do
it 'updates cc' do
visit "/update_cc?team_id=#{team.team_id}&game=#{team.game.name}"
expect(find('h3')).to have_text('PLAYPLAY.IO: UPDATE CREDIT CARD INFO')

customer = double
expect(Stripe::Customer).to receive(:retrieve).and_return(customer)
expect(customer).to receive(:source=)
expect(customer).to receive(:save)

click_button 'Update Credit Card'
sleep 1
stripe_iframe = all('iframe[name=stripe_checkout_app]').last
Capybara.within_frame stripe_iframe do
page.find_field('Email').set '[email protected]'
page.find_field('Card number').set '4012 8888 8888 1881'
page.find_field('MM / YY').set '12/42'
page.find_field('CVC').set '345'
find('button[type="submit"]').click
end

sleep 5

expect(find('#messages')).to have_text("Successfully updated team #{team.name} credit card for #{team.game.name}. Thank you for your support!")
end
end
context 'with a stripe key' do
before do
ENV['STRIPE_API_PUBLISHABLE_KEY'] = 'pk_test_804U1vUeVeTxBl8znwriXskf'
end
after do
ENV.delete 'STRIPE_API_PUBLISHABLE_KEY'
end
context 'a team' do
let!(:team) { Fabricate(:team, game: game, stripe_customer_id: 'stripe_customer_id') }
it_behaves_like 'updates cc'
end
end unless ENV['CI'] # see https://github.com/dblock/slack-gamebot/issues/139
end
Loading

0 comments on commit 2a31b5e

Please sign in to comment.