Importing products from DFC catalog

Technical demonstration of a complete product export-import roundtrip
which we could now do between OFN instances.
This commit is contained in:
Maikel Linke
2024-02-20 16:58:42 +11:00
parent 96ccea3691
commit 30e8f9eb28
4 changed files with 71 additions and 4 deletions

View File

@@ -1,8 +1,10 @@
# frozen_string_literal: true
require "private_address_check"
require "private_address_check/tcpsocket_ext"
module Admin
class DfcProductImportsController < Spree::Admin::BaseController
# Define model class for `can?` permissions:
def model_class
self.class
@@ -12,8 +14,52 @@ module Admin
# The plan:
#
# * Fetch DFC catalog as JSON from URL.
enterprise = OpenFoodNetwork::Permissions.new(spree_current_user)
.managed_product_enterprises.is_primary_producer
.find(params.require(:enterprise_id))
catalog_url = params.require(:catalog_url)
json_catalog = fetch_catalog(catalog_url)
graph = DfcIo.import(json_catalog)
# * First step: import all products for given enterprise.
# * Second step: render table and let user decide which ones to import.
imported = graph.map do |subject|
import_product(subject, enterprise)
end
@count = imported.compact.count
end
private
def fetch_catalog(url)
connection = Faraday.new(
request: { timeout: 30 },
headers: {
'Content-Type' => 'application/json',
'Authorization' => "Bearer #{spree_current_user.oidc_account.token}",
}
)
response = PrivateAddressCheck.only_public_connections do
connection.get(url)
end
response.body
end
# Most of this code is the same as in the DfcProvider::SuppliedProductsController.
def import_product(subject, enterprise)
return unless subject.is_a? DataFoodConsortium::Connector::SuppliedProduct
variant = SuppliedProductBuilder.import_variant(subject, enterprise)
product = variant.product
product.save! if product.new_record?
variant.save! if variant.new_record?
variant
end
end
end

View File

@@ -1,2 +1,3 @@
%h2 Importing a DFC product catalog
%p Catalog size: 0
%p Imported products:
= @count

View File

@@ -87,6 +87,8 @@ class SuppliedProductBuilder < DfcBuilder
end
def self.taxon(supplied_product)
return unless supplied_product.productType
dfc_id = supplied_product.productType.semanticId
Spree::Taxon.find_by(dfc_id: )
end

View File

@@ -1,13 +1,20 @@
# frozen_string_literal: false
require 'system_helper'
require_relative '../../../engines/dfc_provider/spec/support/authorization_helper'
describe "DFC Product Import" do
include AuthorizationHelper
let(:user) { create(:oidc_user, owned_enterprises: [enterprise]) }
let(:enterprise) { create(:enterprise) }
let(:source_product) { create(:product, supplier: enterprise) }
before do
login_as user
source_product # to be imported
allow(PrivateAddressCheck).to receive(:private_address?).and_return(false)
user.oidc_account.update!(token: allow_token_for(email: user.email))
end
it "imports from given catalog" do
@@ -17,10 +24,21 @@ describe "DFC Product Import" do
# We are testing against our own catalog for now but we want to replace
# this with the URL of another app when available.
fill_in "catalog_url", with: "/api/dfc/enterprises/#{enterprise.id}/supplied_products"
host = Rails.application.default_url_options[:host]
url = "http://#{host}/api/dfc/enterprises/#{enterprise.id}/catalog_items"
fill_in "catalog_url", with: url
click_button "Import"
# By feeding our own catalog to the import, we are effectively cloning the
# products. But the DFC product references the spree_product_id which
# make the importer create a variant for that product instead of creating
# a new independent product.
expect {
click_button "Import"
}.to change {
source_product.variants.count
}.by(1)
expect(page).to have_content "Importing a DFC product catalog"
expect(page).to have_content "Imported products: 1"
end
end