mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-03-06 02:51:34 +00:00
Merge pull request #13513 from mkllnk/add-cqcm-staging-server
Add CQCM staging server to platforms to share data with
This commit is contained in:
@@ -47,7 +47,7 @@ Metrics/BlockNesting:
|
||||
Exclude:
|
||||
- 'app/models/spree/payment/processing.rb'
|
||||
|
||||
# Offense count: 47
|
||||
# Offense count: 48
|
||||
# Configuration parameters: CountComments, Max, CountAsOne.
|
||||
Metrics/ClassLength:
|
||||
Exclude:
|
||||
@@ -88,6 +88,7 @@ Metrics/ClassLength:
|
||||
- 'app/services/cart_service.rb'
|
||||
- 'app/services/order_cycles/form_service.rb'
|
||||
- 'app/services/orders/sync_service.rb'
|
||||
- 'app/services/permissions/order.rb'
|
||||
- 'app/services/sets/product_set.rb'
|
||||
- 'engines/order_management/app/services/order_management/order/updater.rb'
|
||||
- 'lib/open_food_network/enterprise_fee_calculator.rb'
|
||||
@@ -98,7 +99,6 @@ Metrics/ClassLength:
|
||||
- 'lib/reporting/reports/enterprise_fee_summary/enterprise_fees_with_tax_report_by_producer.rb'
|
||||
- 'lib/reporting/reports/enterprise_fee_summary/scope.rb'
|
||||
- 'lib/reporting/reports/xero_invoices/base.rb'
|
||||
- 'app/services/permissions/order.rb'
|
||||
|
||||
# Offense count: 30
|
||||
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
||||
@@ -129,14 +129,13 @@ Metrics/CyclomaticComplexity:
|
||||
- 'lib/spree/localized_number.rb'
|
||||
- 'spec/models/product_importer_spec.rb'
|
||||
|
||||
# Offense count: 23
|
||||
# Offense count: 22
|
||||
# Configuration parameters: CountComments, Max, CountAsOne, AllowedMethods, AllowedPatterns.
|
||||
Metrics/MethodLength:
|
||||
Exclude:
|
||||
- 'app/controllers/admin/enterprises_controller.rb'
|
||||
- 'app/controllers/payment_gateways/paypal_controller.rb'
|
||||
- 'app/controllers/spree/orders_controller.rb'
|
||||
- 'app/helpers/spree/admin/navigation_helper.rb'
|
||||
- 'app/models/spree/ability.rb'
|
||||
- 'app/models/spree/gateway/pay_pal_express.rb'
|
||||
- 'app/models/spree/order/checkout.rb'
|
||||
@@ -149,7 +148,7 @@ Metrics/MethodLength:
|
||||
- 'lib/spree/localized_number.rb'
|
||||
- 'lib/tasks/sample_data/product_factory.rb'
|
||||
|
||||
# Offense count: 47
|
||||
# Offense count: 10
|
||||
# Configuration parameters: CountComments, Max, CountAsOne.
|
||||
Metrics/ModuleLength:
|
||||
Exclude:
|
||||
@@ -174,7 +173,7 @@ Metrics/ParameterLists:
|
||||
- 'spec/support/controller_requests_helper.rb'
|
||||
- 'spec/system/admin/reports_spec.rb'
|
||||
|
||||
# Offense count: 3
|
||||
# Offense count: 4
|
||||
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
||||
Metrics/PerceivedComplexity:
|
||||
Exclude:
|
||||
@@ -182,6 +181,27 @@ Metrics/PerceivedComplexity:
|
||||
- 'app/models/spree/ability.rb'
|
||||
- 'app/models/spree/order/checkout.rb'
|
||||
|
||||
# Offense count: 1
|
||||
# Configuration parameters: EnforcedStyle, AllowedPatterns.
|
||||
# SupportedStyles: snake_case, camelCase
|
||||
Naming/MethodName:
|
||||
Exclude:
|
||||
- 'engines/dfc_provider/lib/dfc_provider/catalog_item.rb'
|
||||
|
||||
# Offense count: 1
|
||||
# Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
|
||||
# AllowedNames: as, at, by, cc, db, id, if, in, io, ip, of, on, os, pp, to
|
||||
Naming/MethodParameterName:
|
||||
Exclude:
|
||||
- 'engines/dfc_provider/lib/dfc_provider/catalog_item.rb'
|
||||
|
||||
# Offense count: 3
|
||||
# Configuration parameters: EnforcedStyle, AllowedIdentifiers, AllowedPatterns.
|
||||
# SupportedStyles: snake_case, camelCase
|
||||
Naming/VariableName:
|
||||
Exclude:
|
||||
- 'engines/dfc_provider/lib/dfc_provider/catalog_item.rb'
|
||||
|
||||
# Offense count: 1
|
||||
# Configuration parameters: TransactionMethods.
|
||||
Rails/TransactionExitStatement:
|
||||
|
||||
13
app/controllers/well_known_controller.rb
Normal file
13
app/controllers/well_known_controller.rb
Normal file
@@ -0,0 +1,13 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class WellKnownController < ApplicationController
|
||||
layout nil
|
||||
|
||||
def dfc
|
||||
base = "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/scopes.rdf#"
|
||||
render json: {
|
||||
"#{base}ReadEnterprise" => "/api/dfc/enterprises/",
|
||||
"#{base}ReadProducts" => "/api/dfc/supplied_products/",
|
||||
}
|
||||
end
|
||||
end
|
||||
@@ -50,7 +50,7 @@ module Admin
|
||||
end
|
||||
|
||||
def dfc_platforms_available?
|
||||
DfcProvider::PlatformsController::PLATFORM_IDS.keys.any? do |id|
|
||||
ApiUser::PLATFORMS.keys.any? do |id|
|
||||
feature?(id, spree_current_user)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -29,6 +29,9 @@ Openfoodnetwork::Application.routes.draw do
|
||||
get '/orders/:id/token/:token' => 'spree/orders#show', :as => :token_order
|
||||
get '/payments/:id/authorize' => 'payments#redirect_to_authorize', as: "authorize_payment"
|
||||
|
||||
# Well known paths
|
||||
get "/.well-known/dfc/", to: "well_known#dfc"
|
||||
|
||||
resource :cart, controller: "cart" do
|
||||
post :populate
|
||||
end
|
||||
|
||||
@@ -9,13 +9,11 @@ module DfcProvider
|
||||
def index
|
||||
require_permission "ReadProducts"
|
||||
|
||||
enterprises = current_user.enterprises.map do |enterprise|
|
||||
EnterpriseBuilder.enterprise(enterprise)
|
||||
end
|
||||
catalog_items = enterprises.flat_map(&:catalogItems)
|
||||
enterprise = EnterpriseBuilder.enterprise(current_enterprise)
|
||||
catalog_items = enterprise.catalogItems
|
||||
|
||||
render json: DfcIo.export(
|
||||
*enterprises,
|
||||
enterprise,
|
||||
*catalog_items,
|
||||
*catalog_items.map(&:product),
|
||||
*catalog_items.map(&:product).flat_map(&:isVariantOf),
|
||||
@@ -24,7 +22,7 @@ module DfcProvider
|
||||
end
|
||||
|
||||
def show
|
||||
catalog_item = DfcBuilder.catalog_item(variant)
|
||||
catalog_item = CatalogItemBuilder.catalog_item(variant)
|
||||
offers = catalog_item.offers
|
||||
render json: DfcIo.export(catalog_item, *offers)
|
||||
end
|
||||
|
||||
@@ -3,7 +3,22 @@
|
||||
# Controller used to provide the CatalogItem API for the DFC application
|
||||
module DfcProvider
|
||||
class EnterprisesController < DfcProvider::ApplicationController
|
||||
before_action :check_enterprise
|
||||
before_action :check_enterprise, except: :index
|
||||
|
||||
def index
|
||||
enterprises = current_user.enterprises.map do |enterprise|
|
||||
EnterpriseBuilder.enterprise(enterprise)
|
||||
end
|
||||
|
||||
render json: DfcIo.export(
|
||||
*enterprises,
|
||||
*enterprises.map(&:mainContact),
|
||||
*enterprises.flat_map(&:localizations),
|
||||
*enterprises.flat_map(&:suppliedProducts),
|
||||
*enterprises.flat_map(&:catalogItems),
|
||||
*enterprises.flat_map(&:socialMedias),
|
||||
)
|
||||
end
|
||||
|
||||
def show
|
||||
enterprise = EnterpriseBuilder.enterprise(current_enterprise)
|
||||
|
||||
@@ -2,12 +2,6 @@
|
||||
|
||||
module DfcProvider
|
||||
class PlatformsController < DfcProvider::ApplicationController
|
||||
# List of platform identifiers.
|
||||
# local ID => semantic ID
|
||||
PLATFORM_IDS = {
|
||||
'cqcm-dev' => "https://api.proxy-dev.cqcm.startinblox.com/profile",
|
||||
}.freeze
|
||||
|
||||
prepend_before_action :move_authenticity_token
|
||||
before_action :check_enterprise
|
||||
|
||||
@@ -30,21 +24,16 @@ module DfcProvider
|
||||
scopes_to_delete = current_scopes - requested_scopes
|
||||
scopes_to_create = requested_scopes - current_scopes
|
||||
|
||||
DfcPermission.where(
|
||||
user: current_user,
|
||||
enterprise: current_enterprise,
|
||||
scope: scopes_to_delete,
|
||||
grantee: key,
|
||||
).delete_all
|
||||
dfc_permissions(key).where(scope: scopes_to_delete).delete_all
|
||||
|
||||
scopes_to_create.each do |scope|
|
||||
DfcPermission.create!(
|
||||
user: current_user,
|
||||
enterprise: current_enterprise,
|
||||
scope:,
|
||||
grantee: key,
|
||||
)
|
||||
dfc_permissions(key).create!(scope:)
|
||||
end
|
||||
|
||||
urls = DfcProvider::Engine.routes.url_helpers
|
||||
enterprise_url = urls.enterprise_url(current_enterprise.id)
|
||||
ProxyNotifier.new.refresh(key, enterprise_url)
|
||||
|
||||
render json: platform(key)
|
||||
end
|
||||
|
||||
@@ -65,13 +54,15 @@ module DfcProvider
|
||||
end
|
||||
|
||||
def available_platforms
|
||||
PLATFORM_IDS.keys.select(&method(:feature?))
|
||||
ApiUser::PLATFORMS.keys.select do |platform|
|
||||
feature?(platform, current_user)
|
||||
end
|
||||
end
|
||||
|
||||
def platform(key)
|
||||
{
|
||||
'@type': "dfc-t:Platform",
|
||||
'@id': PLATFORM_IDS[key],
|
||||
'@id': ApiUser.platform_url(key),
|
||||
localId: key,
|
||||
'dfc-t:hasAssignedScopes': {
|
||||
'@type': "rdf:List",
|
||||
@@ -90,11 +81,15 @@ module DfcProvider
|
||||
end
|
||||
|
||||
def granted_scopes(platform_id)
|
||||
dfc_permissions(platform_id).pluck(:scope)
|
||||
end
|
||||
|
||||
def dfc_permissions(platform_id)
|
||||
DfcPermission.where(
|
||||
user: current_user,
|
||||
enterprise: current_enterprise,
|
||||
grantee: platform_id,
|
||||
).pluck(:scope)
|
||||
)
|
||||
end
|
||||
|
||||
# The DFC Permission Module is sending tokens in the Authorization header.
|
||||
|
||||
@@ -4,11 +4,33 @@
|
||||
# SuppliedProducts are products that are managed by an enterprise.
|
||||
module DfcProvider
|
||||
class SuppliedProductsController < DfcProvider::ApplicationController
|
||||
before_action :check_enterprise
|
||||
before_action :check_enterprise, except: :index
|
||||
rescue_from JSON::LD::JsonLdError::LoadingDocumentFailed, with: -> do
|
||||
head :bad_request
|
||||
end
|
||||
|
||||
def index
|
||||
# WARNING!
|
||||
#
|
||||
# For DFC platforms accessing this with scoped permissions:
|
||||
# We rely on the ReadEnterprise scope to list enterprises and
|
||||
# assume that the ReadProducts scope has been granted as well.
|
||||
#
|
||||
# This will be correct for the first iteration of the DFC Permissions
|
||||
# module but needs to be revised later.
|
||||
enterprises = current_user.enterprises.map do |enterprise|
|
||||
EnterpriseBuilder.enterprise(enterprise)
|
||||
end
|
||||
catalog_items = enterprises.flat_map(&:catalogItems)
|
||||
|
||||
render json: DfcIo.export(
|
||||
*catalog_items,
|
||||
*catalog_items.map(&:product),
|
||||
*catalog_items.map(&:product).flat_map(&:isVariantOf),
|
||||
*catalog_items.flat_map(&:offers),
|
||||
)
|
||||
end
|
||||
|
||||
def create
|
||||
supplied_product = import&.first
|
||||
|
||||
|
||||
@@ -8,7 +8,9 @@ class AddressBuilder < DfcBuilder
|
||||
postalCode: address.zipcode,
|
||||
city: address.city,
|
||||
country: address.country.name,
|
||||
region: address.state.name
|
||||
region: address.state.name,
|
||||
latitude: address.latitude,
|
||||
longitude: address.longitude,
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,9 +2,29 @@
|
||||
|
||||
# Authorised user or client using the API
|
||||
class ApiUser
|
||||
CLIENT_MAP = {
|
||||
"https://waterlooregionfood.ca/portal/profile" => "cqcm-dev",
|
||||
PLATFORMS = {
|
||||
'cqcm-dev' => {
|
||||
id: "https://api.proxy-dev.cqcm.startinblox.com/profile",
|
||||
tokens: "https://kc.cqcm.startinblox.com/realms/startinblox/protocol/openid-connect/token",
|
||||
},
|
||||
'cqcm-stg' => {
|
||||
id: "https://api.proxy-stg.cqcm.startinblox.com/profile",
|
||||
tokens: "https://kc.cqcm.startinblox.com/realms/startinblox/protocol/openid-connect/token",
|
||||
},
|
||||
'cqcm' => {
|
||||
id: "https://carte.cqcm.coop/profile",
|
||||
tokens: "https://authentification.cqcm.coop/realms/cqcm/protocol/openid-connect/token",
|
||||
},
|
||||
}.freeze
|
||||
CLIENT_MAP = PLATFORMS.keys.index_by { |key| PLATFORMS.dig(key, :id) }.freeze
|
||||
|
||||
def self.platform_url(platform)
|
||||
PLATFORMS.dig(platform, :id)
|
||||
end
|
||||
|
||||
def self.token_endpoint(platform)
|
||||
PLATFORMS.dig(platform, :tokens)
|
||||
end
|
||||
|
||||
def self.from_client_id(client_id)
|
||||
id = CLIENT_MAP[client_id]
|
||||
|
||||
@@ -18,6 +18,13 @@ class AuthorizationControl
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqtvdb3BdHoLnNeMLaWd7nugPwdRAJJpdSySTtttEQY2/v1Q3byJ/kReSNGrUNkPVkOeDN3milgN5Apz+sNCwbtzOCulyFMmvuIOZFBqz5tcgwjZinSwpGBXpn6ehXyCET2LlcfLYAPA9axtaNg9wBLIHoxIPWpa2LcZstogyZY/yKUZXQTDqM5B5TyUkPN89xHFdq8SQuXPasbpYl7mGhZHkTDHiKZ9VK7K5tqsEZTD9dCuTGMKsthbOrlDnc9bAJ3PyKLRdib21Y1GGlTozo4Y/1q448E/DFp5rVC6jG6JFnsEnP0WVn+6qz7yxI7IfUU2YSAGgtGYaQkWtEfED0QIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
KEY
|
||||
|
||||
# Copied from: https:///authentification.cqcm.coop/realms/cqcm
|
||||
"https:///authentification.cqcm.coop/realms/cqcm" => <<~KEY,
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhz7dK3xQAWL+u++E/64T1OHEvnFrZRLzgCmw0leib3JL/XbaE4Jbd3fs2+zc3+dCwvCuLEKKO9Hc9wg79ifjtMKFfZDE1Ba+qhw7J9tYnu7TBtaxKuWUCdtwuultEdW+NFndaUvhD/TdyjDkRiO98mgvUbm2A3q/zyDmoUpR2IEfevkMSz8MnxUo1bDTJIyoYoKwnbToI1E9RVx2uYsYKk24Pfd+r6oTbi7TxA6Ia4EiREFki2gNIAdp66IqF0Gxyd+nGlkIbQGrW+9xynU4ar3ZNq/P8EZFdO57AdEvC3ZAzpTvOVcQ0cQ4XbRSYWQHyZ8jnjggpeddTGSqVlgx1wIDAQAB
|
||||
-----END PUBLIC KEY-----
|
||||
KEY
|
||||
}.freeze
|
||||
|
||||
def self.public_key(token)
|
||||
|
||||
@@ -1,6 +1,23 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class CatalogItemBuilder < DfcBuilder
|
||||
def self.catalog_item(variant)
|
||||
id = urls.enterprise_catalog_item_url(
|
||||
enterprise_id: variant.supplier_id,
|
||||
id: variant.id,
|
||||
)
|
||||
supplier_url = urls.enterprise_url(variant.supplier_id)
|
||||
product = SuppliedProductBuilder.supplied_product(variant)
|
||||
|
||||
DfcProvider::CatalogItem.new(
|
||||
id, product:,
|
||||
sku: variant.sku,
|
||||
stockLimitation: stock_limitation(variant),
|
||||
offers: [OfferBuilder.build(variant)],
|
||||
managedBy: supplier_url,
|
||||
)
|
||||
end
|
||||
|
||||
def self.apply_stock(item, variant)
|
||||
limit = item&.stockLimitation
|
||||
|
||||
|
||||
@@ -1,21 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class DfcBuilder
|
||||
def self.catalog_item(variant)
|
||||
id = urls.enterprise_catalog_item_url(
|
||||
enterprise_id: variant.supplier_id,
|
||||
id: variant.id,
|
||||
)
|
||||
product = SuppliedProductBuilder.supplied_product(variant)
|
||||
|
||||
DataFoodConsortium::Connector::CatalogItem.new(
|
||||
id, product:,
|
||||
sku: variant.sku,
|
||||
stockLimitation: stock_limitation(variant),
|
||||
offers: [OfferBuilder.build(variant)],
|
||||
)
|
||||
end
|
||||
|
||||
# The DFC sees "empty" stock as unlimited.
|
||||
# http://static.datafoodconsortium.org/conception/DFC%20-%20Business%20rules.pdf
|
||||
def self.stock_limitation(variant)
|
||||
|
||||
@@ -6,7 +6,7 @@ class EnterpriseBuilder < DfcBuilder
|
||||
# in the DFC standard.
|
||||
|
||||
variants = enterprise.supplied_variants.to_a
|
||||
catalog_items = variants.map(&method(:catalog_item))
|
||||
catalog_items = variants.map(&CatalogItemBuilder.method(:catalog_item))
|
||||
supplied_products = catalog_items.map(&:product)
|
||||
address = AddressBuilder.address(enterprise.address)
|
||||
|
||||
|
||||
61
engines/dfc_provider/app/services/proxy_notifier.rb
Normal file
61
engines/dfc_provider/app/services/proxy_notifier.rb
Normal file
@@ -0,0 +1,61 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "private_address_check"
|
||||
require "private_address_check/tcpsocket_ext"
|
||||
|
||||
# Call a webhook to notify a data proxy about changes in our data.
|
||||
class ProxyNotifier
|
||||
def refresh(platform, enterprise_url)
|
||||
PrivateAddressCheck.only_public_connections do
|
||||
notify_proxy(platform, enterprise_url)
|
||||
end
|
||||
end
|
||||
|
||||
def request_token(platform)
|
||||
connection = Faraday.new(
|
||||
request: { timeout: 5 },
|
||||
) do |f|
|
||||
f.request :url_encoded
|
||||
f.response :json
|
||||
f.response :raise_error
|
||||
end
|
||||
|
||||
url = ApiUser.token_endpoint(platform)
|
||||
data = {
|
||||
grant_type: "client_credentials",
|
||||
client_id: ENV.fetch("OPENID_APP_ID", nil),
|
||||
client_secret: ENV.fetch("OPENID_APP_SECRET", nil),
|
||||
scope: "WriteEnterprise",
|
||||
}
|
||||
response = connection.post(url, data)
|
||||
response.body["access_token"]
|
||||
end
|
||||
|
||||
def notify_proxy(platform, enterprise_url)
|
||||
token = request_token(platform)
|
||||
data = {
|
||||
eventType: "refresh",
|
||||
enterpriseUrlid: enterprise_url,
|
||||
scope: "ReadEnterprise",
|
||||
}
|
||||
|
||||
connection = Faraday.new(
|
||||
request: { timeout: 10 },
|
||||
headers: {
|
||||
'Authorization' => "Bearer #{token}",
|
||||
}
|
||||
) do |f|
|
||||
f.request :json
|
||||
f.response :json
|
||||
f.response :raise_error
|
||||
end
|
||||
connection.post(webhook_url(platform), data)
|
||||
end
|
||||
|
||||
def webhook_url(platform)
|
||||
platform_url = ApiUser.platform_url(platform)
|
||||
URI.parse(platform_url).tap do |url|
|
||||
url.path = "/djangoldp-dfc/webhook/"
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
DfcProvider::Engine.routes.draw do
|
||||
resources :addresses, only: [:show]
|
||||
resources :enterprises, only: [:show] do
|
||||
resources :enterprises, only: [:index, :show] do
|
||||
resources :catalog_items, only: [:index, :show, :update]
|
||||
resources :offers, only: [:show, :update]
|
||||
resources :platforms, only: [:index, :show, :update]
|
||||
@@ -13,6 +13,7 @@ DfcProvider::Engine.routes.draw do
|
||||
resources :affiliated_by, only: [:create, :destroy], module: 'enterprise_groups'
|
||||
end
|
||||
resources :persons, only: [:show]
|
||||
resources :supplied_products, only: [:index]
|
||||
resources :product_groups, only: [:show]
|
||||
|
||||
resource :affiliate_sales_data, only: [:show]
|
||||
|
||||
@@ -9,6 +9,7 @@ require "dfc_provider/engine"
|
||||
# Custom data types
|
||||
require "dfc_provider/supplied_product"
|
||||
require "dfc_provider/address"
|
||||
require "dfc_provider/catalog_item"
|
||||
require "dfc_provider/coordination"
|
||||
|
||||
# 🙈 Monkey-patch a better inspector for semantic objects
|
||||
|
||||
16
engines/dfc_provider/lib/dfc_provider/catalog_item.rb
Normal file
16
engines/dfc_provider/lib/dfc_provider/catalog_item.rb
Normal file
@@ -0,0 +1,16 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Temporary solution.
|
||||
module DfcProvider
|
||||
class CatalogItem < DataFoodConsortium::Connector::CatalogItem
|
||||
attr_accessor :managedBy
|
||||
|
||||
def initialize(semantic_id, managedBy: "", **properties)
|
||||
super(semantic_id, **properties)
|
||||
@managedBy = managedBy
|
||||
|
||||
registerSemanticProperty("dfc-b:managedBy", &method("managedBy"))
|
||||
.valueSetter = method("managedBy=")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -80,6 +80,23 @@ RSpec.describe "CatalogItems", swagger_doc: "dfc.yaml" do
|
||||
run_test!
|
||||
end
|
||||
|
||||
context "with a second enterprise" do
|
||||
let(:enterprise_id) { 10_000 }
|
||||
|
||||
before do
|
||||
create(
|
||||
:distributor_enterprise,
|
||||
id: 10_001, owner: user, name: "Fred's Icecream", description: "Yum",
|
||||
address: build(:address, id: 40_001),
|
||||
)
|
||||
end
|
||||
|
||||
run_test! do
|
||||
expect(response.body).to include "Apple"
|
||||
expect(response.body).not_to include "Icecream"
|
||||
end
|
||||
end
|
||||
|
||||
context "with default enterprise id" do
|
||||
let(:enterprise_id) { "default" }
|
||||
|
||||
|
||||
@@ -15,7 +15,22 @@ RSpec.describe "Enterprises", swagger_doc: "dfc.yaml" do
|
||||
email_address: "hello@example.org",
|
||||
phone: "0404 444 000 200",
|
||||
website: "https://openfoodnetwork.org",
|
||||
address: build(:address, id: 40_000, address1: "42 Doveton Street"),
|
||||
address:,
|
||||
)
|
||||
end
|
||||
let(:address) {
|
||||
build(
|
||||
:address,
|
||||
id: 40_000, address1: "42 Doveton Street",
|
||||
latitude: -25.345376, longitude: 131.0312006,
|
||||
)
|
||||
}
|
||||
let!(:other_enterprise) do
|
||||
create(
|
||||
:distributor_enterprise,
|
||||
id: 10_001, owner: user, abn: "123 457", name: "Fred's Icecream",
|
||||
description: "We use our strawberries to make icecream.",
|
||||
address: build(:address, id: 40_001, address1: "42 Doveton Street"),
|
||||
)
|
||||
end
|
||||
let!(:enterprise_group) do
|
||||
@@ -46,6 +61,63 @@ RSpec.describe "Enterprises", swagger_doc: "dfc.yaml" do
|
||||
|
||||
before { login_as user }
|
||||
|
||||
path "/api/dfc/enterprises" do
|
||||
get "List enterprises" do
|
||||
produces "application/json"
|
||||
|
||||
response "200", "successful" do
|
||||
context "as platform user" do
|
||||
include_context "authenticated as platform"
|
||||
|
||||
context "without permissions" do
|
||||
run_test! do
|
||||
expect(response.body).to eq ""
|
||||
end
|
||||
end
|
||||
|
||||
context "with access to one enterprise" do
|
||||
before do
|
||||
DfcPermission.create!(
|
||||
user:, enterprise_id: enterprise.id,
|
||||
scope: "ReadEnterprise", grantee: "cqcm-dev",
|
||||
)
|
||||
end
|
||||
|
||||
run_test! do
|
||||
expect(response.body).to include "Fred's Farm"
|
||||
expect(response.body).not_to include "Fred's Icecream"
|
||||
end
|
||||
end
|
||||
|
||||
context "with access to two enterprises" do
|
||||
before do
|
||||
DfcPermission.create!(
|
||||
user:, enterprise_id: enterprise.id,
|
||||
scope: "ReadEnterprise", grantee: "cqcm-dev",
|
||||
)
|
||||
DfcPermission.create!(
|
||||
user:, enterprise_id: other_enterprise.id,
|
||||
scope: "ReadEnterprise", grantee: "cqcm-dev",
|
||||
)
|
||||
end
|
||||
|
||||
run_test! do
|
||||
expect(response.body).to include "Fred's Farm"
|
||||
expect(response.body).to include "Fred's Icecream"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "as user owning two enterprises" do
|
||||
run_test! do
|
||||
expect(response.body).to include "Fred's Farm"
|
||||
expect(response.body).to include "Fred's Icecream"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
path "/api/dfc/enterprises/{id}" do
|
||||
get "Show enterprise" do
|
||||
parameter name: :id, in: :path, type: :string
|
||||
@@ -91,18 +163,6 @@ RSpec.describe "Enterprises", swagger_doc: "dfc.yaml" do
|
||||
"dfc-b:affiliates" => "http://test.host/api/dfc/enterprise_groups/60000",
|
||||
"dfc-b:websitePage" => "https://openfoodnetwork.org",
|
||||
)
|
||||
|
||||
# Insert static value to keep documentation deterministic:
|
||||
response.body.gsub!(
|
||||
%r{active_storage/[0-9A-Za-z/=-]*/logo-white.png},
|
||||
"active_storage/url/logo-white.png",
|
||||
).gsub!(
|
||||
%r{active_storage/[0-9A-Za-z/=-]*/logo.png},
|
||||
"active_storage/url/logo.png",
|
||||
).gsub!(
|
||||
%r{active_storage/[0-9A-Za-z/=-]*/promo.png},
|
||||
"active_storage/url/promo.png",
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -93,6 +93,12 @@ RSpec.describe "Platforms", swagger_doc: "dfc.yaml" do
|
||||
example.metadata[:operation][:parameters].first[:schema][:example]
|
||||
end
|
||||
|
||||
before do
|
||||
stub_request(:post, "https://kc.cqcm.startinblox.com/realms/startinblox/protocol/openid-connect/token")
|
||||
.and_return(body: { access_token: "testtoken" }.to_json)
|
||||
stub_request(:post, "https://api.proxy-dev.cqcm.startinblox.com/djangoldp-dfc/webhook/")
|
||||
end
|
||||
|
||||
run_test! do
|
||||
expect(json_response["@id"]).to eq "https://api.proxy-dev.cqcm.startinblox.com/profile"
|
||||
end
|
||||
|
||||
@@ -14,7 +14,11 @@ RSpec.describe "SuppliedProducts", swagger_doc: "dfc.yaml" do
|
||||
)
|
||||
}
|
||||
let(:variant) {
|
||||
build(:base_variant, id: 10_001, unit_value: 1, primary_taxon: taxon, supplier: enterprise)
|
||||
build(
|
||||
:base_variant,
|
||||
id: 10_001, sku: "BP", unit_value: 1,
|
||||
primary_taxon: taxon, supplier: enterprise,
|
||||
)
|
||||
}
|
||||
let(:taxon) {
|
||||
build(
|
||||
@@ -34,6 +38,47 @@ RSpec.describe "SuppliedProducts", swagger_doc: "dfc.yaml" do
|
||||
|
||||
before { login_as user }
|
||||
|
||||
path "/api/dfc/supplied_products" do
|
||||
get "Index SuppliedProducts" do
|
||||
produces "application/json"
|
||||
|
||||
response "200", "success" do
|
||||
context "as platform user" do
|
||||
include_context "authenticated as platform"
|
||||
|
||||
context "without permissions" do
|
||||
run_test! do
|
||||
expect(response.body).to eq ""
|
||||
end
|
||||
end
|
||||
|
||||
context "with access to products" do
|
||||
before do
|
||||
DfcPermission.create!(
|
||||
user:, enterprise_id: 10_000,
|
||||
scope: "ReadEnterprise", grantee: "cqcm-dev",
|
||||
)
|
||||
DfcPermission.create!(
|
||||
user:, enterprise_id: 10_000,
|
||||
scope: "ReadProducts", grantee: "cqcm-dev",
|
||||
)
|
||||
end
|
||||
|
||||
run_test! do
|
||||
expect(response.body).to include "Pesto"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "as user owning two enterprises" do
|
||||
run_test! do
|
||||
expect(response.body).to include "Pesto"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
path "/api/dfc/enterprises/{enterprise_id}/supplied_products" do
|
||||
parameter name: :enterprise_id, in: :path, type: :string
|
||||
|
||||
@@ -167,10 +212,6 @@ RSpec.describe "SuppliedProducts", swagger_doc: "dfc.yaml" do
|
||||
"supplied_products/#{variant_id}",
|
||||
"supplied_products/10001"
|
||||
)
|
||||
.gsub!(
|
||||
%r{active_storage/[0-9A-Za-z/=-]*/logo-white.png},
|
||||
"active_storage/url/logo-white.png",
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -195,12 +236,6 @@ RSpec.describe "SuppliedProducts", swagger_doc: "dfc.yaml" do
|
||||
expect(json_response["ofn:spree_product_id"]).to eq 90_000
|
||||
expect(json_response["dfc-b:hasType"]).to eq("dfc-pt:processed-vegetable")
|
||||
expect(json_response["ofn:image"]).to include("logo-white.png")
|
||||
|
||||
# Insert static value to keep documentation deterministic:
|
||||
response.body.gsub!(
|
||||
%r{active_storage/[0-9A-Za-z/=-]*/logo-white.png},
|
||||
"active_storage/url/logo-white.png",
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ RSpec.describe AddressBuilder do
|
||||
build(
|
||||
:address,
|
||||
id: 1, address1: "Paradise 15", zipcode: "0001", city: "Goosnargh",
|
||||
latitude: -25.345376, longitude: 131.0312006,
|
||||
state: build(:state, name: "Victoria")
|
||||
)
|
||||
}
|
||||
@@ -38,5 +39,10 @@ RSpec.describe AddressBuilder do
|
||||
it "assigns a region" do
|
||||
expect(result.region).to eq "Victoria"
|
||||
end
|
||||
|
||||
it "assigns coordinates" do
|
||||
expect(result.latitude).to eq(-25.345376)
|
||||
expect(result.longitude).to eq 131.0312006
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,15 +2,17 @@
|
||||
|
||||
require_relative "../spec_helper"
|
||||
|
||||
RSpec.describe DfcBuilder do
|
||||
RSpec.describe CatalogItemBuilder do
|
||||
let(:variant) { build(:variant) }
|
||||
|
||||
describe ".catalog_item" do
|
||||
it "assigns a semantic id" do
|
||||
before do
|
||||
variant.id = 5
|
||||
variant.supplier_id = 7
|
||||
end
|
||||
|
||||
item = DfcBuilder.catalog_item(variant)
|
||||
it "assigns a semantic id" do
|
||||
item = CatalogItemBuilder.catalog_item(variant)
|
||||
|
||||
expect(item.semanticId).to eq(
|
||||
"http://test.host/api/dfc/enterprises/7/catalog_items/5"
|
||||
@@ -18,15 +20,20 @@ RSpec.describe DfcBuilder do
|
||||
end
|
||||
|
||||
it "refers to a supplied product" do
|
||||
variant.id = 5
|
||||
variant.supplier_id = 7
|
||||
|
||||
item = DfcBuilder.catalog_item(variant)
|
||||
item = CatalogItemBuilder.catalog_item(variant)
|
||||
|
||||
expect(item.product.semanticId).to eq(
|
||||
"http://test.host/api/dfc/enterprises/7/supplied_products/5"
|
||||
)
|
||||
end
|
||||
|
||||
it "refers to the supplier" do
|
||||
item = CatalogItemBuilder.catalog_item(variant)
|
||||
|
||||
expect(item.managedBy).to eq(
|
||||
"http://test.host/api/dfc/enterprises/7"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe ".apply_stock" do
|
||||
|
||||
28
engines/dfc_provider/spec/services/proxy_notifier_spec.rb
Normal file
28
engines/dfc_provider/spec/services/proxy_notifier_spec.rb
Normal file
@@ -0,0 +1,28 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative "../spec_helper"
|
||||
|
||||
# These tests depend on valid OpenID Connect client credentials in your
|
||||
# `.env.test.local` file.
|
||||
#
|
||||
# OPENID_APP_ID="..."
|
||||
# OPENID_APP_SECRET="..."
|
||||
RSpec.describe ProxyNotifier do
|
||||
let(:platform) { "cqcm-dev" }
|
||||
let(:enterprise_url) { "http://ofn.example.net/api/dfc/enterprises/10000" }
|
||||
|
||||
it "receives an access token", :vcr do
|
||||
token = subject.request_token(platform)
|
||||
expect(token).to be_a String
|
||||
expect(token.length).to be > 20
|
||||
end
|
||||
|
||||
it "notifies the proxy", :vcr do
|
||||
# The test server is not reachable by the notified server.
|
||||
# If you don't have valid credentials, you'll get an unauthorized error.
|
||||
# Correctly authenticated, the server fails to update its data.
|
||||
expect {
|
||||
subject.refresh(platform, enterprise_url)
|
||||
}.to raise_error Faraday::ServerError
|
||||
end
|
||||
end
|
||||
@@ -3,12 +3,18 @@
|
||||
# Authenticate via Authoriztion token
|
||||
RSpec.shared_context "authenticated as platform" do
|
||||
let(:Authorization) {
|
||||
"Bearer #{file_fixture('startinblox_access_token.jwt').read}"
|
||||
"Bearer #{access_token}"
|
||||
}
|
||||
let(:access_token) {
|
||||
file_fixture("startinblox_access_token.jwt").read
|
||||
}
|
||||
|
||||
before do
|
||||
payload = JWT.decode(access_token, nil, false, { algorithm: "RS256" }).first
|
||||
issued_at = Time.zone.at(payload["iat"])
|
||||
|
||||
# Once upon a time when the access token hadn't expired yet...
|
||||
travel_to(Date.parse("2025-06-13"))
|
||||
travel_to(issued_at)
|
||||
|
||||
# Reset any login via session cookie.
|
||||
login_as nil
|
||||
|
||||
@@ -62,7 +62,13 @@ module OpenFoodNetwork
|
||||
Enable the inventory.
|
||||
DESC
|
||||
"cqcm-dev" => <<~DESC,
|
||||
Show DFC Permissions interface to share data with CQCM dev platform.
|
||||
Show DFC Permissions interface with development platform.
|
||||
DESC
|
||||
"cqcm-stg" => <<~DESC,
|
||||
Show DFC Permissions interface to share data with CQCM staging platform.
|
||||
DESC
|
||||
"cqcm" => <<~DESC,
|
||||
Show DFC Permissions interface to share data with CQCM.
|
||||
DESC
|
||||
}.merge(conditional_features).freeze;
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJRRlJES1daQ2hzMllQYnRqYl9yQUtwQzNzMFo0T2FCMEtFQ056NnlxWHQ0In0.eyJleHAiOjE3NDk3ODk3MDcsImlhdCI6MTc0OTc4OTQwNywianRpIjoiOWE4ODU4NDAtODhjNy00OTliLWIyOGUtMmE5ZmViM2EyNmU0IiwiaXNzIjoiaHR0cHM6Ly9rYy5jcWNtLnN0YXJ0aW5ibG94LmNvbS9yZWFsbXMvc3RhcnRpbmJsb3giLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiNWZlM2MyNmMtMjczNi00OGE0LWI2Y2YtYTllM2JjZmNkZjAwIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoiaHR0cHM6Ly93YXRlcmxvb3JlZ2lvbmZvb2QuY2EvcG9ydGFsL3Byb2ZpbGUiLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsib2ZmbGluZV9hY2Nlc3MiLCJ1bWFfYXV0aG9yaXphdGlvbiIsImRlZmF1bHQtcm9sZXMtc3RhcnRpbmJsb3giXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6IlJlYWRFbnRlcnByaXNlIFJlYWRQcm9kdWN0cyIsImNsaWVudEhvc3QiOiIxNzIuMTguMC4xIiwiY2xpZW50QWRkcmVzcyI6IjE3Mi4xOC4wLjEiLCJjbGllbnRfaWQiOiJodHRwczovL3dhdGVybG9vcmVnaW9uZm9vZC5jYS9wb3J0YWwvcHJvZmlsZSJ9.Ln7wY0_ptRAza7M8w3yXU02TvluH028uaoJ5VHiN9-PnakokzHve7SCuSd1hvVikYAivWFIBRP97vwfpb_DW-d9Afk_XcQqcA0L36ynUIZ69X5uQ2zakEW0kB6pwqd8AL8tlWVUg2PixBXJ6daJcgWNF7RlKXg6wgy4JYL_VxD3VJjST911-z4_TMuQ2OC-3SJNwNv3BspSmUXm7F6y8xGFN7wuCPjU90WIiZ_vxTbVdM0zNtBM0uMJFeFv2_ZzoJIIiNHYLWtD3LrKcXePLSejpo-DPVWR_lGdDdM7BmzOHPKZ9KMaV-oa3lYNYC5shhJOpoB3vHngtdYdv8jq7Cg
|
||||
eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJRRlJES1daQ2hzMllQYnRqYl9yQUtwQzNzMFo0T2FCMEtFQ056NnlxWHQ0In0.eyJleHAiOjE3NTg2ODY1OTUsImlhdCI6MTc1ODY4NjI5NSwianRpIjoiMjhjZmZkOGItNWNlNi00ZjgxLWFiYjUtMjY0NTg4MjhhM2E3IiwiaXNzIjoiaHR0cHM6Ly9rYy5jcWNtLnN0YXJ0aW5ibG94LmNvbS9yZWFsbXMvc3RhcnRpbmJsb3giLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiNWZlM2MyNmMtMjczNi00OGE0LWI2Y2YtYTllM2JjZmNkZjAwIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoiaHR0cHM6Ly9hcGkucHJveHktZGV2LmNxY20uc3RhcnRpbmJsb3guY29tL3Byb2ZpbGUiLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsib2ZmbGluZV9hY2Nlc3MiLCJ1bWFfYXV0aG9yaXphdGlvbiIsImRlZmF1bHQtcm9sZXMtc3RhcnRpbmJsb3giXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6IlJlYWRFbnRlcnByaXNlIiwiY2xpZW50SG9zdCI6IjE3Mi4xOC4wLjEiLCJjbGllbnRBZGRyZXNzIjoiMTcyLjE4LjAuMSIsImNsaWVudF9pZCI6Imh0dHBzOi8vYXBpLnByb3h5LWRldi5jcWNtLnN0YXJ0aW5ibG94LmNvbS9wcm9maWxlIn0.DH0o4GJxKJumSbuLwdk3wz0DdwUvBM9NH6E07lkP3s1iJ23bMIE_p4gsL44RQHjB05nZWDXYrwyIJK8vLlrd8oRcZCzHgBHMQ1_-8G_JFb6s8IW_q7ROZqPwm7Wknt5fSiE7Tf3NXR2Xr6afm4f8BAcQDd2i7LjIGHomEt0pG8Q3HWzSpXJ9scJ_9enXRZTd02JLOnargKdpK9VPfGO8HjxDMip_W-aGKQ89-3XF-q3ZjC-rOxK7ZzOEbT-YE_M3nrfVeX9BnwX38vAk97UKhsLGFtupsSD3aoS6bZb2Axv3cn6e0IJ3G2iPXy36WSc_WVnhRUt8H5E7YDeHJpzTZg
|
||||
|
||||
110
spec/fixtures/vcr_cassettes/ProxyNotifier/notifies_the_proxy.yml
vendored
Normal file
110
spec/fixtures/vcr_cassettes/ProxyNotifier/notifies_the_proxy.yml
vendored
Normal file
File diff suppressed because one or more lines are too long
52
spec/fixtures/vcr_cassettes/ProxyNotifier/receives_an_access_token.yml
vendored
Normal file
52
spec/fixtures/vcr_cassettes/ProxyNotifier/receives_an_access_token.yml
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
---
|
||||
http_interactions:
|
||||
- request:
|
||||
method: post
|
||||
uri: https://kc.cqcm.startinblox.com/realms/startinblox/protocol/openid-connect/token
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: client_id=https%3A%2F%2Fstaging.openfoodnetwork.org.uk%2F&client_secret=<HIDDEN-OPENID_APP_SECRET>&grant_type=client_credentials&scope=WriteEnterprise
|
||||
headers:
|
||||
User-Agent:
|
||||
- Faraday v2.9.0
|
||||
Content-Type:
|
||||
- application/x-www-form-urlencoded
|
||||
Accept-Encoding:
|
||||
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
||||
Accept:
|
||||
- "*/*"
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Server:
|
||||
- nginx/1.22.1
|
||||
Date:
|
||||
- Fri, 19 Sep 2025 06:09:58 GMT
|
||||
Content-Type:
|
||||
- application/json
|
||||
Content-Length:
|
||||
- '1726'
|
||||
Connection:
|
||||
- keep-alive
|
||||
Cache-Control:
|
||||
- no-store
|
||||
Pragma:
|
||||
- no-cache
|
||||
Referrer-Policy:
|
||||
- no-referrer
|
||||
Strict-Transport-Security:
|
||||
- max-age=31536000; includeSubDomains
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Frame-Options:
|
||||
- SAMEORIGIN
|
||||
X-Xss-Protection:
|
||||
- 1; mode=block
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: '{"access_token":"<HIDDEN-OPENID-TOKEN>","expires_in":300,"refresh_expires_in":0,"token_type":"Bearer","not-before-policy":0,"scope":"WriteEnterprise
|
||||
profile email"}'
|
||||
recorded_at: Fri, 19 Sep 2025 06:09:58 GMT
|
||||
recorded_with: VCR 6.2.0
|
||||
16
spec/requests/well_known_spec.rb
Normal file
16
spec/requests/well_known_spec.rb
Normal file
@@ -0,0 +1,16 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe "/.well-known/" do
|
||||
describe "dfc/" do
|
||||
it "publishes our endpoints" do
|
||||
get "/.well-known/dfc/"
|
||||
|
||||
expect(response).to have_http_status :ok
|
||||
expect(response.body).to include "ReadEnterprise"
|
||||
expect(response.content_type).to eq "application/json; charset=utf-8"
|
||||
expect(response.parsed_body.count).to eq 2
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -80,6 +80,12 @@ RSpec.configure do |config|
|
||||
|
||||
next if response&.body.blank?
|
||||
|
||||
# Replace random values from generated strings for a deterministic documentation.
|
||||
response.body.gsub!(
|
||||
%r{/rails/active_storage/[0-9A-Za-z/=-]*/([^/.]+).png},
|
||||
'/rails/active_storage/url/\1.png',
|
||||
)
|
||||
|
||||
# Include response as example in the documentation.
|
||||
example.metadata[:response][:content] ||= {}
|
||||
example.metadata[:response][:content].deep_merge!(
|
||||
|
||||
@@ -11,6 +11,9 @@ RSpec.describe "DFC Permissions", feature: "cqcm-dev", vcr: true do
|
||||
|
||||
before do
|
||||
login_as enterprise.owner
|
||||
|
||||
# Disable data proxy webhook which can't reach our test server.
|
||||
allow_any_instance_of(ProxyNotifier).to receive(:refresh)
|
||||
end
|
||||
|
||||
it "is not visible when no platform is enabled" do
|
||||
|
||||
134
swagger/dfc.yaml
134
swagger/dfc.yaml
@@ -407,6 +407,92 @@ paths:
|
||||
dfc-b:hasCity: Herndon
|
||||
dfc-b:hasCountry: Australia
|
||||
dfc-b:region: Victoria
|
||||
"/api/dfc/enterprises":
|
||||
get:
|
||||
summary: List enterprises
|
||||
tags:
|
||||
- Enterprises
|
||||
responses:
|
||||
'200':
|
||||
description: successful
|
||||
content:
|
||||
application/json:
|
||||
examples:
|
||||
test_example:
|
||||
value:
|
||||
"@context": https://www.datafoodconsortium.org
|
||||
"@graph":
|
||||
- "@id": http://test.host/api/dfc/enterprises/10001
|
||||
"@type": dfc-b:Enterprise
|
||||
dfc-b:hasAddress: http://test.host/api/dfc/addresses/40001
|
||||
dfc-b:name: Fred's Icecream
|
||||
dfc-b:hasDescription: We use our strawberries to make icecream.
|
||||
dfc-b:VATnumber: 123 457
|
||||
dfc-b:hasMainContact: http://test.host/api/dfc/enterprises/10001#mainContact
|
||||
ofn:long_description: "<p>Hello, world!</p><p>This is a paragraph.</p>"
|
||||
- "@id": http://test.host/api/dfc/enterprises/10000
|
||||
"@type": dfc-b:Enterprise
|
||||
dfc-b:hasAddress: http://test.host/api/dfc/addresses/40000
|
||||
dfc-b:hasPhoneNumber: 0404 444 000 200
|
||||
dfc-b:email: hello@example.org
|
||||
dfc-b:websitePage: https://openfoodnetwork.org
|
||||
dfc-b:hasSocialMedia: http://test.host/api/dfc/enterprises/10000/social_medias/facebook
|
||||
dfc-b:logo: http://test.host/rails/active_storage/url/logo.png
|
||||
dfc-b:name: Fred's Farm
|
||||
dfc-b:hasDescription: This is an awesome enterprise
|
||||
dfc-b:VATnumber: 123 456
|
||||
dfc-b:manages: http://test.host/api/dfc/enterprises/10000/catalog_items/10001
|
||||
dfc-b:supplies: http://test.host/api/dfc/enterprises/10000/supplied_products/10001
|
||||
dfc-b:hasMainContact: http://test.host/api/dfc/enterprises/10000#mainContact
|
||||
ofn:long_description: "<p>Hello, world!</p><p>This is a paragraph.</p>"
|
||||
ofn:contact_name: Fred Farmer
|
||||
ofn:logo_url: http://test.host/rails/active_storage/url/logo.png
|
||||
ofn:promo_image_url: http://test.host/rails/active_storage/url/promo.png
|
||||
- "@id": http://test.host/api/dfc/enterprises/10001#mainContact
|
||||
"@type": dfc-b:Person
|
||||
- "@id": http://test.host/api/dfc/enterprises/10000#mainContact
|
||||
"@type": dfc-b:Person
|
||||
dfc-b:firstName: Fred
|
||||
dfc-b:familyName: Farmer
|
||||
- "@id": http://test.host/api/dfc/addresses/40001
|
||||
"@type": dfc-b:Address
|
||||
dfc-b:hasStreet: 42 Doveton Street
|
||||
dfc-b:hasPostalCode: '20170'
|
||||
dfc-b:hasCity: Herndon
|
||||
dfc-b:hasCountry: Australia
|
||||
dfc-b:region: Victoria
|
||||
- "@id": http://test.host/api/dfc/addresses/40000
|
||||
"@type": dfc-b:Address
|
||||
dfc-b:hasStreet: 42 Doveton Street
|
||||
dfc-b:hasPostalCode: '20170'
|
||||
dfc-b:hasCity: Herndon
|
||||
dfc-b:hasCountry: Australia
|
||||
dfc-b:latitude: -25.345376
|
||||
dfc-b:longitude: 131.0312006
|
||||
dfc-b:region: Victoria
|
||||
- "@id": http://test.host/api/dfc/enterprises/10000/supplied_products/10001
|
||||
"@type": dfc-b:SuppliedProduct
|
||||
dfc-b:name: Apple - 1g
|
||||
dfc-b:description: Round
|
||||
dfc-b:hasQuantity:
|
||||
"@type": dfc-b:QuantitativeValue
|
||||
dfc-b:hasUnit: dfc-m:Gram
|
||||
dfc-b:value: 1.0
|
||||
dfc-b:image: http://test.host/rails/active_storage/url/logo-white.png
|
||||
dfc-b:isVariantOf: http://test.host/api/dfc/product_groups/90000
|
||||
ofn:spree_product_id: 90000
|
||||
ofn:spree_product_uri: http://test.host/api/dfc/enterprises/10000?spree_product_id=90000
|
||||
ofn:image: http://test.host/rails/active_storage/url/logo-white.png
|
||||
- "@id": http://test.host/api/dfc/enterprises/10000/catalog_items/10001
|
||||
"@type": dfc-b:CatalogItem
|
||||
dfc-b:references: http://test.host/api/dfc/enterprises/10000/supplied_products/10001
|
||||
dfc-b:sku: APP
|
||||
dfc-b:stockLimitation: 5
|
||||
dfc-b:offeredThrough: http://test.host/api/dfc/enterprises/10000/offers/10001
|
||||
- "@id": http://test.host/api/dfc/enterprises/10000/social_medias/facebook
|
||||
"@type": dfc-b:SocialMedia
|
||||
dfc-b:name: facebook
|
||||
dfc-b:URL: https://facebook.com/user
|
||||
"/api/dfc/enterprises/{id}":
|
||||
get:
|
||||
summary: Show enterprise
|
||||
@@ -457,6 +543,8 @@ paths:
|
||||
dfc-b:hasPostalCode: '20170'
|
||||
dfc-b:hasCity: Herndon
|
||||
dfc-b:hasCountry: Australia
|
||||
dfc-b:latitude: -25.345376
|
||||
dfc-b:longitude: 131.0312006
|
||||
dfc-b:region: Victoria
|
||||
- "@id": http://test.host/api/dfc/enterprises/10000/supplied_products/10001
|
||||
"@type": dfc-b:SuppliedProduct
|
||||
@@ -726,6 +814,52 @@ paths:
|
||||
dfc-b:URL: https://facebook.com/user
|
||||
'404':
|
||||
description: not found
|
||||
"/api/dfc/supplied_products":
|
||||
get:
|
||||
summary: Index SuppliedProducts
|
||||
tags:
|
||||
- SuppliedProducts
|
||||
responses:
|
||||
'200':
|
||||
description: success
|
||||
content:
|
||||
application/json:
|
||||
examples:
|
||||
test_example:
|
||||
value:
|
||||
"@context": https://www.datafoodconsortium.org
|
||||
"@graph":
|
||||
- "@id": http://test.host/api/dfc/enterprises/10000/catalog_items/10001
|
||||
"@type": dfc-b:CatalogItem
|
||||
dfc-b:references: http://test.host/api/dfc/enterprises/10000/supplied_products/10001
|
||||
dfc-b:sku: BP
|
||||
dfc-b:stockLimitation: 5
|
||||
dfc-b:offeredThrough: http://test.host/api/dfc/enterprises/10000/offers/10001
|
||||
- "@id": http://test.host/api/dfc/enterprises/10000/supplied_products/10001
|
||||
"@type": dfc-b:SuppliedProduct
|
||||
dfc-b:name: Pesto - 1g
|
||||
dfc-b:description: Basil Pesto
|
||||
dfc-b:hasType: dfc-pt:processed-vegetable
|
||||
dfc-b:hasQuantity:
|
||||
"@type": dfc-b:QuantitativeValue
|
||||
dfc-b:hasUnit: dfc-m:Gram
|
||||
dfc-b:value: 1.0
|
||||
dfc-b:image: http://test.host/rails/active_storage/url/logo-white.png
|
||||
dfc-b:isVariantOf: http://test.host/api/dfc/product_groups/90000
|
||||
ofn:spree_product_id: 90000
|
||||
ofn:spree_product_uri: http://test.host/api/dfc/enterprises/10000?spree_product_id=90000
|
||||
ofn:image: http://test.host/rails/active_storage/url/logo-white.png
|
||||
- "@id": http://test.host/api/dfc/product_groups/90000
|
||||
"@type": dfc-b:SuppliedProduct
|
||||
dfc-b:name: Pesto
|
||||
dfc-b:hasVariant: http://test.host/api/dfc/enterprises/10000/supplied_products/10001
|
||||
- "@id": http://test.host/api/dfc/enterprises/10000/offers/10001
|
||||
"@type": dfc-b:Offer
|
||||
dfc-b:hasPrice:
|
||||
"@type": dfc-b:Price
|
||||
dfc-b:value: 19.99
|
||||
dfc-b:hasUnit: dfc-m:AustralianDollar
|
||||
dfc-b:stockLimitation: 5
|
||||
"/api/dfc/enterprises/{enterprise_id}/supplied_products":
|
||||
parameters:
|
||||
- name: enterprise_id
|
||||
|
||||
Reference in New Issue
Block a user