diff --git a/lib/travis/api/v3/models/user.rb b/lib/travis/api/v3/models/user.rb index 54df28c54..a343abf1d 100644 --- a/lib/travis/api/v3/models/user.rb +++ b/lib/travis/api/v3/models/user.rb @@ -87,6 +87,18 @@ def installation @installation = Models::Installation.find_by(owner_type: 'User', owner_id: id, removed_by_id: nil) end + def internal? + !!get_internal_user + end + + def get_internal_user + Travis.config[:internal_users]&.find { |item| item[:id] == id } + end + + def login + read_attribute(:login) || get_internal_user&.dig(:login) + end + def github? vcs_type == 'GithubUser' end diff --git a/lib/travis/api/v3/renderer/user.rb b/lib/travis/api/v3/renderer/user.rb index 9ebcc6504..9497131c8 100644 --- a/lib/travis/api/v3/renderer/user.rb +++ b/lib/travis/api/v3/renderer/user.rb @@ -2,7 +2,7 @@ module Travis::API::V3 class Renderer::User < Renderer::Owner - representation(:standard, :email, :is_syncing, :synced_at, :recently_signed_up, :secure_user_hash, :ro_mode, :confirmed_at, :custom_keys) + representation(:standard, :email, :is_syncing, :synced_at, :recently_signed_up, :secure_user_hash, :ro_mode, :confirmed_at, :custom_keys, :internal) representation(:additional, :emails, :collaborator) def email @@ -17,6 +17,10 @@ def collaborator query(:user).collaborator? @model.id end + def internal + @model.internal? + end + def secure_user_hash hmac_secret_key = Travis.config.intercom && Travis.config.intercom.hmac_secret_key.to_s OpenSSL::HMAC.hexdigest('sha256', hmac_secret_key, @model.id.to_s) if @model.id && hmac_secret_key diff --git a/lib/travis/config/defaults.rb b/lib/travis/config/defaults.rb index 460c0eaf4..543113b28 100644 --- a/lib/travis/config/defaults.rb +++ b/lib/travis/config/defaults.rb @@ -105,7 +105,8 @@ def fallback_logs_api_auth_token authorizer: { url: 'http://authorizer', auth_key: 'secret' }, recaptcha: { endpoint: 'https://www.google.com', secret: ENV['RECAPTCHA_SECRET_KEY'] || '' }, antifraud: { captcha_max_failed_attempts: 3, captcha_block_duration: 24, credit_card_max_failed_attempts: 3, credit_card_block_duration: 24 }, - legacy_roles: false + legacy_roles: false, + internal_users: [{id: 0, login: 'cron'}] default :_access => [:key] diff --git a/spec/support/billing_spec_helper.rb b/spec/support/billing_spec_helper.rb index a6e7bc71d..5263e33ed 100644 --- a/spec/support/billing_spec_helper.rb +++ b/spec/support/billing_spec_helper.rb @@ -362,5 +362,48 @@ def billing_executions_response_body(attributes = {}) 'updated_at' => Time.now.utc.iso8601 }.deep_merge(attributes) end + + def billing_executions_multiple_response_body(attributes = {}) + [{ + 'id' => 1, + 'os' => 'linux', + 'instance_size' => 'standard-2', + 'arch' => 'amd64', + 'virtualization_type' => 'vm', + 'queue' => 'builds.gce-oss', + 'job_id' => 123, + 'repository_id' => 1, + 'owner_id' => 1, + 'owner_type' => 'User', + 'plan_id' => 2, + 'sender_id' => 1, + 'credits_consumed' => 5, + 'user_license_credits_consumed' => 4, + 'started_at' => Time.now.utc.iso8601, + 'finished_at' => (Time.now. + 10.minutes).utc.iso8601, + 'created_at' => Time.now.utc.iso8601, + 'updated_at' => Time.now.utc.iso8601 + }.deep_merge(attributes), + { + 'id' => 2, + 'os' => 'linux', + 'instance_size' => 'standard-2', + 'arch' => 'amd64', + 'virtualization_type' => 'vm', + 'queue' => 'builds.gce-oss', + 'job_id' => 123, + 'repository_id' => 1, + 'owner_id' => 1, + 'owner_type' => 'User', + 'plan_id' => 2, + 'sender_id' => 0, + 'credits_consumed' => 5, + 'user_license_credits_consumed' => 4, + 'started_at' => Time.now.utc.iso8601, + 'finished_at' => (Time.now. + 10.minutes).utc.iso8601, + 'created_at' => Time.now.utc.iso8601, + 'updated_at' => Time.now.utc.iso8601 + }] + end end end diff --git a/spec/v3/services/build/find_spec.rb b/spec/v3/services/build/find_spec.rb index 859126725..39f543d54 100644 --- a/spec/v3/services/build/find_spec.rb +++ b/spec/v3/services/build/find_spec.rb @@ -9,9 +9,12 @@ let(:authorization) { { 'permissions' => ['repository_state_update', 'repository_build_create', 'repository_settings_create', 'repository_settings_update', 'repository_cache_view', 'repository_cache_delete', 'repository_settings_delete', 'repository_log_view', 'repository_log_delete', 'repository_build_cancel', 'repository_build_debug', 'repository_build_restart', 'repository_settings_read', 'repository_scans_view'] } } - before { stub_request(:get, %r((.+)/permissions/repo/(.+))).to_return(status: 200, body: JSON.generate(authorization)) } before do + stub_request(:get, %r((.+)/permissions/repo/(.+))).to_return(status: 200, body: JSON.generate(authorization)) + stub_request(:post, 'http://billingfake.travis-ci.com/usage/stats') + .with(body: "{\"owners\":[{\"id\":1,\"type\":\"User\"}],\"query\":\"trial_allowed\"}") + .to_return(status: 200, body: "{\"trial_allowed\": false }", headers: {}) build.update(sender_id: repo.owner.id, sender_type: 'User') test = build.stages.create(number: 1, name: 'test') deploy = build.stages.create(number: 2, name: 'deploy') diff --git a/spec/v3/services/installation/find_spec.rb b/spec/v3/services/installation/find_spec.rb index 5100ccf6a..2be8b6132 100644 --- a/spec/v3/services/installation/find_spec.rb +++ b/spec/v3/services/installation/find_spec.rb @@ -72,6 +72,7 @@ "recently_signed_up" => false, "secure_user_hash" => nil, "trial_allowed" => false, + "internal" => false, "ro_mode" => true, "confirmed_at" => nil, } diff --git a/spec/v3/services/owner/find_spec.rb b/spec/v3/services/owner/find_spec.rb index 8ee837a42..042466272 100644 --- a/spec/v3/services/owner/find_spec.rb +++ b/spec/v3/services/owner/find_spec.rb @@ -345,7 +345,7 @@ "github_id" => 1234, "vcs_id" => org.vcs_id, "vcs_type" => org.vcs_type, - "trial_allowed" => false, + "trial_allowed" => false, "ro_mode" => true, "avatar_url" => nil, "education" => false, @@ -392,7 +392,7 @@ "github_id" => 1234, "vcs_id" => org.vcs_id, "vcs_type" => org.vcs_type, - "trial_allowed" => false, + "trial_allowed" => false, "ro_mode" => true, "avatar_url" => nil, "education" => false, @@ -445,7 +445,8 @@ "custom_keys" => [], "recently_signed_up"=>false, "secure_user_hash" => nil, - "trial_allowed" => false, + "trial_allowed" => false, + "internal" => false, "ro_mode" => false, "confirmed_at" => nil, }} @@ -479,7 +480,8 @@ "custom_keys" => [], "recently_signed_up"=>false, "secure_user_hash" => nil, - "trial_allowed" => false, + "trial_allowed" => false, + "internal" => false, "ro_mode" => false, "confirmed_at" => nil, }} @@ -513,7 +515,8 @@ "custom_keys" => [], "recently_signed_up"=>false, "secure_user_hash" => nil, - "trial_allowed" => false, + "trial_allowed" => false, + "internal" => false, "ro_mode" => false, "confirmed_at" => nil, }} @@ -554,7 +557,8 @@ "custom_keys" => [], "recently_signed_up"=>false, "secure_user_hash" => nil, - "trial_allowed" => false, + "trial_allowed" => false, + "internal" => false, "ro_mode" => false, "confirmed_at" => nil, "@warnings" => [{ diff --git a/spec/v3/services/repository/find_spec.rb b/spec/v3/services/repository/find_spec.rb index 659e535e5..80578c3a8 100644 --- a/spec/v3/services/repository/find_spec.rb +++ b/spec/v3/services/repository/find_spec.rb @@ -9,9 +9,13 @@ let(:authorization_role) { { 'roles' => ['repository_admin'] } } - before { stub_request(:get, %r((.+)/permissions/repo/(.+))).to_return(status: 200, body: JSON.generate(authorization)) } - before { stub_request(:get, %r((.+)/roles/repo/(.+))).to_return(status: 200, body: JSON.generate(authorization_role)) } - + before do + stub_request(:get, %r((.+)/permissions/repo/(.+))).to_return(status: 200, body: JSON.generate(authorization)) + stub_request(:get, %r((.+)/roles/repo/(.+))).to_return(status: 200, body: JSON.generate(authorization_role)) + stub_request(:post, 'http://billingfake.travis-ci.com/usage/stats') + .with(body: "{\"owners\":[{\"id\":1,\"type\":\"User\"}],\"query\":\"trial_allowed\"}") + .to_return(status: 200, body: "{\"trial_allowed\": false }", headers: {}) + end let(:permissions) do { diff --git a/spec/v3/services/user/current_spec.rb b/spec/v3/services/user/current_spec.rb index 2f0745ce7..f493d0be4 100644 --- a/spec/v3/services/user/current_spec.rb +++ b/spec/v3/services/user/current_spec.rb @@ -26,6 +26,7 @@ "education" => nil, "allow_migration" => false, "trial_allowed" => false, + "internal" => false, "allowance" => { "@type" => "allowance", "@representation" => "minimal", diff --git a/spec/v3/services/user/find_spec.rb b/spec/v3/services/user/find_spec.rb index 49fd4412e..163ae8c73 100644 --- a/spec/v3/services/user/find_spec.rb +++ b/spec/v3/services/user/find_spec.rb @@ -41,6 +41,7 @@ "education" => true, "allow_migration" => false, "trial_allowed" => false, + "internal" => false, "allowance" => { "@type" => "allowance", "@representation" => "minimal", @@ -82,6 +83,7 @@ "education" => true, "allow_migration" => false, "trial_allowed" => false, + "internal" => false, "allowance" => { "@type" => "allowance", "@representation" => "minimal", @@ -123,6 +125,7 @@ "education" => true, "allow_migration" => false, "trial_allowed" => false, + "internal" => false, "allowance" => { "@type" => "allowance", "@representation" => "minimal", diff --git a/spec/v3/services/user/sync_spec.rb b/spec/v3/services/user/sync_spec.rb index 574f7bde4..07fb77d2d 100644 --- a/spec/v3/services/user/sync_spec.rb +++ b/spec/v3/services/user/sync_spec.rb @@ -12,6 +12,9 @@ @original_sidekiq = Sidekiq::Client Sidekiq.send(:remove_const, :Client) # to avoid a warning Sidekiq::Client = [] + stub_request(:post, 'http://billingfake.travis-ci.com/usage/stats'). + with(body: "{\"owners\":[{\"id\":1,\"type\":\"User\"}],\"query\":\"trial_allowed\"}") + .to_return(status: 200, body: "{\"trial_allowed\": false }", headers: {}) end after do diff --git a/spec/v3/services/v2_subscription/executions_spec.rb b/spec/v3/services/v2_subscription/executions_spec.rb index c0677db81..9685c0e5d 100644 --- a/spec/v3/services/v2_subscription/executions_spec.rb +++ b/spec/v3/services/v2_subscription/executions_spec.rb @@ -199,6 +199,7 @@ "education"=>nil, "allow_migration"=>false, "trial_allowed"=>false, + "internal"=> false, "allowance"=> { "@type"=>"allowance", @@ -218,5 +219,101 @@ ]} ) end + + context 'with cron build' do + let!(:cron_user) { FactoryBot.create(:user, id: 0, login: nil, name: nil) } + before { + stub_request(:get, "#{billing_url}/usage/users/#{user.id}/executions?page=0&per_page=0&from=#{from.to_s}&to=#{to.to_s}") + .with(basic_auth: ['_', billing_auth_key], headers: { 'X-Travis-User-Id' => user.id }) + .to_return(body: billing_executions_multiple_response_body) + } + it 'responds with list of executions per sender' do + get("/v3/owner/#{user.login}/executions_per_sender?from=#{from.to_s}&to=#{to.to_s}", {}, headers) + + expect(last_response.status).to eq(200) + expect(parsed_body).to eql_json({ + '@type' => 'executionspersender', + '@href' => "/v3/owner/travis-ci/executions_per_sender?from=#{from.to_s}&to=#{to.to_s}", + '@representation' => 'standard', + 'executionspersender' => + [ + { + "credits_consumed"=>5, + "minutes_consumed"=>10, + "sender_id"=>1, + "sender"=> + { + "@type"=>"user", + "@href"=>"/user/1", + "@representation"=>"standard", + "@permissions"=>{"read"=>true, "sync"=>false}, + "id"=>1, + "login"=>"svenfuchs", + "name"=>"Sven Fuchs", + "github_id"=>nil, + "vcs_id"=>nil, + "vcs_type"=>"GithubUser", + "avatar_url"=>"https://0.gravatar.com/avatar/07fb84848e68b96b69022d333ca8a3e2", + "education"=>nil, + "allow_migration"=>false, + "trial_allowed"=>false, + "internal"=> false, + "allowance"=> + { + "@type"=>"allowance", + "@representation"=>"minimal", + "id"=>1 + }, + "custom_keys" => [], + "email"=>"sven@fuchs.com", + "is_syncing"=>nil, + "synced_at"=>nil, + "recently_signed_up"=>false, + "secure_user_hash"=>nil, + "ro_mode" => false, + "confirmed_at" => nil, + } + }, + { + "credits_consumed"=>5, + "minutes_consumed"=>10, + "sender_id"=>0, + "sender"=> + { + "@type"=>"user", + "@href"=>"/user/0", + "@representation"=>"standard", + "@permissions"=>{"read"=>true, "sync"=>false}, + "id"=>0, + "login"=>"cron", + "name"=>nil, + "github_id"=>nil, + "vcs_id"=>nil, + "vcs_type"=>"GithubUser", + "avatar_url"=>"https://0.gravatar.com/avatar/07fb84848e68b96b69022d333ca8a3e2", + "education"=>nil, + "allow_migration"=>false, + "trial_allowed"=>false, + "internal"=> true, + "allowance"=> + { + "@type"=>"allowance", + "@representation"=>"minimal", + "id"=>0 + }, + "custom_keys" => [], + "email"=>"sven@fuchs.com", + "is_syncing"=>nil, + "synced_at"=>nil, + "recently_signed_up"=>false, + "secure_user_hash"=>nil, + "ro_mode" => false, + "confirmed_at" => nil, + } + } + ]} + ) + end + end end end