diff --git a/app/controllers/discourse_donations/charges_controller.rb b/app/controllers/discourse_donations/charges_controller.rb index 4e6912b..dc03b4e 100644 --- a/app/controllers/discourse_donations/charges_controller.rb +++ b/app/controllers/discourse_donations/charges_controller.rb @@ -12,22 +12,20 @@ module DiscourseDonations elsif create_account && params[:username].nil? response = {'message' => 'Please enter a username'} else - Stripe.api_key = SiteSetting.discourse_donations_secret_key - currency = SiteSetting.discourse_donations_currency + payment = DiscourseDonations::Stripe.new(secret_key, stripe_options) + response = payment.charge(email, params) + end - customer = Stripe::Customer.create( - :email => email, - :source => params[:stripeToken] - ) + response['rewards'] = [] - response = Stripe::Charge.create( - :customer => customer.id, - :amount => params[:amount], - :description => SiteSetting.discourse_donations_description, - :currency => currency - ) - - response['message'] = response['outcome']['seller_message'] + if reward_user?(payment) + reward = DiscourseDonations::Rewards.new(current_user) + if reward.add_to_group(group_name) + response['rewards'] << { type: :group, name: group_name } + end + if reward.grant_badge(badge_name) + response['rewards'] << { type: :badge, name: badge_name } + end end render :json => response @@ -39,6 +37,29 @@ module DiscourseDonations params[:create_account] == 'true' end + def reward_user?(payment) + payment.present? && payment.successful? && current_user.present? + end + + def group_name + SiteSetting.discourse_donations_reward_group_name + end + + def badge_name + SiteSetting.discourse_donations_reward_badge_name + end + + def secret_key + SiteSetting.discourse_donations_secret_key + end + + def stripe_options + { + description: SiteSetting.discourse_donations_description, + currency: SiteSetting.discourse_donations_currency + } + end + def email params[:email] || current_user.try(:email) end diff --git a/app/services/discourse_donations/rewards.rb b/app/services/discourse_donations/rewards.rb new file mode 100644 index 0000000..a901dd3 --- /dev/null +++ b/app/services/discourse_donations/rewards.rb @@ -0,0 +1,29 @@ + + +module DiscourseDonations + class Rewards + attr_reader :user + + def initialize(user) + @user = user + end + + def add_to_group(name) + grp = ::Group.find_by_name(name) + return if grp.nil? + log_group_add(grp) + grp.add(user) + end + + def grant_badge(name) + badge = ::Badge.find_by_name(name) + return if badge.nil? + BadgeGranter.grant(badge, user) + end + + def log_group_add(grp) + system_user = User.find(-1) + GroupActionLogger.new(system_user, grp).log_add_user_to_group(user) + end + end +end diff --git a/app/services/discourse_donations/stripe.rb b/app/services/discourse_donations/stripe.rb new file mode 100644 index 0000000..a8e4fa4 --- /dev/null +++ b/app/services/discourse_donations/stripe.rb @@ -0,0 +1,29 @@ + +module DiscourseDonations + class Stripe + def initialize(secret_key, opts) + ::Stripe.api_key = secret_key + @description = opts[:description] + @currency = opts[:currency] + end + + def charge(email, opts) + customer = ::Stripe::Customer.create( + email: email, + source: opts[:stripeToken] + ) + @charge = ::Stripe::Charge.create( + customer: customer.id, + amount: opts[:amount], + description: @description, + currency: @currency + ) + @charge[:message] = @charge[:outcome][:seller_message] if @charge[:outcome] + @charge + end + + def successful? + @charge[:paid] + end + end +end diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 52fd59d..49a1544 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -6,3 +6,5 @@ en: discourse_donations_public_key: Stripe Public Key discourse_donations_currency: Currency Code discourse_donations_hide_zip_code: Hide Zip Code + discourse_donations_reward_badge_name: Grant this badge to user when a payment is successful + discourse_donations_reward_group_name: Add the user to this group when a payment is successful diff --git a/config/settings.yml b/config/settings.yml index 46b68d8..0a3770d 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -18,3 +18,9 @@ plugins: discourse_donations_hide_zip_code: default: true client: true + discourse_donations_reward_badge_name: + client: false + default: 'Donation' + discourse_donations_reward_group_name: + client: false + default: 'Donation' diff --git a/plugin.rb b/plugin.rb index c2acab6..a41f6ec 100644 --- a/plugin.rb +++ b/plugin.rb @@ -1,10 +1,10 @@ # name: discourse-donations # about: Integrating Discourse with Stripe for donations -# version: 1.7.3 +# version: 1.9.0 # url: https://github.com/choiceaustralia/discourse-donations # authors: Rimian Perkins -gem 'stripe', '2.1.0' +gem 'stripe', '2.4.0' load File.expand_path('../lib/discourse_donations/engine.rb', __FILE__) @@ -13,16 +13,9 @@ enabled_site_setting :discourse_donations_enabled after_initialize do # Must be placed on every page for fraud protection. header_script = '' - - discourse_donations_customization = SiteCustomization.find_or_create_by({ - name: 'Discourse Donations Header', - header: header_script, - mobile_header: header_script, - enabled: true, - user_id: -1 - }) - - SiteCustomization.where(name: discourse_donations_customization.name).where.not(id: discourse_donations_customization.id).delete_all + discourse_donations_theme = Theme.find_or_create_by(name: 'Discourse Donations Header', hidden: false, user_id: -1) + discourse_donations_theme.set_field('common', 'head_tag', header_script) + discourse_donations_theme.save end Discourse::Application.routes.prepend do diff --git a/spec/controllers/discourse_donations/charges_controller_spec.rb b/spec/controllers/discourse_donations/charges_controller_spec.rb index 678199f..c3b3270 100644 --- a/spec/controllers/discourse_donations/charges_controller_spec.rb +++ b/spec/controllers/discourse_donations/charges_controller_spec.rb @@ -8,6 +8,8 @@ module DiscourseDonations before do SiteSetting.stubs(:discourse_donations_secret_key).returns('secret-key-yo') + SiteSetting.stubs(:discourse_donations_description).returns('charity begins at discourse plugin') + SiteSetting.stubs(:discourse_donations_currency).returns('AUD') end it 'responds ok for anonymous users' do @@ -40,5 +42,36 @@ module DiscourseDonations expect(body['message']).to eq('Payment complete.') expect(response).to have_http_status(200) end + + describe 'rewards' do + let(:group_name) { 'Zasch' } + let(:badge_name) { 'Beanie' } + let(:response_rewards) { JSON.parse(response.body)['rewards'] } + let(:stripe) { ::Stripe::Charge } + + before do + SiteSetting.stubs(:discourse_donations_reward_group_name).returns(group_name) + SiteSetting.stubs(:discourse_donations_reward_badge_name).returns(badge_name) + Fabricate(:group, name: SiteSetting.discourse_donations_reward_group_name) + Fabricate(:badge, name: SiteSetting.discourse_donations_reward_badge_name) + log_in :coding_horror + end + + it 'has no rewards' do + stripe.expects(:create).returns({ outcome: { seller_message: 'bummer' } }) + post :create + expect(response_rewards).to be_empty + end + + it 'awards a group' do + post :create + expect(response_rewards).to include({'type' => 'group', 'name' => group_name}) + end + + it 'awards a badge' do + post :create + expect(response_rewards).to include({'type' => 'badge', 'name' => badge_name}) + end + end end end diff --git a/spec/services/discourse_donations/rewards_spec.rb b/spec/services/discourse_donations/rewards_spec.rb new file mode 100644 index 0000000..9daa820 --- /dev/null +++ b/spec/services/discourse_donations/rewards_spec.rb @@ -0,0 +1,39 @@ +require 'rails_helper' + +module DiscourseDonations + RSpec.describe DiscourseDonations::Rewards do + let(:grp) { Fabricate(:group) } + let(:user) { Fabricate(:user) } + subject { described_class.new(user) } + + it 'adds the user to a group' do + Group.expects(:find_by_name).with(grp.name).returns(grp) + grp.expects(:add).with(user) + subject.expects(:log_group_add).once + subject.add_to_group(grp.name) + end + + it 'does not add the user to a group' do + Group.expects(:find_by_name).with(grp.name).returns(nil) + grp.expects(:add).never + subject.expects(:log_group_add).never + expect(subject.add_to_group(grp.name)).to be_falsy + end + + it 'logs the group add' do + GroupActionLogger.any_instance.expects(:log_add_user_to_group) + subject.add_to_group(grp.name) + end + + it 'grants the user a badge' do + badge = Fabricate(:badge) + BadgeGranter.expects(:grant).with(badge, user) + subject.grant_badge(badge.name) + end + + it 'does not grant the user a badge' do + BadgeGranter.expects(:grant).never + expect(subject.grant_badge('does not exist')).to be_falsy + end + end +end diff --git a/spec/services/discourse_donations/stripe_spec.rb b/spec/services/discourse_donations/stripe_spec.rb new file mode 100644 index 0000000..cc7f30c --- /dev/null +++ b/spec/services/discourse_donations/stripe_spec.rb @@ -0,0 +1,64 @@ +require 'rails_helper' +require_relative '../../support/dd_helper' + +module DiscourseDonations + RSpec.describe DiscourseDonations::Stripe do + before { SiteSetting.stubs(:discourse_donations_secret_key).returns('secret-key-yo') } + + let(:stripe_options) { { description: 'hi there', currency: 'AUD' } } + let(:params) { { email: email, stripeToken: 'stripe-token', amount: '1234', other: 'redundant param' } } + let(:email) { 'ray-zintoast@example.com' } + let(:customer) { stub(id: 1) } + let!(:subject) { described_class.new('secret-key-yo', stripe_options) } + + it 'sets the api key' do + expect(::Stripe.api_key).to eq 'secret-key-yo' + end + + it 'creates a customer and charges them an amount' do + ::Stripe::Customer.expects(:create).with( + email: email, + source: 'stripe-token' + ).returns(customer) + ::Stripe::Charge.expects(:create).with( + customer: customer.id, + amount: params[:amount], + description: stripe_options[:description], + currency: stripe_options[:currency] + ).returns( + { + paid: true, + outcome: { seller_message: 'yay!' } + } + ) + subject.charge(email, params) + end + + it 'has a message' do + ::Stripe::Customer.expects(:create).returns(customer) + ::Stripe::Charge.expects(:create).returns({ outcome: { seller_message: 'yay!' } }) + response = subject.charge(email, params) + expect(response[:message]).to eq 'yay!' + end + + describe '.successful?' do + let(:charge_options) { { customer: customer.id, amount: params[:amount], description: stripe_options[:description], currency: stripe_options[:currency] } } + + before do + ::Stripe::Customer.expects(:create).with(email: email, source: 'stripe-token').returns(customer) + end + + it 'is successful' do + ::Stripe::Charge.expects(:create).with(charge_options).returns({paid: true}) + subject.charge(email, params) + expect(subject).to be_successful + end + + it 'is not successful' do + ::Stripe::Charge.expects(:create).with(charge_options).returns({paid: false}) + subject.charge(email, params) + expect(subject).not_to be_successful + end + end + end +end diff --git a/spec/support/dd_helper.rb b/spec/support/dd_helper.rb index 6dd0ef8..3c196f0 100644 --- a/spec/support/dd_helper.rb +++ b/spec/support/dd_helper.rb @@ -1,3 +1,4 @@ +require 'fakeweb' #TODO register some fixtures