diff --git a/app/models/agreement.rb b/app/models/agreement.rb index 7d9636f..3e55c6c 100644 --- a/app/models/agreement.rb +++ b/app/models/agreement.rb @@ -1,5 +1,4 @@ class Agreement < DataTable - self.air_table_name = "Information Sharing Agreements" self.rapid_table_name = :agreements self.rapid_name_field = :agreement_name diff --git a/app/models/agreement_control_person.rb b/app/models/agreement_control_person.rb index dccb95b..fb5b955 100644 --- a/app/models/agreement_control_person.rb +++ b/app/models/agreement_control_person.rb @@ -8,16 +8,7 @@ class << self def populate delete_all # Simplest way to ensure records deleted from Airtable do not persist in local database - air_table_data_source? ? populate_from_airtable : populate_from_rapid - end - - def populate_from_airtable - Agreement.find_each do |agreement| - (agreement.fields["controllers"] || []).each do |control_person_id| - control_person = ControlPerson.find_by(record_id: control_person_id) - find_or_create_by!(agreement:, control_person:) if control_person.present? - end - end + populate_from_rapid end def populate_from_rapid diff --git a/app/models/agreement_processor.rb b/app/models/agreement_processor.rb index bbb8a85..9489f9f 100644 --- a/app/models/agreement_processor.rb +++ b/app/models/agreement_processor.rb @@ -8,16 +8,7 @@ class << self def populate delete_all # Simplest way to ensure records deleted from Airtable do not persist in local database - air_table_data_source? ? populate_from_airtable : populate_from_rapid - end - - def populate_from_airtable - Agreement.find_each do |agreement| - (agreement.fields["processors"] || []).each do |processor_id| - processor = Processor.find_by(record_id: processor_id) - find_or_create_by!(agreement:, processor:) if processor.present? - end - end + populate_from_rapid end def populate_from_rapid diff --git a/app/models/air_table_base.rb b/app/models/air_table_base.rb deleted file mode 100644 index d20c31e..0000000 --- a/app/models/air_table_base.rb +++ /dev/null @@ -1,25 +0,0 @@ -# Added AirTable prefix as having a class called Base could be problematic -# The base is the root object that defines which set of data is being retrieved -# The id of the base is needed for API calls for sub-objects -class AirTableBase < ApplicationRecord - class << self - def default - @default ||= begin - populate if count.zero? - first # Assume api key only allows access to one base so default will be the first and only - end - end - - delegate :base_id, to: :default - - def populate - data = AirTableApi.data_for("/meta/bases") - data[:bases].each do |base| - air_table_base = find_or_initialize_by(base_id: base[:id]) - air_table_base.name = base[:name] - air_table_base.permission_level = base[:permissionLevel] - air_table_base.save! - end - end - end -end diff --git a/app/models/air_table_table.rb b/app/models/air_table_table.rb deleted file mode 100644 index 7fdafb7..0000000 --- a/app/models/air_table_table.rb +++ /dev/null @@ -1,19 +0,0 @@ -# An identity store for each of the tables within the current AirTable base -class AirTableTable < ApplicationRecord - def self.populate - data = AirTableApi.data_for("meta/bases/#{AirTableBase.base_id}/tables") - data[:tables].each do |base| - air_table_base = find_or_initialize_by(record_id: base[:id]) - air_table_base.name = base[:name] - air_table_base.save! - end - end - - # Converting table names into URL friendly text is problematic. - # So instead this method is used to find the id that matches the name - # Then the id can be used within any API URL rather than the name - def self.id_for_name(name) - populate if count.zero? - find_by(name:)&.record_id - end -end diff --git a/app/models/application_record.rb b/app/models/application_record.rb index deabf1e..08dc537 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -2,8 +2,4 @@ class ApplicationRecord < ActiveRecord::Base primary_abstract_class - - def self.air_table_data_source? - Rails.configuration.data_source == :airtable - end end diff --git a/app/models/concerns/airtable_data_source.rb b/app/models/concerns/airtable_data_source.rb deleted file mode 100644 index 1487174..0000000 --- a/app/models/concerns/airtable_data_source.rb +++ /dev/null @@ -1,41 +0,0 @@ -# Use in data tables where source of data is (can be) Airtable. -# Add the class via extend. For example: -# -# class FooBar < DataTable -# extend AirtableDataSource -# - -module AirtableDataSource - def search_via_air_table(text) - query = { "filterByFormula" => %[SEARCH("#{text}",{Name})] } - data = AirTableApi.data_for(air_table_path, query:) - return none if data[:records].empty? - - ids = data[:records].pluck(:id) - where(record_id: ids) - end - - def data_from_air_table - data = {} - records = {} - # API returns 100 records at a time. - # If there are more records, API returns an offset key that needs to be - # passed into the next query - while data.empty? || data[:offset].present? - query = data[:offset].present? ? { offset: data[:offset] } : {} - data = AirTableApi.data_for(air_table_path, query:) - data[:records].each do |record| - next if record[:fields].empty? - next if is_draft?(record) - - records[record[:id]] = record[:fields] - end - end - records - end - - def air_table_path - table_id = AirTableTable.id_for_name(air_table_name) - "#{AirTableBase.base_id}/#{table_id}" - end -end diff --git a/app/models/control_person.rb b/app/models/control_person.rb index f4ab70b..6f0f11f 100644 --- a/app/models/control_person.rb +++ b/app/models/control_person.rb @@ -1,11 +1,7 @@ class ControlPerson < DataTable - self.air_table_name = "Controllers" self.rapid_table_name = :controllers self.rapid_name_field = :controller_name - has_many :power_control_people, dependent: :delete_all - has_many :powers, through: :power_control_people - has_many :agreement_control_people, dependent: :delete_all has_many :agreements, through: :agreement_control_people end diff --git a/app/models/data_table.rb b/app/models/data_table.rb index a547028..96d3a35 100644 --- a/app/models/data_table.rb +++ b/app/models/data_table.rb @@ -1,18 +1,17 @@ # Classes that inherit from this one store data for each of the main data tables -# For data held in Airtable, the table name used in Airtable will need to be defined -# in the sub-classes. For example, if you want to store the data for an Airtable "Foo bar" -# you can: +# Subclasses of DataTable need to specify the name of the rAPId table the data +# will be pulled from and which field contains the instance name: # ``` # class FooBar < DataTable -# self.air_table_name = 'Foo bar' +# self.rapid_table_name = :my_model +# self.rapid_name_field = :my_model_name # end # ``` # # With that in place, `FooBar.populate` will pull each of the records from the data source # and store them in the data_tables table with the type 'FooBar'. class DataTable < ApplicationRecord - extend AirtableDataSource extend RapidDataSource include PgSearch::Model @@ -23,7 +22,7 @@ class DataTable < ApplicationRecord } class << self - attr_accessor :air_table_name, :rapid_table_name, :rapid_name_field + attr_accessor :rapid_table_name, :rapid_name_field def populate raise "Cannot run on root class - DataTable" if self == DataTable @@ -55,7 +54,7 @@ def before_populate_save(instance) end def data_from_source - air_table_data_source? ? data_from_air_table : data_from_rapid + data_from_rapid end private diff --git a/app/models/power.rb b/app/models/power.rb index 0d3def3..be4cc2b 100644 --- a/app/models/power.rb +++ b/app/models/power.rb @@ -1,11 +1,7 @@ class Power < DataTable - self.air_table_name = "Power Disclosure" self.rapid_table_name = :dea_upload_powers self.rapid_name_field = :name has_many :power_agreements has_many :agreements, through: :power_agreements - - has_many :power_control_people - has_many :control_people, through: :power_control_people end diff --git a/app/models/power_agreement.rb b/app/models/power_agreement.rb index a961a02..def2cb1 100644 --- a/app/models/power_agreement.rb +++ b/app/models/power_agreement.rb @@ -8,16 +8,7 @@ class << self def populate delete_all # Simplest way to ensure records deleted from Airtable do not persist in local database - air_table_data_source? ? populate_from_airtable : populate_from_rapid - end - - def populate_from_airtable - Agreement.find_each do |agreement| - (agreement.fields["Power Disclosure"] || []).each do |power_id| - power = Power.find_by(record_id: power_id) - find_or_create_by!(power:, agreement:) if power.present? - end - end + populate_from_rapid end def populate_from_rapid diff --git a/app/models/power_control_person.rb b/app/models/power_control_person.rb deleted file mode 100644 index c774847..0000000 --- a/app/models/power_control_person.rb +++ /dev/null @@ -1,15 +0,0 @@ -class PowerControlPerson < ApplicationRecord - belongs_to :power - belongs_to :control_person - - def self.populate - return unless air_table_data_source? - - Power.find_each do |power| - (power.fields["Person"] || []).each do |person_id| - control_person = ControlPerson.find_by(record_id: person_id) - find_or_create_by!(power:, control_person:) if control_person.present? - end - end - end -end diff --git a/app/models/processor.rb b/app/models/processor.rb index d28fa6a..e668b0e 100644 --- a/app/models/processor.rb +++ b/app/models/processor.rb @@ -1,5 +1,4 @@ class Processor < DataTable - self.air_table_name = "Processors" self.rapid_table_name = :processors self.rapid_name_field = :processor_name diff --git a/app/services/air_table_api.rb b/app/services/air_table_api.rb deleted file mode 100644 index 9d63108..0000000 --- a/app/services/air_table_api.rb +++ /dev/null @@ -1,44 +0,0 @@ -class AirTableApi - API_KEY = ENV.fetch("AIRTABLE_API_KEY", Rails.application.credentials.airtable_api_key).freeze - BASE_URL = "https://api.airtable.com/v0".freeze - - RequestError = Class.new(StandardError) - - require "net/http" - - def self.data_for(path, query: {}) - new(path, query:).output - end - - def initialize(path, query: {}) - @path = path - @query = query - end - - def output - return data if data[:error].blank? - - raise RequestError, "GET #{uri} returns error: #{data[:error]}" - end - -private - - attr_reader :path, :query - - def data - @data ||= JSON.parse(response, symbolize_names: true) - end - - def response - uri.query = query.to_param if query.present? - Net::HTTP.get(uri, headers) - end - - def uri - @uri ||= URI(File.join(BASE_URL, path)) - end - - def headers - { Authorization: "Bearer #{API_KEY}" } - end -end diff --git a/app/services/update_data_from_source.rb b/app/services/update_data_from_source.rb index 1e55fc6..388f2bf 100644 --- a/app/services/update_data_from_source.rb +++ b/app/services/update_data_from_source.rb @@ -9,7 +9,6 @@ def self.call Processor, Power, PowerAgreement, - PowerControlPerson, AgreementControlPerson, AgreementProcessor, ] diff --git a/app/views/control_people/show.html.erb b/app/views/control_people/show.html.erb index eb1e8f0..9868efa 100644 --- a/app/views/control_people/show.html.erb +++ b/app/views/control_people/show.html.erb @@ -4,4 +4,4 @@

<%= @control_person.fields['description'] %>

-<%= render 'shared/associations', associations: { agreements: @control_person.agreements, powers: @control_person.powers } %> +<%= render 'shared/associations', associations: { agreements: @control_person.agreements } %> diff --git a/app/views/powers/show.html.erb b/app/views/powers/show.html.erb index e0ae2c6..7746bc5 100644 --- a/app/views/powers/show.html.erb +++ b/app/views/powers/show.html.erb @@ -6,4 +6,4 @@

<%= @power.fields['description'] %>

-<%= render 'shared/associations', associations: { agreements: @power.agreements, controllers: @power.control_people } %> +<%= render 'shared/associations', associations: { agreements: @power.agreements } %> diff --git a/config/application.rb b/config/application.rb index ddff6a2..beb0377 100644 --- a/config/application.rb +++ b/config/application.rb @@ -21,9 +21,6 @@ class Application < Rails::Application # config.time_zone = "Central Time (US & Canada)" # config.eager_load_paths << Rails.root.join("extras") - # Data source options are :airtable and :rapid - config.data_source = ENV.fetch("DATA_SOURCE", :rapid).to_sym - config.active_job.queue_adapter = :delayed_job end end diff --git a/db/migrate/20250108132452_remove_air_table_specific_models.rb b/db/migrate/20250108132452_remove_air_table_specific_models.rb new file mode 100644 index 0000000..5196bcc --- /dev/null +++ b/db/migrate/20250108132452_remove_air_table_specific_models.rb @@ -0,0 +1,18 @@ +class RemoveAirTableSpecificModels < ActiveRecord::Migration[7.0] + def change + drop_table :air_table_bases do |t| + t.string :name + t.string :permission_level + t.string :base_id + + t.timestamps + end + + drop_table :air_table_tables do |t| + t.string :name + t.string :record_id + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index cb96d52..c39701e 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2024_12_02_124358) do +ActiveRecord::Schema[7.0].define(version: 2025_01_08_132452) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -28,21 +28,6 @@ t.index ["processor_id", "agreement_id"], name: "agreement_processors_by_processor" end - create_table "air_table_bases", force: :cascade do |t| - t.string "name" - t.string "permission_level" - t.string "base_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - end - - create_table "air_table_tables", force: :cascade do |t| - t.string "name" - t.string "record_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - end - create_table "data_tables", force: :cascade do |t| t.string "name" t.json "fields" diff --git a/db/seeds.rb b/db/seeds.rb index 5d7930a..13c083f 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -5,7 +5,7 @@ # # rubocop:disable Rails/Output -starting = "Seeding data from #{Rails.configuration.data_source}" +starting = "Seeding data from source" puts starting # This is sent to STOUT to provide feedback when seeding run at console Rails.logger.debug starting diff --git a/spec/factories/air_table_bases.rb b/spec/factories/air_table_bases.rb deleted file mode 100644 index 51723f8..0000000 --- a/spec/factories/air_table_bases.rb +++ /dev/null @@ -1,7 +0,0 @@ -FactoryBot.define do - factory :air_table_base do - name { Faker::Company.name } - permission_level { %w[none read comment edit create].sample } - base_id { SecureRandom.uuid } - end -end diff --git a/spec/factories/air_table_tables.rb b/spec/factories/air_table_tables.rb deleted file mode 100644 index 7c88d3c..0000000 --- a/spec/factories/air_table_tables.rb +++ /dev/null @@ -1,6 +0,0 @@ -FactoryBot.define do - factory :air_table_table do - name { Faker::Company.name } - record_id { rand(1..100) } - end -end diff --git a/spec/models/agreement_control_person_spec.rb b/spec/models/agreement_control_person_spec.rb index 7611e75..feb44d8 100644 --- a/spec/models/agreement_control_person_spec.rb +++ b/spec/models/agreement_control_person_spec.rb @@ -6,51 +6,6 @@ let!(:control_person) { create :control_person } - context "with airtable source" do - let!(:agreement) do - agreement = build(:agreement) - agreement.fields["controllers"] = [control_person.record_id] - agreement.save! - agreement - end - - before do - allow(Rails.configuration).to receive(:data_source).and_return(:airtable) - end - - it "creates a new instance" do - expect { populate }.to change(described_class, :count).by(1) - end - - it "associates the agreement with the control person" do - populate - expect(agreement.reload.control_people).to include(control_person) - end - - it "associates the control person with the agreement" do - populate - expect(control_person.reload.agreements).to include(agreement) - end - - describe "with an existing instance" do - let!(:agreement_control_person) { create :agreement_control_person } - - it "associates the agreement with the control person" do - populate - expect(agreement.reload.control_people).to include(control_person) - end - - it "deleted the existing association" do - expect { populate }.not_to change(described_class, :count) # +1 new, -1 old removed = 0 - end - - it "existing to be removed" do - populate - expect(described_class.find_by(agreement_control_person.attributes)).to be_nil - end - end - end - context "with rAPId source" do let!(:agreement) { create :agreement } @@ -64,7 +19,6 @@ end before do - allow(Rails.configuration).to receive(:data_source).and_return(:rapid) expect(RapidApi).to receive(:output_for).with(described_class::RAPID_TABLE_NAME).and_return(data) end diff --git a/spec/models/agreement_processor_spec.rb b/spec/models/agreement_processor_spec.rb index e4d8a40..c8fb8e6 100644 --- a/spec/models/agreement_processor_spec.rb +++ b/spec/models/agreement_processor_spec.rb @@ -6,51 +6,6 @@ let!(:processor) { create :processor } - context "with airtable source" do - let!(:agreement) do - agreement = build(:agreement) - agreement.fields["processors"] = [processor.record_id] - agreement.save! - agreement - end - - before do - allow(Rails.configuration).to receive(:data_source).and_return(:airtable) - end - - it "creates a new instance" do - expect { populate }.to change(described_class, :count).by(1) - end - - it "associates the agreement with the processor" do - populate - expect(agreement.reload.processors).to include(processor) - end - - it "associates the processor with the agreement" do - populate - expect(processor.reload.agreements).to include(agreement) - end - - describe "with an existing instance" do - let!(:agreement_processor) { create :agreement_processor } - - it "associates the agreement with the processor" do - populate - expect(agreement.reload.processors).to include(processor) - end - - it "deleted the existing association" do - expect { populate }.not_to change(described_class, :count) # +1 new, -1 old removed = 0 - end - - it "existing to be removed" do - populate - expect(described_class.find_by(agreement_processor.attributes)).to be_nil - end - end - end - context "with rAPId source" do let!(:agreement) { create :agreement } @@ -64,7 +19,6 @@ end before do - allow(Rails.configuration).to receive(:data_source).and_return(:rapid) expect(RapidApi).to receive(:output_for).with(described_class::RAPID_TABLE_NAME).and_return(data) end diff --git a/spec/models/agreement_spec.rb b/spec/models/agreement_spec.rb index 4da5787..075f708 100644 --- a/spec/models/agreement_spec.rb +++ b/spec/models/agreement_spec.rb @@ -7,7 +7,6 @@ subject(:populate) { described_class.populate } before do - allow(Rails.configuration).to receive(:data_source).and_return(:rapid) expect(RapidApi).to receive(:output_for).with(described_class.rapid_table_name).and_return(data) end diff --git a/spec/models/air_table_base_spec.rb b/spec/models/air_table_base_spec.rb deleted file mode 100644 index 859fe89..0000000 --- a/spec/models/air_table_base_spec.rb +++ /dev/null @@ -1,79 +0,0 @@ -require "rails_helper" - -RSpec.describe AirTableBase, type: :model do - let(:base) do - { - id: SecureRandom.uuid, - name: Faker::Company.name, - permissionLevel: Faker::Lorem.word, - } - end - let(:data) do - { bases: [base] } - end - - describe ".populate" do - subject(:populate) { described_class.populate } - - before do - expect(AirTableApi).to receive(:data_for).and_return(data) - end - - it "creates a new record" do - expect { populate }.to change(described_class, :count).by(1) - end - - it "populates the record" do - populate - record = described_class.last - expect(record.name).to eq(base[:name]) - expect(record.base_id).to eq(base[:id]) - expect(record.permission_level).to eq(base[:permissionLevel]) - end - - context "with an existing matching base" do - let!(:air_table_base) { create :air_table_base, base_id: base[:id] } - - it "does not create a new record" do - expect { populate }.not_to change(described_class, :count) - end - - it "does update the record" do - populate - air_table_base.reload - expect(air_table_base.name).to eq(base[:name]) - expect(air_table_base.permission_level).to eq(base[:permissionLevel]) - end - end - end - - describe ".default" do - subject(:default) { described_class.default } - - before do - allow(AirTableApi).to receive(:data_for).and_return(data) - - # clear cached entry - if described_class.instance_variable_defined?(:@default) - described_class.remove_instance_variable(:@default) - end - end - - it "returns a new air table base" do - expect(default.base_id).to eq(base[:id]) - end - - it "caches the new entry" do - default - expect(described_class.instance_variable_get(:@default).base_id).to eq(base[:id]) - end - - context "with an existing air table base" do - let!(:air_table_base) { create :air_table_base } - - it "uses the existing record" do - expect(default.base_id).to eq(air_table_base.base_id) - end - end - end -end diff --git a/spec/models/air_table_table_spec.rb b/spec/models/air_table_table_spec.rb deleted file mode 100644 index f5a0fae..0000000 --- a/spec/models/air_table_table_spec.rb +++ /dev/null @@ -1,52 +0,0 @@ -require "rails_helper" - -RSpec.describe AirTableTable, type: :model do - let(:table) do - { - id: SecureRandom.uuid, - name: Faker::Company.name, - } - end - let(:data) do - { tables: [table] } - end - - describe ".populate" do - subject(:populate) { described_class.populate } - - before do - create :air_table_base - expect(AirTableApi).to receive(:data_for).and_return(data) - end - - it "creates a new record" do - expect { populate }.to change(described_class, :count).by(1) - end - - it "populates the record" do - populate - record = described_class.last - expect(record.name).to eq(table[:name]) - expect(record.record_id).to eq(table[:id]) - end - end - - describe ".id_for_name" do - let(:table_record) { create :air_table_table } - - it "returns the id when passed a table name" do - expect(described_class.id_for_name(table_record.name)).to eq(table_record.record_id) - end - - context "when table not populated" do - before do - described_class.delete_all - create :air_table_base - expect(AirTableApi).to receive(:data_for).and_return(data) - end - it "populates the table and finds the id" do - expect(described_class.id_for_name(table[:name])).to eq(table[:id]) - end - end - end -end diff --git a/spec/models/control_person_spec.rb b/spec/models/control_person_spec.rb index d748d96..65b1c85 100644 --- a/spec/models/control_person_spec.rb +++ b/spec/models/control_person_spec.rb @@ -22,7 +22,6 @@ end before do - allow(Rails.configuration).to receive(:data_source).and_return(:rapid) expect(RapidApi).to receive(:output_for).with(described_class.rapid_table_name).and_return(data) end diff --git a/spec/models/power_agreement_spec.rb b/spec/models/power_agreement_spec.rb index 1a9bbfa..f510644 100644 --- a/spec/models/power_agreement_spec.rb +++ b/spec/models/power_agreement_spec.rb @@ -6,16 +6,20 @@ let!(:power) { create :power } - context "with airtable source" do - let!(:agreement) do - agreement = build(:agreement) - agreement.fields["Power Disclosure"] = [power.record_id] - agreement.save! - agreement + context "with rAPId source" do + let!(:agreement) { create :agreement } + + let(:data) do + { + SecureRandom.uuid => { + id: agreement.fields["id"], + name: power.name, + }, + } end before do - allow(Rails.configuration).to receive(:data_source).and_return(:airtable) + expect(RapidApi).to receive(:output_for).with(described_class::RAPID_TABLE_NAME).and_return(data) end it "creates a PowerAgreement" do @@ -44,43 +48,11 @@ expect { populate }.not_to change(described_class, :count) # +1 new, -1 old removed = 0 end - it "existing to be removed" do + it "existing is removed" do populate expect(described_class.find_by(power_agreement.attributes)).to be_nil end end end - - context "with rAPId source" do - let!(:agreement) { create :agreement } - - let(:data) do - { - SecureRandom.uuid => { - id: agreement.fields["id"], - name: power.name, - }, - } - end - - before do - allow(Rails.configuration).to receive(:data_source).and_return(:rapid) - expect(RapidApi).to receive(:output_for).with(described_class::RAPID_TABLE_NAME).and_return(data) - end - - it "creates a PowerAgreement" do - expect { populate }.to change(described_class, :count).by(1) - end - - it "associates the agreement with the power" do - populate - expect(agreement.reload.powers).to include(power) - end - - it "associates the power with the agreement" do - populate - expect(power.reload.agreements).to include(agreement) - end - end end end diff --git a/spec/models/power_control_person_spec.rb b/spec/models/power_control_person_spec.rb deleted file mode 100644 index 625a6c8..0000000 --- a/spec/models/power_control_person_spec.rb +++ /dev/null @@ -1,46 +0,0 @@ -require "rails_helper" - -RSpec.describe PowerControlPerson, type: :model do - describe ".populate" do - subject(:populate) { described_class.populate } - - let!(:control_person) { create :control_person } - - context "with airtable source" do - let!(:power) do - power = build(:power) - power.fields["Person"] = [control_person.record_id] - power.save! - power - end - - before do - allow(Rails.configuration).to receive(:data_source).and_return(:airtable) - end - - it "creates a PowerAgreement" do - expect { populate }.to change(described_class, :count).by(1) - end - - it "associates the control person with the power" do - populate - expect(control_person.reload.powers).to include(power) - end - - it "associates the power with the control person" do - populate - expect(power.reload.control_people).to include(control_person) - end - end - - context "with rAPId source" do - before do - allow(Rails.configuration).to receive(:data_source).and_return(:rapid) - end - - it "does nothing" do # no matching rAPId table - expect { populate }.not_to change(described_class, :count) - end - end - end -end diff --git a/spec/requests/control_people_spec.rb b/spec/requests/control_people_spec.rb index cc4e7da..e8213eb 100644 --- a/spec/requests/control_people_spec.rb +++ b/spec/requests/control_people_spec.rb @@ -41,26 +41,5 @@ get control_person_path(control_person) expect(response.body).to include(escape_html(control_person.name)) end - - context "when power present" do - let(:power_control_person) { create :power_control_person } - let(:control_person) { power_control_person.control_person } - let(:power) { power_control_person.power } - - it "renders a successful response" do - get control_person_path(control_person) - expect(response).to have_http_status(:success) - end - - it "displays control person" do - get control_person_path(control_person) - expect(response.body).to include(escape_html(control_person.name)) - end - - it "displays a link to the power" do - get control_person_path(control_person) - expect(response.body).to include(power_path(power)) - end - end end end diff --git a/spec/services/air_table_api_spec.rb b/spec/services/air_table_api_spec.rb deleted file mode 100644 index 6ea4ecd..0000000 --- a/spec/services/air_table_api_spec.rb +++ /dev/null @@ -1,43 +0,0 @@ -require "rails_helper" - -RSpec.describe AirTableApi, type: :service do - describe ".data_for" do - let(:path) { "/meta/bases" } - let(:url) { File.join("https://api.airtable.com/v0", path) } - let(:payload) do - { foo: "bar" } - end - - before do - stub_request(:get, url) - .with(headers: { "Authorization" => ["Bearer", described_class::API_KEY].select(&:present?).join(" ") }) - .to_return(body: payload.to_json) - end - - it "returns payload from url response" do - expect(described_class.data_for(path)).to eq(payload) - end - - context "with query" do - let(:query) do - { some: "thing" } - end - let(:url) { File.join("https://api.airtable.com/v0", "#{path}?#{query.to_query}") } - - it "returns payload from url response" do - expect(described_class.data_for(path, query:)).to eq(payload) - end - end - - context "with error" do - let(:error) { Faker::Lorem.sentence } - let(:payload) do - { error: } - end - - it "raises an error" do - expect { described_class.data_for(path) }.to raise_error(AirTableApi::RequestError) - end - end - end -end diff --git a/spec/shared_examples/is_data_table.rb b/spec/shared_examples/is_data_table.rb index 6d5d7d6..59969ec 100644 --- a/spec/shared_examples/is_data_table.rb +++ b/spec/shared_examples/is_data_table.rb @@ -6,18 +6,20 @@ let(:id) { rand(0..100).to_s } context "with rAPId source" do + let(:fields) do + { + id:, + described_class.rapid_name_field => name, + foo: "bar", + } + end let(:data) do { - id => { - id:, - described_class.rapid_name_field => name, - foo: "bar", - }, + id => fields, } end before do - allow(Rails.configuration).to receive(:data_source).and_return(:rapid) expect(RapidApi).to receive(:output_for).with(described_class.rapid_table_name).and_return(data) end @@ -69,54 +71,12 @@ expect(record.fields["end_date"]).to eq(valid_date) end end - end - - context "with airtable source" do - # make sure a base exists to avoid callout for base - let!(:air_table_base) { create :air_table_base } - let(:base_id) { AirTableBase.base_id } - - # There needs to be an air table table object to look up the table id - let!(:air_table_table) { create :air_table_table, name: described_class.air_table_name } - let(:table_id) { air_table_table.record_id } - - let(:fields) do - { - name:, - foo: "bar", - } - end - - let(:data) do - { - records: [{ - id:, - fields:, - }], - } - end - - before do - allow(Rails.configuration).to receive(:data_source).and_return(:airtable) - expect(AirTableApi).to receive(:data_for).with("#{base_id}/#{table_id}", query: {}).and_return(data) - end - - it "creates a new record" do - expect { populate }.to change(described_class, :count).by(1) - end - - it "populates the record" do - populate - record = described_class.last - expect(record.name).to eq(name) - expect(record.record_id).to eq(id) - expect(record.fields["foo"]).to eq("bar") - end context "when keys are not downcase" do let(:fields) do { - name:, + id:, + described_class.rapid_name_field => name, Foo_Bar: "bar", } end @@ -131,7 +91,8 @@ context "when keys contain spaces" do let(:fields) do { - name:, + id:, + described_class.rapid_name_field => name, "Foo Bar": "bar", } end @@ -143,36 +104,6 @@ end end - context "when an offset exists" do - # Offset needs to be returned by first calls so is added to the initial data - let(:offset) { SecureRandom.uuid } - let(:data) { super().merge(offset:) } - - # A second call is then triggered and that needs to return a different set of data - # As this is then the last set of data, it does not include an offset - let(:offset_id) { rand(1..100).to_s } - let(:offset_data) do - { - records: [{ - id: offset_id, - fields:, - }], - } - end - before do - expect(AirTableApi).to receive(:data_for).with("#{base_id}/#{table_id}", query: { offset: }).and_return(offset_data) - end - - it "creates records from two calls" do - expect { populate }.to change(described_class, :count).by(2) - end - - it "creates record that match the data" do - populate - expect(described_class.pluck(:record_id)).to contain_exactly(id, offset_id) - end - end - context "when record is empty" do let(:fields) { {} } @@ -181,20 +112,6 @@ end end - context "when record has draft sync status" do - let(:fields) do - { - name:, - foo: "bar", - Sync_Status: "Draft", - } - end - - it "does not create a record" do - expect { populate }.not_to change(described_class, :count) - end - end - context "when name has two parts separated by a colon" do let(:first_part) { Faker::Lorem.sentence } let(:second_part) { Faker::Company.name }