Commit 8154cc0f authored by Jan Provaznik's avatar Jan Provaznik

Merge branch 'rc/generate_oauth_on_subscription_create' into 'master'

Generate oauth token on subscription create

See merge request gitlab-org/gitlab!63259
parents 6bf6a221 fc940cc1
...@@ -2,8 +2,12 @@ ...@@ -2,8 +2,12 @@
module Subscriptions module Subscriptions
class CreateService class CreateService
include Gitlab::Utils::StrongMemoize
attr_reader :current_user, :customer_params, :subscription_params attr_reader :current_user, :customer_params, :subscription_params
CUSTOMERS_OAUTH_APP_ID_CACHE_KEY = 'customers_oauth_app_id'
def initialize(current_user, group:, customer_params:, subscription_params:) def initialize(current_user, group:, customer_params:, subscription_params:)
@current_user = current_user @current_user = current_user
@group = group @group = group
...@@ -16,6 +20,8 @@ module Subscriptions ...@@ -16,6 +20,8 @@ module Subscriptions
return response unless response[:success] return response unless response[:success]
oauth_token&.save
# We can't use an email from GL.com because it may differ from the billing email. # We can't use an email from GL.com because it may differ from the billing email.
# Instead we use the email received from the CustomersDot as a billing email. # Instead we use the email received from the CustomersDot as a billing email.
customer_data = response.with_indifferent_access[:data][:customer] customer_data = response.with_indifferent_access[:data][:customer]
...@@ -41,10 +47,10 @@ module Subscriptions ...@@ -41,10 +47,10 @@ module Subscriptions
} }
end end
# Return an empty hash for now, because the Customers API requires the credentials attribute to be present,
# although it does not require the actual values. Remove this once the Customers API has been updated.
def credentials_attrs def credentials_attrs
{} {
token: oauth_token&.token
}
end end
def customer_attrs def customer_attrs
...@@ -89,5 +95,31 @@ module Subscriptions ...@@ -89,5 +95,31 @@ module Subscriptions
def client def client
Gitlab::SubscriptionPortal::Client Gitlab::SubscriptionPortal::Client
end end
def customers_oauth_app_id
Rails.cache.fetch(CUSTOMERS_OAUTH_APP_ID_CACHE_KEY, expires_in: 1.hour) do
response = client.customers_oauth_app_id
response.dig(:data, 'oauth_app_id')
end
end
def oauth_token
strong_memoize(:oauth_token) do
next unless customers_oauth_app_id
application = Doorkeeper::Application.find_by_uid(customers_oauth_app_id)
existing_token = Doorkeeper::AccessToken.matching_token_for(application, current_user.id, application.scopes)
next existing_token if existing_token
Doorkeeper::AccessToken.new(
application_id: customers_oauth_app_id,
resource_owner_id: current_user.id,
token: Doorkeeper::OAuth::Helpers::UniqueToken.generate,
scopes: application.scopes.to_s
)
end
end
end end
end end
...@@ -33,6 +33,10 @@ module Gitlab ...@@ -33,6 +33,10 @@ module Gitlab
http_get("api/payment_methods/#{id}", admin_headers) http_get("api/payment_methods/#{id}", admin_headers)
end end
def customers_oauth_app_id
http_get("api/v1/oauth_app_id", admin_headers)
end
private private
def error_message def error_message
......
...@@ -2,7 +2,9 @@ ...@@ -2,7 +2,9 @@
"customer": { "customer": {
"provider": "gitlab", "provider": "gitlab",
"uid": 111, "uid": 111,
"credentials": {}, "credentials": {
"token": "foo_token"
},
"customer": { "customer": {
"country": "NLD", "country": "NLD",
"address_1": "Address line 1", "address_1": "Address line 1",
......
...@@ -124,4 +124,17 @@ RSpec.describe Gitlab::SubscriptionPortal::Clients::Rest do ...@@ -124,4 +124,17 @@ RSpec.describe Gitlab::SubscriptionPortal::Clients::Rest do
it_behaves_like 'when response code is 500' it_behaves_like 'when response code is 500'
it_behaves_like 'when http call raises an exception' it_behaves_like 'when http call raises an exception'
end end
describe '#customers_oauth_app_id' do
subject do
client.customers_oauth_app_id
end
let(:http_method) { :get }
it_behaves_like 'when response is successful'
it_behaves_like 'when response code is 422'
it_behaves_like 'when response code is 500'
it_behaves_like 'when http call raises an exception'
end
end end
...@@ -7,6 +7,7 @@ RSpec.describe Subscriptions::CreateService do ...@@ -7,6 +7,7 @@ RSpec.describe Subscriptions::CreateService do
let_it_be(:user) { create(:user, id: 111, first_name: 'First name', last_name: 'Last name', email: 'first.last@gitlab.com') } let_it_be(:user) { create(:user, id: 111, first_name: 'First name', last_name: 'Last name', email: 'first.last@gitlab.com') }
let_it_be(:group) { create(:group, id: 222, name: 'Group name') } let_it_be(:group) { create(:group, id: 222, name: 'Group name') }
let_it_be(:oauth_app) { create(:oauth_application) }
let_it_be(:customer_params) do let_it_be(:customer_params) do
{ {
...@@ -33,6 +34,11 @@ RSpec.describe Subscriptions::CreateService do ...@@ -33,6 +34,11 @@ RSpec.describe Subscriptions::CreateService do
let_it_be(:create_service_params) { Gitlab::Json.parse(fixture_file('create_service_params.json', dir: 'ee')).deep_symbolize_keys } let_it_be(:create_service_params) { Gitlab::Json.parse(fixture_file('create_service_params.json', dir: 'ee')).deep_symbolize_keys }
describe '#execute' do describe '#execute' do
before do
allow(client).to receive(:customers_oauth_app_id).and_return( { data: { 'oauth_app_id' => oauth_app.uid } } )
allow(Doorkeeper::OAuth::Helpers::UniqueToken).to receive(:generate).and_return('foo_token')
end
context 'when failing to create a customer' do context 'when failing to create a customer' do
before do before do
allow(client).to receive(:create_customer).and_return(success: false, data: { errors: 'failed to create customer' }) allow(client).to receive(:create_customer).and_return(success: false, data: { errors: 'failed to create customer' })
...@@ -41,20 +47,30 @@ RSpec.describe Subscriptions::CreateService do ...@@ -41,20 +47,30 @@ RSpec.describe Subscriptions::CreateService do
it 'returns the response hash' do it 'returns the response hash' do
expect(execute).to eq(success: false, data: { errors: 'failed to create customer' }) expect(execute).to eq(success: false, data: { errors: 'failed to create customer' })
end end
it 'does not save oauth token' do
expect { execute }.not_to change { Doorkeeper::AccessToken.count }
end
end end
context 'when successfully creating a customer' do context 'when successfully creating a customer' do
before do before do
allow(client).to receive(:create_customer).and_return(success: true, data: { success: true, 'customer' => { 'authentication_token' => 'token', 'email' => customer_email } }) allow(client).to receive(:create_customer).and_return(success: true, data: { success: true, 'customer' => { 'authentication_token' => 'token', 'email' => customer_email } })
end
it 'creates a subscription with the returned authentication token' do allow(client)
expect(client)
.to receive(:create_subscription) .to receive(:create_subscription)
.with(anything, customer_email, 'token') .with(anything, customer_email, 'token')
.and_return(success: true, data: { success: true, subscription_id: 'xxx' }) .and_return(success: true, data: { success: true, subscription_id: 'xxx' })
end
it 'creates a subscription with the returned authentication token' do
execute execute
expect(client).to have_received(:create_subscription).with(anything, customer_email, 'token')
end
it 'saves oauth token' do
expect { execute }.to change { Doorkeeper::AccessToken.count }.by(1)
end end
context 'when failing to create a subscription' do context 'when failing to create a subscription' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment