diff --git a/app/views/admin/enterprises/form/_dfc_permissions.html.haml b/app/views/admin/enterprises/form/_dfc_permissions.html.haml index dd12047bf6..bb3f7ab6c3 100644 --- a/app/views/admin/enterprises/form/_dfc_permissions.html.haml +++ b/app/views/admin/enterprises/form/_dfc_permissions.html.haml @@ -19,7 +19,7 @@ :plain diff --git a/engines/dfc_provider/app/controllers/dfc_provider/platforms_controller.rb b/engines/dfc_provider/app/controllers/dfc_provider/platforms_controller.rb index 3b614d79a4..7da338949d 100644 --- a/engines/dfc_provider/app/controllers/dfc_provider/platforms_controller.rb +++ b/engines/dfc_provider/app/controllers/dfc_provider/platforms_controller.rb @@ -2,6 +2,12 @@ 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 + # DANGER! # This endpoint is open to CSRF attacks. # This is a temporary measure until the DFC Permissions module accesses @@ -11,15 +17,86 @@ module DfcProvider before_action :check_enterprise def index - render json: <<~JSON - {"@context":"https://cdn.startinblox.com/owl/context-bis.jsonld","@id":"https://mydataserver.com/enterprises/1/platforms","dfc-t:platforms":{"@list":[{"@id":"https://waterlooregionfood.ca/portal/profile","@type":"dfc-t:Platform","_id":{"$oid":"682afcc4966dbb3aa7464d56"},"description":"A super duper portal for the waterloo region","dfc-t:hasAssignedScopes":{"@list":[{"@id":"https://data-server.cqcm.startinblox.com/enterprises/1/platforms/scopes/ReadEnterprise","@type":"dfc-t:Scope","dfc-t:scope":"ReadEnterprise"},{"@id":"https://data-server.cqcm.startinblox.com/enterprises/1/platforms/scopes/WriteEnterprise","@type":"dfc-t:Scope","dfc-t:scope":"WriteEnterprise"},{"@id":"https://data-server.cqcm.startinblox.com/enterprises/1/platforms/scopes/ReadProducts","@type":"dfc-t:Scope","dfc-t:scope":"ReadProducts"},{"@id":"https://data-server.cqcm.startinblox.com/enterprises/1/platforms/scopes/WriteProducts","@type":"dfc-t:Scope","dfc-t:scope":"WriteProducts"},{"@id":"https://data-server.cqcm.startinblox.com/enterprises/1/platforms/scopes/ReadOrders","@type":"dfc-t:Scope","dfc-t:scope":"ReadOrders"},{"@id":"https://data-server.cqcm.startinblox.com/enterprises/1/platforms/scopes/WriteOrders","@type":"dfc-t:Scope","dfc-t:scope":"WriteOrders"}],"@type":"rdf:List"},"termsandconditions":"https://waterlooregionfood.ca/terms-and-conditions","title":"Waterloo Region Food Portal"},{"@id":"https://anotherplatform.ca/portal/profile","@type":"dfc-t:Platform","_id":{"$oid":"682b2e2b031c28f69cda1645"},"description":"A super duper portal for the waterloo region","dfc-t:hasAssignedScopes":{"@list":[],"@type":"rdf:List"},"termsandconditions":"https://anotherplatform.ca/terms-and-conditions","title":"anotherplatform Portal"}],"@type":"rdf:List"}} - JSON + render json: platforms + end + + def show + render json: platform(params[:id]) end def update - render json: <<~JSON - {"@id":"https://anotherplatform.ca/portal/profile","@type":"dfc-t:Platform","description":"A super duper portal for the waterloo region","dfc-t:hasAssignedScopes":{"@list":[{"@id":"https://data-server.cqcm.startinblox.com/enterprises/1/platforms/scopes/ReadEnterprise","@type":"dfc-t:Scope","dfc-t:scope":"ReadEnterprise"},{"@id":"https://data-server.cqcm.startinblox.com/enterprises/1/platforms/scopes/WriteEnterprise","@type":"dfc-t:Scope","dfc-t:scope":"WriteEnterprise"},{"@id":"https://data-server.cqcm.startinblox.com/enterprises/1/platforms/scopes/ReadProducts","@type":"dfc-t:Scope","dfc-t:scope":"ReadProducts"},{"@id":"https://data-server.cqcm.startinblox.com/enterprises/1/platforms/scopes/WriteProducts","@type":"dfc-t:Scope","dfc-t:scope":"WriteProducts"},{"@id":"https://data-server.cqcm.startinblox.com/enterprises/1/platforms/scopes/ReadOrders","@type":"dfc-t:Scope","dfc-t:scope":"ReadOrders"},{"@id":"https://data-server.cqcm.startinblox.com/enterprises/1/platforms/scopes/WriteOrders","@type":"dfc-t:Scope","dfc-t:scope":"WriteOrders"}],"@type":"rdf:List"},"termsandconditions":"https://anotherplatform.ca/terms-and-conditions","title":"anotherplatform Portal"} - JSON + key = params[:id] + requested_platform = JSON.parse(request.body.read) + requested_scopes = requested_platform + .dig("dfc-t:hasAssignedScopes", "@list") + .pluck("@id") + .map { |uri| uri[/[a-zA-Z]+$/] } # return last part like ReadEnterprise + current_scopes = granted_scopes(key) + 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 + + scopes_to_create.each do |scope| + DfcPermission.create!( + user: current_user, + enterprise: current_enterprise, + scope:, + grantee: key, + ) + end + render json: platform(key) + end + + private + + def platforms + id = DfcProvider::Engine.routes.url_helpers.enterprise_platforms_url(current_enterprise.id) + platforms = PLATFORM_IDS.keys.map(&method(:platform)) + + { + '@context': "https://cdn.startinblox.com/owl/context-bis.jsonld", + '@id': id, + 'dfc-t:platforms': { + '@type': "rdf:List", + '@list': platforms, + } + } + end + + def platform(key) + { + '@type': "dfc-t:Platform", + '@id': PLATFORM_IDS[key], + localId: key, + 'dfc-t:hasAssignedScopes': { + '@type': "rdf:List", + '@list': scopes(key), + } + } + end + + def scopes(platform_id) + granted_scopes(platform_id).map do |scope| + { + '@id': "https://example.com/scopes/#{scope}", + '@type': "dfc-t:Scope", + 'dfc-t:scope': scope, + } + end + end + + def granted_scopes(platform_id) + DfcPermission.where( + user: current_user, + enterprise: current_enterprise, + grantee: platform_id, + ).pluck(:scope) end end end diff --git a/engines/dfc_provider/config/routes.rb b/engines/dfc_provider/config/routes.rb index 2de21e6406..6c7c487040 100644 --- a/engines/dfc_provider/config/routes.rb +++ b/engines/dfc_provider/config/routes.rb @@ -5,7 +5,7 @@ DfcProvider::Engine.routes.draw do resources :enterprises, only: [:show] do resources :catalog_items, only: [:index, :show, :update] resources :offers, only: [:show, :update] - resources :platforms, only: [:index, :update] + resources :platforms, only: [:index, :show, :update] resources :supplied_products, only: [:create, :show, :update] resources :social_medias, only: [:show] end diff --git a/engines/dfc_provider/spec/requests/platforms_spec.rb b/engines/dfc_provider/spec/requests/platforms_spec.rb index 1e493ae43e..bc5ea5e372 100644 --- a/engines/dfc_provider/spec/requests/platforms_spec.rb +++ b/engines/dfc_provider/spec/requests/platforms_spec.rb @@ -23,7 +23,7 @@ RSpec.describe "Platforms", swagger_doc: "dfc.yaml" do let(:enterprise_id) { enterprise.id } run_test! do - expect(json_response["@id"]).to eq "https://mydataserver.com/enterprises/1/platforms" + expect(json_response["@id"]).to eq "http://test.host/api/dfc/enterprises/10000/platforms" end end end @@ -33,15 +33,68 @@ RSpec.describe "Platforms", swagger_doc: "dfc.yaml" do parameter name: :enterprise_id, in: :path, type: :string parameter name: :platform_id, in: :path, type: :string - put "Update authorized scopes of a platform" do + get "Show platform scopes" do produces "application/json" response "200", "successful" do let(:enterprise_id) { enterprise.id } - let(:platform_id) { "682b2e2b031c28f69cda1645" } + let(:platform_id) { "cqcm-dev" } run_test! do - expect(json_response["@id"]).to eq "https://anotherplatform.ca/portal/profile" + expect(json_response["@id"]).to eq "https://api.proxy-dev.cqcm.startinblox.com/profile" + end + end + end + + put "Update authorized scopes of a platform" do + consumes "application/json" + produces "application/json" + + parameter name: :platform, in: :body, schema: { + example: { + '@context': "https://cdn.startinblox.com/owl/context-bis.jsonld", + '@id': "http://localhost:3000/api/dfc/enterprises/3/platforms/cqcm-dev", + 'dfc-t:hasAssignedScopes': { + '@list': [ + { + '@id': "https://example.com/scopes/ReadEnterprise", + '@type': "dfc-t:Scope" + }, + { + '@id': "https://example.com/scopes/WriteEnterprise", + '@type': "dfc-t:Scope" + }, + { + '@id': "https://example.com/scopes/ReadProducts", + '@type': "dfc-t:Scope" + }, + { + '@id': "https://example.com/scopes/WriteProducts", + '@type': "dfc-t:Scope" + }, + { + '@id': "https://example.com/scopes/ReadOrders", + '@type': "dfc-t:Scope" + }, + { + '@id': "https://example.com/scopes/WriteOrders", + '@type': "dfc-t:Scope" + } + ], + '@type': "rdf:List" + } + } + } + + response "200", "successful" do + let(:enterprise_id) { enterprise.id } + let(:platform_id) { "cqcm-dev" } + let(:platform) do |example| + example.metadata[:operation][:parameters].first[:schema][:example] + end + + run_test! do + expect(json_response["@id"]).to eq "https://api.proxy-dev.cqcm.startinblox.com/profile" end end end diff --git a/swagger/dfc.yaml b/swagger/dfc.yaml index 96ef5949af..ecf27c436e 100644 --- a/swagger/dfc.yaml +++ b/swagger/dfc.yaml @@ -578,48 +578,16 @@ paths: test_example: value: "@context": https://cdn.startinblox.com/owl/context-bis.jsonld - "@id": https://mydataserver.com/enterprises/1/platforms + "@id": http://test.host/api/dfc/enterprises/10000/platforms dfc-t:platforms: - "@list": - - "@id": https://waterlooregionfood.ca/portal/profile - "@type": dfc-t:Platform - _id: - "$oid": 682afcc4966dbb3aa7464d56 - description: A super duper portal for the waterloo region - dfc-t:hasAssignedScopes: - "@list": - - "@id": https://data-server.cqcm.startinblox.com/enterprises/1/platforms/scopes/ReadEnterprise - "@type": dfc-t:Scope - dfc-t:scope: ReadEnterprise - - "@id": https://data-server.cqcm.startinblox.com/enterprises/1/platforms/scopes/WriteEnterprise - "@type": dfc-t:Scope - dfc-t:scope: WriteEnterprise - - "@id": https://data-server.cqcm.startinblox.com/enterprises/1/platforms/scopes/ReadProducts - "@type": dfc-t:Scope - dfc-t:scope: ReadProducts - - "@id": https://data-server.cqcm.startinblox.com/enterprises/1/platforms/scopes/WriteProducts - "@type": dfc-t:Scope - dfc-t:scope: WriteProducts - - "@id": https://data-server.cqcm.startinblox.com/enterprises/1/platforms/scopes/ReadOrders - "@type": dfc-t:Scope - dfc-t:scope: ReadOrders - - "@id": https://data-server.cqcm.startinblox.com/enterprises/1/platforms/scopes/WriteOrders - "@type": dfc-t:Scope - dfc-t:scope: WriteOrders - "@type": rdf:List - termsandconditions: https://waterlooregionfood.ca/terms-and-conditions - title: Waterloo Region Food Portal - - "@id": https://anotherplatform.ca/portal/profile - "@type": dfc-t:Platform - _id: - "$oid": 682b2e2b031c28f69cda1645 - description: A super duper portal for the waterloo region - dfc-t:hasAssignedScopes: - "@list": [] - "@type": rdf:List - termsandconditions: https://anotherplatform.ca/terms-and-conditions - title: anotherplatform Portal "@type": rdf:List + "@list": + - "@type": dfc-t:Platform + "@id": https://api.proxy-dev.cqcm.startinblox.com/profile + localId: cqcm-dev + dfc-t:hasAssignedScopes: + "@type": rdf:List + "@list": [] "/api/dfc/enterprises/{enterprise_id}/platforms/{platform_id}": parameters: - name: enterprise_id @@ -632,8 +600,8 @@ paths: required: true schema: type: string - put: - summary: Update authorized scopes of a platform + get: + summary: Show platform scopes tags: - Platforms responses: @@ -644,32 +612,71 @@ paths: examples: test_example: value: - "@id": https://anotherplatform.ca/portal/profile "@type": dfc-t:Platform - description: A super duper portal for the waterloo region + "@id": https://api.proxy-dev.cqcm.startinblox.com/profile + localId: cqcm-dev dfc-t:hasAssignedScopes: + "@type": rdf:List + "@list": [] + put: + summary: Update authorized scopes of a platform + parameters: [] + tags: + - Platforms + responses: + '200': + description: successful + content: + application/json: + examples: + test_example: + value: + "@type": dfc-t:Platform + "@id": https://api.proxy-dev.cqcm.startinblox.com/profile + localId: cqcm-dev + dfc-t:hasAssignedScopes: + "@type": rdf:List "@list": - - "@id": https://data-server.cqcm.startinblox.com/enterprises/1/platforms/scopes/ReadEnterprise + - "@id": https://example.com/scopes/ReadEnterprise "@type": dfc-t:Scope dfc-t:scope: ReadEnterprise - - "@id": https://data-server.cqcm.startinblox.com/enterprises/1/platforms/scopes/WriteEnterprise + - "@id": https://example.com/scopes/WriteEnterprise "@type": dfc-t:Scope dfc-t:scope: WriteEnterprise - - "@id": https://data-server.cqcm.startinblox.com/enterprises/1/platforms/scopes/ReadProducts + - "@id": https://example.com/scopes/ReadProducts "@type": dfc-t:Scope dfc-t:scope: ReadProducts - - "@id": https://data-server.cqcm.startinblox.com/enterprises/1/platforms/scopes/WriteProducts + - "@id": https://example.com/scopes/WriteProducts "@type": dfc-t:Scope dfc-t:scope: WriteProducts - - "@id": https://data-server.cqcm.startinblox.com/enterprises/1/platforms/scopes/ReadOrders + - "@id": https://example.com/scopes/ReadOrders "@type": dfc-t:Scope dfc-t:scope: ReadOrders - - "@id": https://data-server.cqcm.startinblox.com/enterprises/1/platforms/scopes/WriteOrders + - "@id": https://example.com/scopes/WriteOrders "@type": dfc-t:Scope dfc-t:scope: WriteOrders - "@type": rdf:List - termsandconditions: https://anotherplatform.ca/terms-and-conditions - title: anotherplatform Portal + requestBody: + content: + application/json: + schema: + example: + "@context": https://cdn.startinblox.com/owl/context-bis.jsonld + "@id": http://localhost:3000/api/dfc/enterprises/3/platforms/cqcm-dev + dfc-t:hasAssignedScopes: + "@list": + - "@id": https://example.com/scopes/ReadEnterprise + "@type": dfc-t:Scope + - "@id": https://example.com/scopes/WriteEnterprise + "@type": dfc-t:Scope + - "@id": https://example.com/scopes/ReadProducts + "@type": dfc-t:Scope + - "@id": https://example.com/scopes/WriteProducts + "@type": dfc-t:Scope + - "@id": https://example.com/scopes/ReadOrders + "@type": dfc-t:Scope + - "@id": https://example.com/scopes/WriteOrders + "@type": dfc-t:Scope + "@type": rdf:List "/api/dfc/product_groups/{id}": parameters: - name: enterprise_id