From fdd24c6057db7556addca1c39a119cd747cc61ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Garc=C3=ADa=20Aubert?= Date: Thu, 19 Nov 2020 18:55:15 +0100 Subject: [PATCH] feat: allow to create regular apikeys for data observatory datasets --- .../carto/api/api_key_presenter.rb | 7 +++++ app/models/carto/api_key.rb | 18 ++++++++++- lib/formats/carto/api_key/grants.json | 9 +++++- spec/models/carto/api_key_spec.rb | 31 +++++++++++++++++++ 4 files changed, 63 insertions(+), 2 deletions(-) diff --git a/app/controllers/carto/api/api_key_presenter.rb b/app/controllers/carto/api/api_key_presenter.rb index fb6ac59cbe..a5cd34a210 100644 --- a/app/controllers/carto/api/api_key_presenter.rb +++ b/app/controllers/carto/api/api_key_presenter.rb @@ -50,6 +50,13 @@ module Carto } end + if @api_key.data_observatory_datasets? + grants << { + type: 'data-observatory', + datasets: @api_key.data_observatory_datasets + } + end + grants end diff --git a/app/models/carto/api_key.rb b/app/models/carto/api_key.rb index 7253ad82e5..38d48aefad 100644 --- a/app/models/carto/api_key.rb +++ b/app/models/carto/api_key.rb @@ -10,7 +10,7 @@ class ApiKeyGrantsValidator < ActiveModel::EachValidator record.errors[attribute] << 'only one apis section is allowed' unless value.count { |v| v[:type] == 'apis' } == 1 - max_one_sections = ['database', 'dataservices', 'user'] + max_one_sections = ['database', 'dataservices', 'user', 'data-observatory'] max_one_sections.each do |section| if value.count { |v| v[:type] == section } > 1 record.errors[attribute] << "only one #{section} section is allowed" @@ -255,6 +255,10 @@ module Carto @user_data ||= process_user_data_grants end + def data_observatory_datasets + @data_observatory_datasets ||= process_data_observatory_datasets + end + def regenerate_token! if master? # Send all master key updates through the user model, avoid circular updates @@ -290,6 +294,10 @@ module Carto data_services.present? end + def data_observatory_datasets? + data_observatory_datasets.present? + end + def valid_name_for_type if !master? && name == NAME_MASTER || !default_public? && name == NAME_DEFAULT_PUBLIC errors.add(:name, "api_key name cannot be #{NAME_MASTER} nor #{NAME_DEFAULT_PUBLIC}") @@ -455,6 +463,13 @@ module Carto dataset_metadata_grants.try(:[], :table_metadata) end + def process_data_observatory_datasets + data_observatory_grants = grants.find { |v| v[:type] == 'data-observatory' } + return nil unless data_observatory_grants.present? + + data_observatory_grants[:datasets] + end + def check_permissions # Only checks if no previous errors in JSON definition check_table_permissions @@ -613,6 +628,7 @@ module Carto def redis_hash_as_array hash = ['user', user.username, 'type', type, 'database_role', db_role, 'database_password', db_password] granted_apis.each { |api| hash += ["grants_#{api}", true] } + hash += ["data_observatory_datasets", data_observatory_datasets] hash end diff --git a/lib/formats/carto/api_key/grants.json b/lib/formats/carto/api_key/grants.json index b8585208d4..56f3007ca6 100644 --- a/lib/formats/carto/api_key/grants.json +++ b/lib/formats/carto/api_key/grants.json @@ -13,7 +13,8 @@ "apis", "database", "dataservices", - "user" + "user", + "data-observatory" ] }, "apis": { @@ -115,6 +116,12 @@ }, "table_metadata": { "type": "array" + }, + "datasets": { + "type": "array", + "items": { + "type": "string" + } } } } diff --git a/spec/models/carto/api_key_spec.rb b/spec/models/carto/api_key_spec.rb index 686b53706a..18f46dc3bc 100644 --- a/spec/models/carto/api_key_spec.rb +++ b/spec/models/carto/api_key_spec.rb @@ -82,6 +82,13 @@ describe Carto::ApiKey do } end + def data_observatory_datasets_grant(datasets = ['carto-do.here.pointsofinterest_pointsofinterest_usa_latlon_v1_quarterly_v1']) + { + type: 'data-observatory', + datasets: datasets + } + end + def user_grant(data = ['profile']) { type: 'user', @@ -812,6 +819,30 @@ describe Carto::ApiKey do end end + describe 'data observatory datasets api key' do + before :each do + @db_role = Carto::DB::Sanitize.sanitize_identifier("carto_role_#{SecureRandom.hex}") + Carto::ApiKey.any_instance.stubs(:db_role).returns(@db_role) + end + + after :each do + Carto::ApiKey.any_instance.unstub(:db_role) + end + + it 'grants with data observatory datasets' do + grants = [apis_grant(['maps']), data_observatory_datasets_grant] + expected = ['carto-do.here.pointsofinterest_pointsofinterest_usa_latlon_v1_quarterly_v1'] + api_key = @carto_user1.api_keys.create_regular_key!(name: 'data-observatory', grants: grants) + + api_key.should be + api_key.data_observatory_datasets.should eq expected + data_observatory_datasets = $users_metadata.hget(api_key.send(:redis_key), :data_observatory_datasets) + expect(JSON.parse(data_observatory_datasets, symbolize_names: true)).to eql(expected) + + api_key.destroy + end + end + describe 'filter by type' do it 'filters just master' do api_keys = @carto_user1.api_keys.by_type([Carto::ApiKey::TYPE_MASTER])