diff --git a/Gemfile b/Gemfile index da1f793..05a9fa7 100644 --- a/Gemfile +++ b/Gemfile @@ -13,6 +13,7 @@ gem 'rack-cors', require: 'rack/cors' gem 'active_model_serializers' gem 'devise_token_auth' gem 'aws-sdk-s3' +gem 'stripe-rails' group :development, :test do gem 'byebug', platforms: %i[mri mingw x64_mingw] @@ -22,6 +23,7 @@ group :development, :test do gem 'factory_bot_rails' gem 'pry-rails' gem 'coveralls' + gem 'stripe-ruby-mock' end group :development do diff --git a/Gemfile.lock b/Gemfile.lock index 99c2d5f..b715846 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -93,6 +93,7 @@ GEM thor (>= 0.19.4, < 2.0) tins (~> 1.6) crass (1.0.6) + dante (0.2.0) devise (4.7.1) bcrypt (~> 3.0) orm_adapter (~> 0.1) @@ -135,6 +136,7 @@ GEM mini_portile2 (2.4.0) minitest (5.14.1) msgpack (1.3.3) + multi_json (1.14.1) nio4r (2.5.2) nokogiri (1.10.9) mini_portile2 (~> 2.4.0) @@ -223,6 +225,15 @@ GEM actionpack (>= 4.0) activesupport (>= 4.0) sprockets (>= 3.0.0) + stripe (5.7.1) + stripe-rails (1.9.1) + rails (>= 3) + responders + stripe (>= 1.36.2) + stripe-ruby-mock (3.0.0) + dante (>= 0.2.0) + multi_json (~> 1.0) + stripe (> 5, < 6) sync (0.5.0) term-ansicolor (1.7.1) tins (~> 1.0) @@ -261,6 +272,8 @@ DEPENDENCIES shoulda-matchers spring spring-watcher-listen (~> 2.0.0) + stripe-rails + stripe-ruby-mock RUBY VERSION ruby 2.5.1p57 diff --git a/app/controllers/api/subscriptions_controller.rb b/app/controllers/api/subscriptions_controller.rb new file mode 100644 index 0000000..51fd9dc --- /dev/null +++ b/app/controllers/api/subscriptions_controller.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +class Api::SubscriptionsController < ApplicationController + before_action :authenticate_user! + def create + # check if there is a stripeToken in params + # create a stripe customer based on the current_user and the stipeToken + # assign a subscription plan to the newly created customer + # update the current_user to a subscriber + # respond with a success message + # Stripe API for subscription: price_HMTltjInNtROlZ + if params[:stripeToken] + customer = Stripe::Customer.list(email: current_user.email).data.first + customer ||= Stripe::Customer.create(email: current_user.email, source: params[:stripeToken]) + subscription = Stripe::Subscription.create(customer: customer.id, plan: 'dns_subscription') + if Rails.env.test? + invoice = Stripe::Invoice.create( + customer: customer.id, + subscription: subscription.id, + paid: true + ) + subscription.latest_invoice = invoice.id + end + payment_status = Stripe::Invoice.retrieve(subscription.latest_invoice).paid + if payment_status == true + current_user.update_attribute(:subscriber, true) + render json: { message: 'Transaction was successful' } + else + render json: { message: 'Transaction was NOT successful. There was a problem with your payment...' }, status: 422 + + end + + else + render json: { message: 'Transaction was NOT successful. There was no token provided...' }, status: 422 + end + end +end diff --git a/config/application.rb b/config/application.rb index 362e86a..61a685a 100644 --- a/config/application.rb +++ b/config/application.rb @@ -40,5 +40,7 @@ class Application < Rails::Application generate.routing_specs false generate.controller_specs false end + config.stripe.publishable_key = Rails.application.credentials.stripe[:pk_key] + config.stripe.secret_key = Rails.application.credentials.stripe[:secret_key] end end diff --git a/config/credentials.yml.enc b/config/credentials.yml.enc index cf61aae..a3aaa37 100644 --- a/config/credentials.yml.enc +++ b/config/credentials.yml.enc @@ -1 +1 @@ -14HCMYKecrjxEs+nNdYWfvcQD2evIv2YAeX/TMSL3t2SnNQfLtq4LiuHXxbPWzHvtZ64nUdeapDm10IhJPCtK/u5feu03xJTcrXEo3bUGQlxtykzAyVF4g1R8qDqJUftZreTZWKf1OapUVHtnL9l87mVVZZoQtxmsWif6f6yu+De/u/CG8r92P5gTgvpiC/ni5LD6u/PPNEIleVgi/N+mPGvWtZ8KJl15CRnQghz2o7yqrDf2/I6ZiJuAhFUm6sU2AU6t5O/ivQyuWCjtRqgw+OmCOEPsB6ceI3hx4GT0UZKyU3ZKY19PEIxNvdprB0fCSiyWcZrgNxJMbTiVWXzGci+izRiHjbdXzlRHyywKPwzv4CgMCczwaetUdw3zNI/pdOuWCZIw8Nn++8wxBCNufezH814omCmsawG36bodcWBEVU5vrc3FWvJQFzNkpyy3RaRxISC0Ztm7jhNkhbJsC7oQHM7b274--GnMJl5NhKZP9otjm--acGQbo0/EsjAnibhvNSNnQ== \ No newline at end of file +lZuHUU6GJMJbTadwaoxBH6VUrlpsARVSXJwAJ5VaW6SV55MO+tZiLO1puDmFSmB3WiLxUaRnsnBWZK8ZKFZnJZer1MBK5AJUfKB4rIBjY0VNuE4l5pO1uPpQMTSjXTuWNfJzhRyo7ohTaAUVdufZOYFbDDpOgytxCyURauNLyw6kidubHtLF9sfJdteBcbiZp3+JT6MYfZDplH1qJTmJYpXaiUrC/iNpISGa7af53GDj3hxA0XdQy6JUchZflGCwbjP4N7kBFZRUCzQ51o3V9MR2vGEXmxrE7yoE28IW5LqQ3NzgtikrqFVdXxx2tn8DyXuU+tndYr5PUu5AYqKopV3XvnXCdr+TCODEv1Mv4p9sQpMZWhKQJT1qtlZlta7YqL5MXlx6Mtei25TBafCVCoh7uFrZrMi9RqSTBbHIfmAmIZg/UMaF+DVoclG79NEgmpDzOszNz/+sQq4HmWely1F8KRVYKvDAai0M28VX317nXdCUaClm/rSZgXJ/fgEok7l7tKvR4WHrRjyu8L+7tOKXbRoQLbzBJuMMIAHr0ppx4JxaXoaYlFE8uwMDXwL1rhqyHQ6fj9QPhjFd3EHdDomu3DHFG/o22A==--z4dIo8HiAx6ejYEy--p3O33WxwkzNa67lvoDOSGA== \ No newline at end of file diff --git a/config/initializers/stripe.rb b/config/initializers/stripe.rb new file mode 100644 index 0000000..0328d76 --- /dev/null +++ b/config/initializers/stripe.rb @@ -0,0 +1,7 @@ +Stripe.plan :dns_subscription do |plan| + plan.name = "DNS Subscription 2" + plan.amount = 50000 + plan.currency = "sek" + plan.interval = "month" + plan.interval_count = 6 +end \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 8984b7c..f59b03e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -4,5 +4,6 @@ mount_devise_token_auth_for 'User', at: 'api/auth' namespace :api do resources :articles, only: %i[index show create], constraints: { format: 'json' } + resources :subscriptions, only: [:create], constraints: { format: 'json' } end end diff --git a/db/migrate/20200528093718_add_subcriber_to_users.rb b/db/migrate/20200528093718_add_subcriber_to_users.rb new file mode 100644 index 0000000..3887900 --- /dev/null +++ b/db/migrate/20200528093718_add_subcriber_to_users.rb @@ -0,0 +1,5 @@ +class AddSubcriberToUsers < ActiveRecord::Migration[6.0] + def change + add_column :users, :subscriber, :boolean, default: false + end +end diff --git a/db/schema.rb b/db/schema.rb index 5eb2df4..5b22220 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,8 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2020_05_25_195359) do - +ActiveRecord::Schema.define(version: 2020_05_28_093718) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -67,6 +66,7 @@ t.datetime "last_sign_in_at" t.string "current_sign_in_ip" t.string "last_sign_in_ip" + t.boolean "subscriber", default: false t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true t.index ["email"], name: "index_users_on_email", unique: true t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 4aa3eaf..732bb38 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -4,11 +4,12 @@ it 'should have a valid Factory' do expect(create(:user)).to be_valid end - + describe 'Datatbase table' do it { is_expected.to have_db_column :encrypted_password } it { is_expected.to have_db_column :email } it { is_expected.to have_db_column :tokens } + it { is_expected.to have_db_column :subscriber } end describe 'Validations' do diff --git a/spec/requests/api/registered_user_can_purchase_subscription_endpoint_spec.rb b/spec/requests/api/registered_user_can_purchase_subscription_endpoint_spec.rb new file mode 100644 index 0000000..90409d6 --- /dev/null +++ b/spec/requests/api/registered_user_can_purchase_subscription_endpoint_spec.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +require 'stripe_mock' + +describe 'POST /api/subscriptions', type: :request do + let(:user) { create(:user) } + let(:credentials) { user.create_new_auth_token } + let(:headers) { { HTTP_ACCEPT: 'application/json' }.merge!(credentials) } + let(:stripe_helper) { StripeMock.create_test_helper } + let(:valid_token) { stripe_helper.generate_card_token } + before(:each) { StripeMock.start } + after(:each) { StripeMock.stop } + let!(:product) { stripe_helper.create_product } + let!(:plan) do + stripe_helper.create_plan( + id: 'dns_subscription', + amount: 50000, + currency: 'usd', + inteval: 'month', + interval_count: 6, + name: 'DNS Subscription 2', + product: product.id + ) + end + + + + describe 'with valid paramaters' do + before do + post '/api/subscriptions', + params: { + stripeToken: valid_token + }, + headers: headers + end + + it 'set the "subscriber" attribute to true on successfull transaction' do + user.reload + expect(user.subscriber).to eq true + end + + it 'returns a success http code' do + expect(response).to have_http_status 200 + end + + it 'returns a success message' do + expect(response_json['message']).to eq 'Transaction was successful' + end + end + + + describe 'with invalid parameters' do + before do + post '/api/subscriptions', + headers: headers + end + + it 'returns a error http code' do + expect(response).to have_http_status 422 + end + + it 'does NOT set the "subscriber" attribute to true' do + user.reload + expect(user.subscriber).not_to eq true + end + + it 'returns an error message' do + expect(response_json['message']).to eq 'Transaction was NOT successful. There was no token provided...' + end + + end +end diff --git a/spec/requests/api/sessions_spec.rb b/spec/requests/api/sessions_spec.rb index ea7ad1a..1faf49f 100644 --- a/spec/requests/api/sessions_spec.rb +++ b/spec/requests/api/sessions_spec.rb @@ -7,11 +7,12 @@ { 'data' => { 'id' => user.id, 'uid' => user.uid, 'email'=> user.email, - 'provider' => 'email', 'allow_password_change' => false + 'provider' => 'email', 'allow_password_change' => false, + 'subscriber' => false } } end - + describe 'with valid credentials' do before do post '/api/auth/sign_in',