mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-13 18:46:49 +00:00
Compare commits
66 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90288b8cbf | ||
|
|
c821b0a285 | ||
|
|
c37376d67e | ||
|
|
49ec5b2089 | ||
|
|
92ef5fe3d5 | ||
|
|
ae477b7e52 | ||
|
|
0e191e5fca | ||
|
|
64f9ea6fc0 | ||
|
|
058c6749da | ||
|
|
2d15ec4458 | ||
|
|
56eaa8bb98 | ||
|
|
1e1f1e1e1b | ||
|
|
1f8a9f9c76 | ||
|
|
b1893942ac | ||
|
|
ad59ed4d40 | ||
|
|
8491a167ed | ||
|
|
59277292fb | ||
|
|
354a7ab687 | ||
|
|
a5a1ee9bd9 | ||
|
|
ad3f78ef69 | ||
|
|
e02497b163 | ||
|
|
7d2d94398f | ||
|
|
0ecf004ff2 | ||
|
|
444f448207 | ||
|
|
d9381b23d7 | ||
|
|
6a9a2884d6 | ||
|
|
70edd4b898 | ||
|
|
b57a2befd9 | ||
|
|
fef9a78198 | ||
|
|
dd86736170 | ||
|
|
0d8c7ef118 | ||
|
|
20730b8768 | ||
|
|
ad7c69189b | ||
|
|
3a72aefc1c | ||
|
|
e855ea0dbd | ||
|
|
1eba950e19 | ||
|
|
9cd04c087e | ||
|
|
459d25e533 | ||
|
|
b06e562425 | ||
|
|
2936cfebca | ||
|
|
b8ad428b5d | ||
|
|
ca34d24847 | ||
|
|
6e581fce75 | ||
|
|
66041061fb | ||
|
|
e54c27c900 | ||
|
|
b3d3d6bf06 | ||
|
|
5876c52318 | ||
|
|
842f4ae40e | ||
|
|
342ef4e9eb | ||
|
|
210201514e | ||
|
|
2d3f18a71b | ||
|
|
9d284b7110 | ||
|
|
994f1ca6c6 | ||
|
|
f65e4797cf | ||
|
|
52aeec5ac4 | ||
|
|
7032b3f463 | ||
|
|
c26686b430 | ||
|
|
60c8f4ee20 | ||
|
|
25f396c126 | ||
|
|
0166abcd2a | ||
|
|
4cd0071dd4 | ||
|
|
1ec570375f | ||
|
|
75c33b29d5 | ||
|
|
910ded1a8c | ||
|
|
2555a9e710 | ||
|
|
f532c4712e |
@@ -7,8 +7,5 @@ SimpleCov.start 'rails' do
|
||||
add_filter '/script'
|
||||
add_filter '/db'
|
||||
|
||||
# We haven't managed to make simplecov recognise rake coverage accurately.
|
||||
add_filter '/lib/tasks/'
|
||||
|
||||
formatter SimpleCov::Formatter::SimpleFormatter
|
||||
end
|
||||
|
||||
1
Gemfile
1
Gemfile
@@ -152,6 +152,7 @@ end
|
||||
group :test, :development do
|
||||
gem 'bullet'
|
||||
gem 'capybara'
|
||||
gem 'capybara-shadowdom'
|
||||
gem 'cuprite'
|
||||
gem 'database_cleaner', require: false
|
||||
gem 'debug', '>= 1.0.0'
|
||||
|
||||
164
Gemfile.lock
164
Gemfile.lock
@@ -48,36 +48,36 @@ PATH
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
Ascii85 (1.1.0)
|
||||
actioncable (7.1.5.1)
|
||||
actionpack (= 7.1.5.1)
|
||||
activesupport (= 7.1.5.1)
|
||||
Ascii85 (2.0.1)
|
||||
actioncable (7.1.5.2)
|
||||
actionpack (= 7.1.5.2)
|
||||
activesupport (= 7.1.5.2)
|
||||
nio4r (~> 2.0)
|
||||
websocket-driver (>= 0.6.1)
|
||||
zeitwerk (~> 2.6)
|
||||
actionmailbox (7.1.5.1)
|
||||
actionpack (= 7.1.5.1)
|
||||
activejob (= 7.1.5.1)
|
||||
activerecord (= 7.1.5.1)
|
||||
activestorage (= 7.1.5.1)
|
||||
activesupport (= 7.1.5.1)
|
||||
actionmailbox (7.1.5.2)
|
||||
actionpack (= 7.1.5.2)
|
||||
activejob (= 7.1.5.2)
|
||||
activerecord (= 7.1.5.2)
|
||||
activestorage (= 7.1.5.2)
|
||||
activesupport (= 7.1.5.2)
|
||||
mail (>= 2.7.1)
|
||||
net-imap
|
||||
net-pop
|
||||
net-smtp
|
||||
actionmailer (7.1.5.1)
|
||||
actionpack (= 7.1.5.1)
|
||||
actionview (= 7.1.5.1)
|
||||
activejob (= 7.1.5.1)
|
||||
activesupport (= 7.1.5.1)
|
||||
actionmailer (7.1.5.2)
|
||||
actionpack (= 7.1.5.2)
|
||||
actionview (= 7.1.5.2)
|
||||
activejob (= 7.1.5.2)
|
||||
activesupport (= 7.1.5.2)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
net-imap
|
||||
net-pop
|
||||
net-smtp
|
||||
rails-dom-testing (~> 2.2)
|
||||
actionpack (7.1.5.1)
|
||||
actionview (= 7.1.5.1)
|
||||
activesupport (= 7.1.5.1)
|
||||
actionpack (7.1.5.2)
|
||||
actionview (= 7.1.5.2)
|
||||
activesupport (= 7.1.5.2)
|
||||
nokogiri (>= 1.8.5)
|
||||
racc
|
||||
rack (>= 2.2.4)
|
||||
@@ -87,15 +87,15 @@ GEM
|
||||
rails-html-sanitizer (~> 1.6)
|
||||
actionpack-action_caching (1.2.2)
|
||||
actionpack (>= 4.0.0)
|
||||
actiontext (7.1.5.1)
|
||||
actionpack (= 7.1.5.1)
|
||||
activerecord (= 7.1.5.1)
|
||||
activestorage (= 7.1.5.1)
|
||||
activesupport (= 7.1.5.1)
|
||||
actiontext (7.1.5.2)
|
||||
actionpack (= 7.1.5.2)
|
||||
activerecord (= 7.1.5.2)
|
||||
activestorage (= 7.1.5.2)
|
||||
activesupport (= 7.1.5.2)
|
||||
globalid (>= 0.6.0)
|
||||
nokogiri (>= 1.8.5)
|
||||
actionview (7.1.5.1)
|
||||
activesupport (= 7.1.5.1)
|
||||
actionview (7.1.5.2)
|
||||
activesupport (= 7.1.5.2)
|
||||
builder (~> 3.1)
|
||||
erubi (~> 1.11)
|
||||
rails-dom-testing (~> 2.2)
|
||||
@@ -107,8 +107,8 @@ GEM
|
||||
activemodel (>= 5.2.0)
|
||||
activestorage (>= 5.2.0)
|
||||
activesupport (>= 5.2.0)
|
||||
activejob (7.1.5.1)
|
||||
activesupport (= 7.1.5.1)
|
||||
activejob (7.1.5.2)
|
||||
activesupport (= 7.1.5.2)
|
||||
globalid (>= 0.3.6)
|
||||
activemerchant (1.133.0)
|
||||
activesupport (>= 4.2)
|
||||
@@ -116,11 +116,11 @@ GEM
|
||||
i18n (>= 0.6.9)
|
||||
nokogiri (~> 1.4)
|
||||
rexml (~> 3.2.5)
|
||||
activemodel (7.1.5.1)
|
||||
activesupport (= 7.1.5.1)
|
||||
activerecord (7.1.5.1)
|
||||
activemodel (= 7.1.5.1)
|
||||
activesupport (= 7.1.5.1)
|
||||
activemodel (7.1.5.2)
|
||||
activesupport (= 7.1.5.2)
|
||||
activerecord (7.1.5.2)
|
||||
activemodel (= 7.1.5.2)
|
||||
activesupport (= 7.1.5.2)
|
||||
timeout (>= 0.4.0)
|
||||
activerecord-import (1.6.0)
|
||||
activerecord (>= 4.2)
|
||||
@@ -133,13 +133,13 @@ GEM
|
||||
multi_json (~> 1.11, >= 1.11.2)
|
||||
rack (>= 2.0.8, < 4)
|
||||
railties (>= 6.1)
|
||||
activestorage (7.1.5.1)
|
||||
actionpack (= 7.1.5.1)
|
||||
activejob (= 7.1.5.1)
|
||||
activerecord (= 7.1.5.1)
|
||||
activesupport (= 7.1.5.1)
|
||||
activestorage (7.1.5.2)
|
||||
actionpack (= 7.1.5.2)
|
||||
activejob (= 7.1.5.2)
|
||||
activerecord (= 7.1.5.2)
|
||||
activesupport (= 7.1.5.2)
|
||||
marcel (~> 1.0)
|
||||
activesupport (7.1.5.1)
|
||||
activesupport (7.1.5.2)
|
||||
base64
|
||||
benchmark (>= 0.3)
|
||||
bigdecimal
|
||||
@@ -189,7 +189,7 @@ GEM
|
||||
aws-sigv4 (~> 1.8)
|
||||
aws-sigv4 (1.8.0)
|
||||
aws-eventstream (~> 1, >= 1.0.2)
|
||||
base64 (0.2.0)
|
||||
base64 (0.3.0)
|
||||
bcp47_spec (0.2.1)
|
||||
bcrypt (3.1.20)
|
||||
benchmark (0.4.1)
|
||||
@@ -201,7 +201,7 @@ GEM
|
||||
bugsnag (6.26.4)
|
||||
concurrent-ruby (~> 1.0)
|
||||
builder (3.2.4)
|
||||
bullet (7.1.6)
|
||||
bullet (8.0.8)
|
||||
activesupport (>= 3.0.0)
|
||||
uniform_notifier (~> 1.11)
|
||||
cable_ready (5.0.6)
|
||||
@@ -221,12 +221,14 @@ GEM
|
||||
rack-test (>= 0.6.3)
|
||||
regexp_parser (>= 1.5, < 3.0)
|
||||
xpath (~> 3.2)
|
||||
capybara-shadowdom (0.3.0)
|
||||
capybara
|
||||
caxlsx (3.3.0)
|
||||
htmlentities (~> 4.3, >= 4.3.4)
|
||||
marcel (~> 1.0)
|
||||
nokogiri (~> 1.10, >= 1.10.4)
|
||||
rubyzip (>= 1.3.0, < 3)
|
||||
cgi (0.3.6)
|
||||
cgi (0.3.7)
|
||||
childprocess (5.0.0)
|
||||
choice (0.2.0)
|
||||
chronic (0.10.2)
|
||||
@@ -241,8 +243,8 @@ GEM
|
||||
combine_pdf (1.0.26)
|
||||
matrix
|
||||
ruby-rc4 (>= 0.1.5)
|
||||
concurrent-ruby (1.3.1)
|
||||
connection_pool (2.4.1)
|
||||
concurrent-ruby (1.3.5)
|
||||
connection_pool (2.5.3)
|
||||
cookiejar (0.3.4)
|
||||
crack (1.0.0)
|
||||
bigdecimal
|
||||
@@ -262,7 +264,7 @@ GEM
|
||||
database_cleaner-core (2.0.1)
|
||||
datafoodconsortium-connector (1.1.0)
|
||||
virtual_assembly-semantizer (~> 1.0, >= 1.0.5)
|
||||
date (3.3.4)
|
||||
date (3.4.1)
|
||||
debug (1.9.2)
|
||||
irb (~> 1.10)
|
||||
reline (>= 0.3.8)
|
||||
@@ -298,7 +300,7 @@ GEM
|
||||
email_validator (2.2.4)
|
||||
activemodel
|
||||
erubi (1.12.0)
|
||||
et-orbi (1.2.7)
|
||||
et-orbi (1.3.0)
|
||||
tzinfo
|
||||
eventmachine (1.2.7)
|
||||
eventmachine_httpserver (0.2.1)
|
||||
@@ -351,8 +353,8 @@ GEM
|
||||
nokogiri (>= 1.5.11, < 2.0.0)
|
||||
foreman (0.88.1)
|
||||
formatador (0.2.5)
|
||||
fugit (1.8.1)
|
||||
et-orbi (~> 1, >= 1.2.7)
|
||||
fugit (1.11.1)
|
||||
et-orbi (~> 1, >= 1.2.11)
|
||||
raabro (~> 1.4)
|
||||
fuubar (2.5.1)
|
||||
rspec-core (~> 3.0)
|
||||
@@ -450,7 +452,7 @@ GEM
|
||||
rb-fsevent (~> 0.10, >= 0.10.3)
|
||||
rb-inotify (~> 0.9, >= 0.9.10)
|
||||
logger (1.7.0)
|
||||
loofah (2.22.0)
|
||||
loofah (2.24.1)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.12.0)
|
||||
mail (2.8.1)
|
||||
@@ -470,7 +472,7 @@ GEM
|
||||
mini_magick (4.11.0)
|
||||
mini_mime (1.1.5)
|
||||
mini_portile2 (2.8.6)
|
||||
minitest (5.23.1)
|
||||
minitest (5.25.5)
|
||||
monetize (1.13.0)
|
||||
money (~> 6.12)
|
||||
money (6.16.0)
|
||||
@@ -481,7 +483,7 @@ GEM
|
||||
mutex_m (0.3.0)
|
||||
net-http (0.4.1)
|
||||
uri
|
||||
net-imap (0.4.10)
|
||||
net-imap (0.4.20)
|
||||
date
|
||||
net-protocol
|
||||
net-pop (0.1.2)
|
||||
@@ -492,7 +494,7 @@ GEM
|
||||
net-protocol
|
||||
newrelic_rpm (9.9.0)
|
||||
nio4r (2.7.1)
|
||||
nokogiri (1.16.5)
|
||||
nokogiri (1.18.9)
|
||||
mini_portile2 (~> 2.8.2)
|
||||
racc (~> 1.4)
|
||||
nokogiri-html5-inference (0.3.0)
|
||||
@@ -544,9 +546,9 @@ GEM
|
||||
xml-simple
|
||||
paypal-sdk-merchant (1.117.2)
|
||||
paypal-sdk-core (~> 0.3.0)
|
||||
pdf-reader (2.12.0)
|
||||
Ascii85 (~> 1.0)
|
||||
afm (~> 0.2.1)
|
||||
pdf-reader (2.15.0)
|
||||
Ascii85 (>= 1.0, < 3.0, != 2.0.0)
|
||||
afm (>= 0.2.1, < 2)
|
||||
hashery (~> 2.0)
|
||||
ruby-rc4
|
||||
ttfunk
|
||||
@@ -573,7 +575,7 @@ GEM
|
||||
railties (>= 4.2)
|
||||
raabro (1.4.0)
|
||||
racc (1.8.1)
|
||||
rack (2.2.11)
|
||||
rack (2.2.14)
|
||||
rack-mini-profiler (2.3.4)
|
||||
rack (>= 1.2.0)
|
||||
rack-oauth2 (2.2.1)
|
||||
@@ -597,20 +599,20 @@ GEM
|
||||
rackup (1.0.1)
|
||||
rack (< 3)
|
||||
webrick
|
||||
rails (7.1.5.1)
|
||||
actioncable (= 7.1.5.1)
|
||||
actionmailbox (= 7.1.5.1)
|
||||
actionmailer (= 7.1.5.1)
|
||||
actionpack (= 7.1.5.1)
|
||||
actiontext (= 7.1.5.1)
|
||||
actionview (= 7.1.5.1)
|
||||
activejob (= 7.1.5.1)
|
||||
activemodel (= 7.1.5.1)
|
||||
activerecord (= 7.1.5.1)
|
||||
activestorage (= 7.1.5.1)
|
||||
activesupport (= 7.1.5.1)
|
||||
rails (7.1.5.2)
|
||||
actioncable (= 7.1.5.2)
|
||||
actionmailbox (= 7.1.5.2)
|
||||
actionmailer (= 7.1.5.2)
|
||||
actionpack (= 7.1.5.2)
|
||||
actiontext (= 7.1.5.2)
|
||||
actionview (= 7.1.5.2)
|
||||
activejob (= 7.1.5.2)
|
||||
activemodel (= 7.1.5.2)
|
||||
activerecord (= 7.1.5.2)
|
||||
activestorage (= 7.1.5.2)
|
||||
activesupport (= 7.1.5.2)
|
||||
bundler (>= 1.15.0)
|
||||
railties (= 7.1.5.1)
|
||||
railties (= 7.1.5.2)
|
||||
rails-controller-testing (1.0.5)
|
||||
actionpack (>= 5.0.1.rc1)
|
||||
actionview (>= 5.0.1.rc1)
|
||||
@@ -624,16 +626,16 @@ GEM
|
||||
activesupport (>= 4.2)
|
||||
choice (~> 0.2.0)
|
||||
ruby-graphviz (~> 1.2)
|
||||
rails-html-sanitizer (1.6.0)
|
||||
rails-html-sanitizer (1.6.1)
|
||||
loofah (~> 2.21)
|
||||
nokogiri (~> 1.14)
|
||||
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
|
||||
rails-i18n (7.0.9)
|
||||
i18n (>= 0.7, < 2)
|
||||
railties (>= 6.0.0, < 8)
|
||||
rails_safe_tasks (1.0.0)
|
||||
railties (7.1.5.1)
|
||||
actionpack (= 7.1.5.1)
|
||||
activesupport (= 7.1.5.1)
|
||||
railties (7.1.5.2)
|
||||
actionpack (= 7.1.5.2)
|
||||
activesupport (= 7.1.5.2)
|
||||
irb
|
||||
rackup (>= 1.0.0)
|
||||
rake (>= 12.2)
|
||||
@@ -837,12 +839,13 @@ GEM
|
||||
temple (0.8.2)
|
||||
terminal-table (4.0.0)
|
||||
unicode-display_width (>= 1.1.1, < 4)
|
||||
thor (1.3.1)
|
||||
thor (1.4.0)
|
||||
thread-local (1.1.0)
|
||||
tilt (2.3.0)
|
||||
timecop (0.9.8)
|
||||
timeout (0.4.1)
|
||||
ttfunk (1.7.0)
|
||||
timecop (0.9.10)
|
||||
timeout (0.4.3)
|
||||
ttfunk (1.8.0)
|
||||
bigdecimal (~> 3.1)
|
||||
turbo-rails (2.0.5)
|
||||
actionpack (>= 6.0.0)
|
||||
activejob (>= 6.0.0)
|
||||
@@ -860,8 +863,8 @@ GEM
|
||||
simplecov
|
||||
simplecov_json_formatter
|
||||
unicode-display_width (2.5.0)
|
||||
uniform_notifier (1.16.0)
|
||||
uri (0.13.0)
|
||||
uniform_notifier (1.17.0)
|
||||
uri (0.13.2)
|
||||
valid_email2 (5.2.3)
|
||||
activemodel (>= 3.2)
|
||||
mail (~> 2.5)
|
||||
@@ -901,7 +904,7 @@ GEM
|
||||
rack-proxy (>= 0.6.1)
|
||||
railties (>= 5.2)
|
||||
semantic_range (>= 2.3.0)
|
||||
webrick (1.8.1)
|
||||
webrick (1.8.2)
|
||||
websocket-driver (0.7.6)
|
||||
websocket-extensions (>= 0.1.0)
|
||||
websocket-extensions (0.1.5)
|
||||
@@ -941,6 +944,7 @@ DEPENDENCIES
|
||||
cable_ready
|
||||
cancancan (~> 1.15.0)
|
||||
capybara
|
||||
capybara-shadowdom
|
||||
catalog!
|
||||
coffee-rails (~> 5.0.0)
|
||||
combine_pdf
|
||||
|
||||
@@ -80,8 +80,6 @@ class CheckoutController < BaseController
|
||||
|
||||
@order.customer.touch :terms_and_conditions_accepted_at
|
||||
|
||||
return true if redirect_to_payment_gateway
|
||||
|
||||
# Redeem VINE voucher
|
||||
vine_voucher_redeemer = Vine::VoucherRedeemerService.new(order: @order)
|
||||
unless vine_voucher_redeemer.redeem
|
||||
@@ -94,6 +92,9 @@ class CheckoutController < BaseController
|
||||
return false
|
||||
# rubocop:enable Rails/DeprecatedActiveModelErrorsMethods
|
||||
end
|
||||
|
||||
return true if redirect_to_payment_gateway
|
||||
|
||||
@order.process_payments!
|
||||
@order.confirm!
|
||||
BackorderJob.check_stock(@order)
|
||||
|
||||
@@ -26,8 +26,8 @@ module Admin
|
||||
show_enterprise_fees = can?(:manage_enterprise_fees,
|
||||
enterprise) && (is_shop || enterprise.is_primary_producer)
|
||||
show_connected_apps = can?(:manage_connected_apps, enterprise) &&
|
||||
feature?(:connected_apps, spree_current_user, enterprise) &&
|
||||
Spree::Config.connected_apps_enabled.present?
|
||||
(connected_apps_enabled(enterprise).present? ||
|
||||
dfc_platforms_available?)
|
||||
show_inventory_settings = feature?(:inventory, spree_current_user.enterprises) && is_shop
|
||||
|
||||
show_options = {
|
||||
@@ -42,11 +42,19 @@ module Admin
|
||||
build_enterprise_side_menu_items(is_shop:, show_options:)
|
||||
end
|
||||
|
||||
def connected_apps_enabled
|
||||
def connected_apps_enabled(enterprise)
|
||||
return [] unless feature?(:connected_apps, spree_current_user, enterprise)
|
||||
|
||||
connected_apps_enabled = Spree::Config.connected_apps_enabled&.split(',') || []
|
||||
ConnectedApp::TYPES & connected_apps_enabled
|
||||
end
|
||||
|
||||
def dfc_platforms_available?
|
||||
DfcProvider::PlatformsController::PLATFORM_IDS.keys.any? do |id|
|
||||
feature?(id, spree_current_user)
|
||||
end
|
||||
end
|
||||
|
||||
def enterprise_attachment_removal_modal_id
|
||||
attachment_removal_parameter # remove_logo|remove_promo_image|remove_white_label_logo
|
||||
end
|
||||
|
||||
15
app/models/dfc_permission.rb
Normal file
15
app/models/dfc_permission.rb
Normal file
@@ -0,0 +1,15 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Authorisations of a user allowing a platform to access to data.
|
||||
class DfcPermission < ApplicationRecord
|
||||
SCOPES = %w[
|
||||
ReadEnterprise ReadProducts ReadOrders
|
||||
WriteEnterprise WriteProducts WriteOrders
|
||||
].freeze
|
||||
|
||||
belongs_to :user, class_name: "Spree::User"
|
||||
belongs_to :enterprise
|
||||
|
||||
validates :grantee, presence: true
|
||||
validates :scope, presence: true, inclusion: { in: SCOPES }
|
||||
end
|
||||
@@ -1,3 +1,5 @@
|
||||
- connected_apps_enabled.each do |type|
|
||||
- connected_apps_enabled(enterprise).each do |type|
|
||||
= render partial: "/admin/enterprises/form/connected_apps/#{type}",
|
||||
locals: { enterprise:, connected_app: enterprise.connected_apps.public_send(type).first }
|
||||
|
||||
= render partial: "/admin/enterprises/form/dfc_permissions" if dfc_platforms_available?
|
||||
|
||||
30
app/views/admin/enterprises/form/_dfc_permissions.html.haml
Normal file
30
app/views/admin/enterprises/form/_dfc_permissions.html.haml
Normal file
@@ -0,0 +1,30 @@
|
||||
%script{type: "module", src: "https://cdn.jsdelivr.net/npm/@startinblox/core@latest/dist/index.js"}
|
||||
%script{type: "module"}
|
||||
:plain
|
||||
window.orbit = {
|
||||
client: {
|
||||
name: "Orbit",
|
||||
logo: "https://cdn.startinblox.com/logos/ACME.svg",
|
||||
},
|
||||
components: [],
|
||||
getRoute: (route) => route,
|
||||
getDefaultRoute: () => "",
|
||||
getComponent: () => undefined,
|
||||
getComponentFromRoute: () => undefined,
|
||||
Swal: () => {},
|
||||
defaultRoute: "",
|
||||
federations: {},
|
||||
componentSet: new Set(["routing", "menu", "menu-top", "autoLogin", "solid-permissioning"]),
|
||||
};
|
||||
|
||||
:plain
|
||||
<solid-permissioning
|
||||
data-src="#{DfcProvider::Engine.routes.url_helpers.enterprise_platforms_url(@enterprise.id)}"
|
||||
scopes-uri="https://cdn.startinblox.com/owl/dfc/taxonomies/scopes.jsonld"
|
||||
noRouter
|
||||
auto-lang
|
||||
lang="en"
|
||||
auth-token="#{form_authenticity_token}">
|
||||
</solid-permissioning>
|
||||
|
||||
%script{type: "module", src: "https://cdn.jsdelivr.net/npm/@startinblox/solid-data-permissioning@latest/dist/index.js"}
|
||||
@@ -1,20 +1,5 @@
|
||||
// import Flatpickr
|
||||
import Flatpickr from "stimulus-flatpickr";
|
||||
import { ar } from "flatpickr/dist/l10n/ar";
|
||||
import { cat } from "flatpickr/dist/l10n/cat";
|
||||
import { cy } from "flatpickr/dist/l10n/cy";
|
||||
import { de } from "flatpickr/dist/l10n/de";
|
||||
import { fi } from "flatpickr/dist/l10n/fi";
|
||||
import { fr } from "flatpickr/dist/l10n/fr";
|
||||
import { it } from "flatpickr/dist/l10n/it";
|
||||
import { nl } from "flatpickr/dist/l10n/nl";
|
||||
import { pl } from "flatpickr/dist/l10n/pl";
|
||||
import { pt } from "flatpickr/dist/l10n/pt";
|
||||
import { ru } from "flatpickr/dist/l10n/ru";
|
||||
import { sv } from "flatpickr/dist/l10n/sv";
|
||||
import { tr } from "flatpickr/dist/l10n/tr";
|
||||
import { en } from "flatpickr/dist/l10n/default.js";
|
||||
import { hu } from "flatpickr/dist/l10n/hu";
|
||||
import ShortcutButtonsPlugin from "shortcut-buttons-flatpickr";
|
||||
import labelPlugin from "flatpickr/dist/plugins/labelPlugin/labelPlugin";
|
||||
|
||||
@@ -24,28 +9,11 @@ export default class extends Flatpickr {
|
||||
*/
|
||||
static values = { enableTime: Boolean, mode: String, defaultDate: String };
|
||||
static targets = ["start", "end"];
|
||||
locales = {
|
||||
ar: ar,
|
||||
cat: cat,
|
||||
cy: cy,
|
||||
de: de,
|
||||
fi: fi,
|
||||
fr: fr,
|
||||
it: it,
|
||||
nl: nl,
|
||||
pl: pl,
|
||||
pt: pt,
|
||||
ru: ru,
|
||||
sv: sv,
|
||||
tr: tr,
|
||||
en: en,
|
||||
hu: hu,
|
||||
};
|
||||
|
||||
initialize() {
|
||||
const datetimepicker = this.enableTimeValue === true;
|
||||
const mode = this.modeValue === "range" ? "range" : "single";
|
||||
// sets your language (you can also set some global setting for all time pickers)
|
||||
// configure flatpickr options (locale set dynamically in connect())
|
||||
this.config = {
|
||||
altInput: true,
|
||||
altFormat: datetimepicker
|
||||
@@ -54,13 +22,18 @@ export default class extends Flatpickr {
|
||||
dateFormat: datetimepicker ? "Y-m-d H:i" : "Y-m-d",
|
||||
enableTime: datetimepicker,
|
||||
time_24hr: datetimepicker,
|
||||
locale: I18n.base_locale,
|
||||
plugins: this.plugins(mode, datetimepicker),
|
||||
mode,
|
||||
};
|
||||
}
|
||||
|
||||
connect() {
|
||||
async connect() {
|
||||
const locale = await this.importFlatpickrLocale(I18n.base_locale);
|
||||
this.config = {
|
||||
...this.config,
|
||||
locale,
|
||||
};
|
||||
|
||||
super.connect();
|
||||
window.addEventListener("flatpickr:change", this.onChangeEvent);
|
||||
window.addEventListener("flatpickr:clear", this.clear);
|
||||
@@ -164,4 +137,16 @@ export default class extends Flatpickr {
|
||||
this.fp.setDate(moment().add(1, "days").startOf("day").format());
|
||||
}
|
||||
}
|
||||
|
||||
async importFlatpickrLocale(localeCode) {
|
||||
// null tells flatpickr to fall back to its built-in english locale
|
||||
if (!localeCode || localeCode === "en") return null;
|
||||
|
||||
try {
|
||||
const localeModule = await import(`flatpickr/dist/l10n/${localeCode}.js`);
|
||||
return localeModule.default?.[localeCode] ?? null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,5 +54,33 @@ Openfoodnetwork::Application.configure do
|
||||
# Print deprecation notices to the stderr
|
||||
# config.active_support.deprecation = :stderr
|
||||
|
||||
# Fail tests on deprecated code unless it's a known case to solve.
|
||||
Rails.application.deprecators.behavior = ->(message, callstack, deprecator) do
|
||||
allowed_warnings = [
|
||||
# List strings here to allow matching deprecations.
|
||||
#
|
||||
# https://guides.rubyonrails.org/upgrading_ruby_on_rails.html#new-activesupport-cache-serialization-format
|
||||
"config.active_support.cache_format_version",
|
||||
|
||||
# `Rails.application.secrets` is deprecated in favor of `Rails.application.credentials` and will be removed in Rails 7.2
|
||||
"Rails.application.secrets",
|
||||
|
||||
"Passing the class as positional argument",
|
||||
|
||||
# Spree::Order model aliases `bill_address`, but `bill_address` is not an attribute. Starting in Rails 7.2, alias_attribute with non-attribute targets will raise. Use `alias_method :billing_address, :bill_address` or define the method manually. (called from initialize at app/models/spree/order.rb:188)
|
||||
"alias_attribute with non-attribute targets will raise",
|
||||
|
||||
# Spree::CreditCard model aliases `cc_type` and has a method called `cc_type=` defined. Starting in Rails 7.2 `brand=` will not be calling `cc_type=` anymore. You may want to additionally define `brand=` to preserve the current behavior.
|
||||
"model aliases",
|
||||
|
||||
# Setting action_dispatch.show_exceptions to true is deprecated. Set to :all instead.
|
||||
# spec/requests/errors_spec.rb
|
||||
"action_dispatch.show_exceptions",
|
||||
]
|
||||
unless allowed_warnings.any? { |pattern| message.match(pattern) }
|
||||
ActiveSupport::Deprecation::DEFAULT_BEHAVIORS[:raise].call(message, callstack, deprecator)
|
||||
end
|
||||
end
|
||||
|
||||
config.active_job.queue_adapter = :test
|
||||
end
|
||||
|
||||
16
db/migrate/20250515050349_create_dfc_permissions.rb
Normal file
16
db/migrate/20250515050349_create_dfc_permissions.rb
Normal file
@@ -0,0 +1,16 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class CreateDfcPermissions < ActiveRecord::Migration[7.0]
|
||||
def change
|
||||
create_table :dfc_permissions do |t|
|
||||
t.references :user, null: false, foreign_key: { to_table: :spree_users }
|
||||
t.references :enterprise, null: false, foreign_key: true
|
||||
t.string :grantee, null: false
|
||||
t.string :scope, null: false
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
add_index :dfc_permissions, :grantee
|
||||
add_index :dfc_permissions, :scope
|
||||
end
|
||||
end
|
||||
15
db/schema.rb
15
db/schema.rb
@@ -111,6 +111,19 @@ ActiveRecord::Schema[7.0].define(version: 2025_07_09_012346) do
|
||||
t.index ["user_id"], name: "index_customers_on_user_id"
|
||||
end
|
||||
|
||||
create_table "dfc_permissions", force: :cascade do |t|
|
||||
t.bigint "user_id", null: false
|
||||
t.bigint "enterprise_id", null: false
|
||||
t.string "grantee", null: false
|
||||
t.string "scope", null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.index ["enterprise_id"], name: "index_dfc_permissions_on_enterprise_id"
|
||||
t.index ["grantee"], name: "index_dfc_permissions_on_grantee"
|
||||
t.index ["scope"], name: "index_dfc_permissions_on_scope"
|
||||
t.index ["user_id"], name: "index_dfc_permissions_on_user_id"
|
||||
end
|
||||
|
||||
create_table "distributors_payment_methods", force: :cascade do |t|
|
||||
t.integer "distributor_id", null: false
|
||||
t.integer "payment_method_id", null: false
|
||||
@@ -1144,6 +1157,8 @@ ActiveRecord::Schema[7.0].define(version: 2025_07_09_012346) do
|
||||
add_foreign_key "customers", "spree_addresses", column: "bill_address_id", name: "customers_bill_address_id_fk"
|
||||
add_foreign_key "customers", "spree_addresses", column: "ship_address_id", name: "customers_ship_address_id_fk"
|
||||
add_foreign_key "customers", "spree_users", column: "user_id", name: "customers_user_id_fk"
|
||||
add_foreign_key "dfc_permissions", "enterprises"
|
||||
add_foreign_key "dfc_permissions", "spree_users", column: "user_id"
|
||||
add_foreign_key "distributors_payment_methods", "enterprises", column: "distributor_id", name: "distributors_payment_methods_distributor_id_fk"
|
||||
add_foreign_key "distributors_payment_methods", "spree_payment_methods", column: "payment_method_id", name: "distributors_payment_methods_payment_method_id_fk"
|
||||
add_foreign_key "distributors_shipping_methods", "enterprises", column: "distributor_id", name: "distributors_shipping_methods_distributor_id_fk"
|
||||
|
||||
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
|
||||
s.authors = ["developers@ofn"]
|
||||
s.summary = "Catalog domain of the OFN solution."
|
||||
|
||||
s.required_ruby_version = File.read(File.expand_path("../../.ruby-version", __dir__)).chomp
|
||||
s.required_ruby_version = ">= 1.0.0" # rubocop:disable Gemspec/RequiredRubyVersion
|
||||
|
||||
s.files = Dir["{app,config,db,lib}/**/*"] + ["LICENSE.txt", "Rakefile", "README.rdoc"]
|
||||
s.metadata['rubygems_mfa_required'] = 'true'
|
||||
|
||||
@@ -63,5 +63,10 @@ module DfcProvider
|
||||
def import
|
||||
DfcIo.import(request.body)
|
||||
end
|
||||
|
||||
# Checks weather a feature is enabled for any of the given actors.
|
||||
def feature?(feature, *actors)
|
||||
OpenFoodNetwork::FeatureToggle.enabled?(feature, *actors)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -7,16 +7,12 @@ module DfcProvider
|
||||
before_action :check_enterprise
|
||||
|
||||
def index
|
||||
person = PersonBuilder.person(current_user)
|
||||
|
||||
enterprises = current_user.enterprises.map do |enterprise|
|
||||
EnterpriseBuilder.enterprise(enterprise)
|
||||
end
|
||||
person.affiliatedOrganizations = enterprises
|
||||
catalog_items = enterprises.flat_map(&:catalogItems)
|
||||
|
||||
render json: DfcIo.export(
|
||||
person,
|
||||
*enterprises,
|
||||
*catalog_items,
|
||||
*catalog_items.map(&:product),
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
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
|
||||
|
||||
def index
|
||||
render json: platforms
|
||||
end
|
||||
|
||||
def show
|
||||
render json: platform(params[:id])
|
||||
end
|
||||
|
||||
def update
|
||||
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]+\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 = available_platforms.map(&method(:platform))
|
||||
|
||||
{
|
||||
'@context': "https://cdn.startinblox.com/owl/context-bis.jsonld",
|
||||
'@id': id,
|
||||
'dfc-t:platforms': {
|
||||
'@type': "rdf:List",
|
||||
'@list': platforms,
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def available_platforms
|
||||
PLATFORM_IDS.keys.select(&method(:feature?))
|
||||
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://github.com/datafoodconsortium/taxonomies/releases/latest/download/scopes.rdf##{scope}",
|
||||
'@type': "dfc-t:Scope",
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def granted_scopes(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.
|
||||
# It assumes that it's an OIDC access token but we are passing the Rails
|
||||
# CSRF token to the component to allow POST request with cookie auth.
|
||||
def move_authenticity_token
|
||||
token = request.delete_header('HTTP_AUTHORIZATION').to_s.split.last
|
||||
request.headers['X-CSRF-Token'] = token if token
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -5,6 +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, :show, :update]
|
||||
resources :supplied_products, only: [:create, :show, :update]
|
||||
resources :social_medias, only: [:show]
|
||||
end
|
||||
|
||||
@@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
|
||||
spec.summary = 'Provides an API stack implementing DFC semantic ' \
|
||||
'specifications'
|
||||
|
||||
spec.required_ruby_version = File.read(File.expand_path("../../.ruby-version", __dir__)).chomp
|
||||
spec.required_ruby_version = ">= 1.0.0" # rubocop:disable Gemspec/RequiredRubyVersion
|
||||
|
||||
spec.files = Dir["{app,config,lib}/**/*"] + ['README.md']
|
||||
|
||||
|
||||
102
engines/dfc_provider/spec/requests/platforms_spec.rb
Normal file
102
engines/dfc_provider/spec/requests/platforms_spec.rb
Normal file
@@ -0,0 +1,102 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require_relative "../swagger_helper"
|
||||
|
||||
RSpec.describe "Platforms", swagger_doc: "dfc.yaml" do
|
||||
let!(:user) { create(:oidc_user) }
|
||||
let!(:enterprise) do
|
||||
create(
|
||||
:distributor_enterprise,
|
||||
id: 10_000, owner: user, name: "Fred's Farm",
|
||||
)
|
||||
end
|
||||
|
||||
before { login_as user }
|
||||
|
||||
path "/api/dfc/enterprises/{enterprise_id}/platforms" do
|
||||
parameter name: :enterprise_id, in: :path, type: :string
|
||||
|
||||
get "List platforms with scopes" do
|
||||
produces "application/json"
|
||||
|
||||
response "200", "successful" do
|
||||
let(:enterprise_id) { enterprise.id }
|
||||
|
||||
run_test! do
|
||||
expect(json_response["@id"]).to eq "http://test.host/api/dfc/enterprises/10000/platforms"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
path "/api/dfc/enterprises/{enterprise_id}/platforms/{platform_id}" do
|
||||
parameter name: :enterprise_id, in: :path, type: :string
|
||||
parameter name: :platform_id, in: :path, type: :string
|
||||
|
||||
get "Show platform scopes" do
|
||||
produces "application/json"
|
||||
|
||||
response "200", "successful" do
|
||||
let(:enterprise_id) { enterprise.id }
|
||||
let(:platform_id) { "cqcm-dev" }
|
||||
|
||||
run_test! do
|
||||
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
|
||||
end
|
||||
end
|
||||
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
|
||||
s.authors = ["developers@ofn"]
|
||||
s.summary = "Order Management domain of the OFN solution."
|
||||
|
||||
s.required_ruby_version = File.read(File.expand_path("../../.ruby-version", __dir__)).chomp
|
||||
s.required_ruby_version = ">= 1.0.0" # rubocop:disable Gemspec/RequiredRubyVersion
|
||||
|
||||
s.files = Dir["{app,config,db,lib}/**/*"] + ["LICENSE.txt", "Rakefile", "README.rdoc"]
|
||||
s.metadata['rubygems_mfa_required'] = 'true'
|
||||
|
||||
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
|
||||
s.authors = ["developers@ofn"]
|
||||
s.summary = "Web domain of the OFN solution."
|
||||
|
||||
s.required_ruby_version = File.read(File.expand_path("../../.ruby-version", __dir__)).chomp
|
||||
s.required_ruby_version = ">= 1.0.0" # rubocop:disable Gemspec/RequiredRubyVersion
|
||||
|
||||
s.files = Dir["{app,config,db,lib}/**/*"] + ["LICENSE.txt", "Rakefile", "README.rdoc"]
|
||||
s.metadata['rubygems_mfa_required'] = 'true'
|
||||
|
||||
@@ -64,6 +64,9 @@ module OpenFoodNetwork
|
||||
"hub_address" => <<~DESC,
|
||||
Show the hub's address as shipping address on pickup orders.
|
||||
DESC
|
||||
"cqcm-dev" => <<~DESC,
|
||||
Show DFC Permissions interface to share data with CQCM dev platform.
|
||||
DESC
|
||||
}.merge(conditional_features).freeze;
|
||||
|
||||
# Features you would like to be enabled to start with.
|
||||
|
||||
@@ -4,6 +4,9 @@ namespace :simplecov do
|
||||
desc "Collates all result sets produced during parallel test runs"
|
||||
task :collate_results, # rubocop:disable Rails/RakeEnvironment doesn't need the full env
|
||||
[:path_to_results, :coverage_dir] do |_t, args|
|
||||
# This code is covered by a spec but trying to measure the code coverage of
|
||||
# the spec breaks the coverage report. We need to ignore it to avoid warnings.
|
||||
# :nocov:
|
||||
require "simplecov"
|
||||
require "undercover/simplecov_formatter"
|
||||
|
||||
@@ -19,5 +22,6 @@ namespace :simplecov do
|
||||
formatter(SimpleCov::Formatter::Undercover)
|
||||
coverage_dir(output_path)
|
||||
end
|
||||
# :nocov:
|
||||
end
|
||||
end
|
||||
|
||||
@@ -68,9 +68,6 @@ InvisibleCaptcha.timestamp_enabled = false
|
||||
InvisibleCaptcha.spinner_enabled = false
|
||||
|
||||
RSpec.configure do |config|
|
||||
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
|
||||
config.fixture_path = Rails.root.join('spec/fixtures').to_s
|
||||
|
||||
# If you're not using ActiveRecord, or you'd prefer not to run each of your
|
||||
# examples within a transaction, remove the following line or assign false
|
||||
# instead of true.
|
||||
|
||||
@@ -625,14 +625,30 @@ RSpec.describe CheckoutController do
|
||||
expect(flash[:error]).to match "There was an error while trying to redeem your voucher"
|
||||
end
|
||||
end
|
||||
|
||||
context "when an external payment gateway is used" do
|
||||
before do
|
||||
expect(payment_method).to receive(:external_gateway?) { true }
|
||||
expect(payment_method).to receive(:external_payment_url) { "https://example.com/pay" }
|
||||
mock_payment_method_fetcher(payment_method)
|
||||
end
|
||||
|
||||
it "redeems the voucher and redirect to the payment gateway's URL" do
|
||||
expect(vine_voucher_redeemer).to receive(:redeem).and_return(true)
|
||||
|
||||
put(:update, params:)
|
||||
|
||||
expect(response.body).to match("https://example.com/pay").and match("redirect")
|
||||
expect(order.reload.state).to eq "confirmation"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when an external payment gateway is used" do
|
||||
before do
|
||||
expect(Checkout::PaymentMethodFetcher).
|
||||
to receive_message_chain(:new, :call) { payment_method }
|
||||
expect(payment_method).to receive(:external_gateway?) { true }
|
||||
expect(payment_method).to receive(:external_payment_url) { "https://example.com/pay" }
|
||||
mock_payment_method_fetcher(payment_method)
|
||||
end
|
||||
|
||||
describe "confirming the order" do
|
||||
@@ -693,4 +709,9 @@ RSpec.describe CheckoutController do
|
||||
[{ "url" => "/checkout/details", "operation" => "redirectTo" }].to_json
|
||||
)
|
||||
end
|
||||
|
||||
def mock_payment_method_fetcher(payment_method)
|
||||
payment_method_fetcher = instance_double(Checkout::PaymentMethodFetcher, call: payment_method)
|
||||
expect(Checkout::PaymentMethodFetcher).to receive(:new).and_return(payment_method_fetcher)
|
||||
end
|
||||
end
|
||||
|
||||
54131
spec/fixtures/vcr_cassettes/DFC_Permissions/can_share_data_with_another_platform.yml
vendored
Normal file
54131
spec/fixtures/vcr_cassettes/DFC_Permissions/can_share_data_with_another_platform.yml
vendored
Normal file
File diff suppressed because one or more lines are too long
157
spec/fixtures/vcr_cassettes/DFC_Permissions/is_not_visible_when_no_platform_is_enabled.yml
vendored
Normal file
157
spec/fixtures/vcr_cassettes/DFC_Permissions/is_not_visible_when_no_platform_is_enabled.yml
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
---
|
||||
http_interactions:
|
||||
- request:
|
||||
method: get
|
||||
uri: http://clients2.google.com/time/1/current?cup2hreq=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855&cup2key=9:xgNLAoOqba-lEGVM6YOjj7pIq8HoxNPpUp9EWljo6sc
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: ''
|
||||
headers:
|
||||
Proxy-Connection:
|
||||
- keep-alive
|
||||
Pragma:
|
||||
- no-cache
|
||||
Cache-Control:
|
||||
- no-cache
|
||||
User-Agent:
|
||||
- Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/138.0.0.0
|
||||
Safari/537.36
|
||||
Accept-Encoding:
|
||||
- ''
|
||||
Connection:
|
||||
- close
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Content-Type:
|
||||
- application/json; charset=utf-8
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
X-Cup-Server-Proof:
|
||||
- 30460221009b0f46a5511673ea580081ce4e919d37745231029ab508ecbda5d9ee8e4c6a22022100e20234b939fd368c664f74624bab1cb2cefb9e966650a6a13f1b7fdf7a0c8549:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
|
||||
Cache-Control:
|
||||
- no-cache, no-store, max-age=0, must-revalidate
|
||||
Pragma:
|
||||
- no-cache
|
||||
Expires:
|
||||
- Mon, 01 Jan 1990 00:00:00 GMT
|
||||
Date:
|
||||
- Tue, 29 Jul 2025 05:06:27 GMT
|
||||
Content-Disposition:
|
||||
- attachment; filename="json.txt"; filename*=UTF-8''json.txt
|
||||
Cross-Origin-Resource-Policy:
|
||||
- same-site
|
||||
Cross-Origin-Opener-Policy:
|
||||
- same-origin
|
||||
Server:
|
||||
- ESF
|
||||
X-Xss-Protection:
|
||||
- '0'
|
||||
X-Frame-Options:
|
||||
- SAMEORIGIN
|
||||
Accept-Ranges:
|
||||
- none
|
||||
Vary:
|
||||
- Sec-Fetch-Dest, Sec-Fetch-Mode, Sec-Fetch-Site,Accept-Encoding
|
||||
Connection:
|
||||
- close
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: |-
|
||||
)]}'
|
||||
{"current_time_millis":1753765587344,"server_nonce":4.706974222338465E-226}
|
||||
recorded_at: Tue, 29 Jul 2025 05:06:27 GMT
|
||||
- request:
|
||||
method: post
|
||||
uri: https://accounts.google.com/ListAccounts?gpsia=1&json=standard&source=ChromiumBrowser
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: " "
|
||||
headers:
|
||||
Connection:
|
||||
- close
|
||||
Content-Length:
|
||||
- '1'
|
||||
Origin:
|
||||
- https://www.google.com
|
||||
Content-Type:
|
||||
- application/x-www-form-urlencoded
|
||||
Sec-Fetch-Site:
|
||||
- none
|
||||
Sec-Fetch-Mode:
|
||||
- no-cors
|
||||
Sec-Fetch-Dest:
|
||||
- empty
|
||||
User-Agent:
|
||||
- Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/138.0.0.0
|
||||
Safari/537.36
|
||||
Accept-Encoding:
|
||||
- ''
|
||||
Accept-Language:
|
||||
- en-US,en;q=0.9
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Content-Type:
|
||||
- application/json; charset=utf-8
|
||||
Access-Control-Allow-Origin:
|
||||
- https://www.google.com
|
||||
Access-Control-Allow-Credentials:
|
||||
- 'true'
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
Cache-Control:
|
||||
- no-cache, no-store, max-age=0, must-revalidate
|
||||
Pragma:
|
||||
- no-cache
|
||||
Expires:
|
||||
- Mon, 01 Jan 1990 00:00:00 GMT
|
||||
Date:
|
||||
- Tue, 29 Jul 2025 05:06:28 GMT
|
||||
Strict-Transport-Security:
|
||||
- max-age=31536000; includeSubDomains
|
||||
Cross-Origin-Opener-Policy:
|
||||
- same-origin
|
||||
Accept-Ch:
|
||||
- Sec-CH-UA-Arch, Sec-CH-UA-Bitness, Sec-CH-UA-Full-Version, Sec-CH-UA-Full-Version-List,
|
||||
Sec-CH-UA-Model, Sec-CH-UA-WoW64, Sec-CH-UA-Form-Factors, Sec-CH-UA-Platform,
|
||||
Sec-CH-UA-Platform-Version
|
||||
Content-Security-Policy:
|
||||
- require-trusted-types-for 'script';report-uri /_/IdentityListAccountsHttp/cspreport
|
||||
- script-src 'report-sample' 'nonce-k53NvqeKlfwH5MjGJUn81Q' 'unsafe-inline';object-src
|
||||
'none';base-uri 'self';report-uri /_/IdentityListAccountsHttp/cspreport;worker-src
|
||||
'self'
|
||||
- 'script-src ''unsafe-inline'' ''unsafe-eval'' blob: data: ''self'' https://apis.google.com
|
||||
https://ssl.gstatic.com https://www.google.com https://www.googletagmanager.com
|
||||
https://www.gstatic.com https://www.google-analytics.com;report-uri /_/IdentityListAccountsHttp/cspreport/allowlist'
|
||||
- 'script-src ''unsafe-inline'' ''unsafe-eval'' blob: data:;report-uri /_/IdentityListAccountsHttp/cspreport/fine-allowlist'
|
||||
Permissions-Policy:
|
||||
- ch-ua-arch=*, ch-ua-bitness=*, ch-ua-full-version=*, ch-ua-full-version-list=*,
|
||||
ch-ua-model=*, ch-ua-wow64=*, ch-ua-form-factors=*, ch-ua-platform=*, ch-ua-platform-version=*
|
||||
Reporting-Endpoints:
|
||||
- default="/_/IdentityListAccountsHttp/web-reports?context=eJzjEtHikmJw05BiOHxtB5Meyy0mIyAW4uG4snbhETaBDxc-TmNS0k3KL4zPTEnNK8ksqczJLC5JTE7OL80rKS5OLSpLLYo3MjAyNTA3MtAzsIgvMAAAgSYcZg"
|
||||
Server:
|
||||
- ESF
|
||||
X-Xss-Protection:
|
||||
- '0'
|
||||
Alt-Svc:
|
||||
- h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
|
||||
Accept-Ranges:
|
||||
- none
|
||||
Vary:
|
||||
- Origin,Accept-Encoding
|
||||
Connection:
|
||||
- close
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: '["gaia.l.a.r",[]]'
|
||||
recorded_at: Tue, 29 Jul 2025 05:06:28 GMT
|
||||
recorded_with: VCR 6.2.0
|
||||
@@ -38,5 +38,16 @@ RSpec.describe Admin::EnterprisesHelper do
|
||||
expect(visible_items.pluck(:name)).to include "inventory_settings"
|
||||
end
|
||||
end
|
||||
|
||||
it "hides Connected Apps by default" do
|
||||
user.enterprises << enterprise
|
||||
expect(visible_items.pluck(:name)).not_to include "connected_apps"
|
||||
end
|
||||
|
||||
it "shows Connected Apps for specific user" do
|
||||
user.enterprises << enterprise
|
||||
Flipper.enable("cqcm-dev", user)
|
||||
expect(visible_items.pluck(:name)).to include "connected_apps"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
35
spec/javascripts/stimulus/flatpickr_controller_test.js
Normal file
35
spec/javascripts/stimulus/flatpickr_controller_test.js
Normal file
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* @jest-environment jsdom
|
||||
*/
|
||||
|
||||
import { Application } from "stimulus";
|
||||
import FlatpickrController from "../../../app/webpacker/controllers/flatpickr_controller.js";
|
||||
|
||||
describe("FlatpickrController", () => {
|
||||
beforeAll(() => {
|
||||
const application = Application.start();
|
||||
application.register("flatpickr", FlatpickrController);
|
||||
});
|
||||
|
||||
describe("#importFlatpickrLocale", () => {
|
||||
describe("returns null to trigger flatpickr fallback to english", () => {
|
||||
test.each([
|
||||
["when no base_locale is set", {}],
|
||||
["when base_locale doesn't match a Flatpickr locale", { base_locale: "invalid-locale" }],
|
||||
["when base_locale is 'en'", { base_locale: "en" }],
|
||||
])("%s", async (_description, i18n) => {
|
||||
const controller = new FlatpickrController();
|
||||
const locale = await controller.importFlatpickrLocale(i18n.base_locale);
|
||||
expect(locale).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
it("returns locale object for a supported locale (fr)", async () => {
|
||||
const controller = new FlatpickrController();
|
||||
const locale = await controller.importFlatpickrLocale("fr");
|
||||
expect(locale).toBeInstanceOf(Object);
|
||||
expect(locale).toHaveProperty("weekAbbreviation");
|
||||
expect(locale.weekAbbreviation).toBe("Sem");
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,15 +1,13 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require 'rake'
|
||||
|
||||
RSpec.describe 'truncate_data.rake' do
|
||||
include_context "rake"
|
||||
|
||||
describe ':truncate' do
|
||||
context 'when months_to_keep is specified' do
|
||||
it 'truncates order cycles closed earlier than months_to_keep months ago' do
|
||||
Rake.application.rake_require 'tasks/data/truncate_data'
|
||||
Rake::Task.define_task(:environment)
|
||||
|
||||
highline = instance_double(HighLine, agree: true)
|
||||
allow(HighLine).to receive(:new).and_return(highline)
|
||||
|
||||
@@ -27,7 +25,7 @@ RSpec.describe 'truncate_data.rake' do
|
||||
create(:order, order_cycle: recent_order_cycle)
|
||||
|
||||
months_to_keep = 6
|
||||
Rake.application.invoke_task "ofn:data:truncate[#{months_to_keep}]"
|
||||
invoke_task "ofn:data:truncate[#{months_to_keep}]"
|
||||
|
||||
expect(OrderCycle.all).to contain_exactly(recent_order_cycle)
|
||||
end
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require 'rake'
|
||||
|
||||
RSpec.describe 'enterprises.rake' do
|
||||
before(:all) do
|
||||
Rake.application.rake_require("tasks/enterprises")
|
||||
Rake::Task.define_task(:environment)
|
||||
end
|
||||
include_context "rake"
|
||||
|
||||
describe ':remove_enterprise' do
|
||||
context 'when the enterprises exists' do
|
||||
@@ -15,7 +11,7 @@ RSpec.describe 'enterprises.rake' do
|
||||
enterprise = create(:enterprise)
|
||||
|
||||
expect {
|
||||
Rake.application.invoke_task "ofn:remove_enterprise[#{enterprise.id}]"
|
||||
invoke_task "ofn:remove_enterprise[#{enterprise.id}]"
|
||||
}.to change { Enterprise.count }.by(-1)
|
||||
end
|
||||
end
|
||||
@@ -32,7 +28,7 @@ RSpec.describe 'enterprises.rake' do
|
||||
enterprise_diff.connected_apps.create
|
||||
|
||||
expect {
|
||||
Rake.application.invoke_task(
|
||||
invoke_task(
|
||||
"ofn:enterprises:activate_connected_app_type[affiliate_sales_data]"
|
||||
)
|
||||
}.to change { ConnectedApps::AffiliateSalesData.count }.by(1)
|
||||
|
||||
@@ -1,23 +1,15 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require 'rake'
|
||||
|
||||
RSpec.describe 'ofn:import:product_images' do
|
||||
before(:all) do
|
||||
Rake.application.rake_require("tasks/import_product_images")
|
||||
Rake::Task.define_task(:environment)
|
||||
end
|
||||
|
||||
before do
|
||||
Rake::Task['ofn:import:product_images'].reenable
|
||||
end
|
||||
include_context "rake"
|
||||
|
||||
describe 'task' do
|
||||
context "filename is blank" do
|
||||
it 'raises an error' do
|
||||
expect {
|
||||
Rake.application.invoke_task('ofn:import:product_images')
|
||||
invoke_task('ofn:import:product_images')
|
||||
}.to raise_error(RuntimeError,
|
||||
'Filename required')
|
||||
end
|
||||
@@ -28,7 +20,7 @@ RSpec.describe 'ofn:import:product_images' do
|
||||
allow(CSV).to receive(:read).and_return(CSV::Table.new([]))
|
||||
|
||||
expect {
|
||||
Rake.application.invoke_task('ofn:import:product_images["path/to/csv/file.csv"]')
|
||||
invoke_task('ofn:import:product_images["path/to/csv/file.csv"]')
|
||||
}.to raise_error(RuntimeError, 'CSV columns reqired: ["producer", "name", "image_url"]')
|
||||
end
|
||||
end
|
||||
@@ -74,7 +66,7 @@ RSpec.describe 'ofn:import:product_images' do
|
||||
OUTPUT
|
||||
|
||||
expect {
|
||||
Rake.application.invoke_task('ofn:import:product_images["path/to/csv/file.csv"]')
|
||||
invoke_task('ofn:import:product_images["path/to/csv/file.csv"]')
|
||||
}.to output(expected_output).to_stdout
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require 'rake'
|
||||
|
||||
RSpec.describe "reset.rake" do
|
||||
before(:all) do
|
||||
Rake.application.rake_require("tasks/reset")
|
||||
Rake::Task.define_task(:environment)
|
||||
end
|
||||
include_context "rake"
|
||||
|
||||
it "clears job queues" do
|
||||
job_class = Class.new do
|
||||
@@ -18,7 +14,7 @@ RSpec.describe "reset.rake" do
|
||||
queue = Sidekiq::Queue.all.first # rubocop:disable Rails/RedundantActiveRecordAllMethod
|
||||
|
||||
expect {
|
||||
Rake.application.invoke_task "ofn:reset_sidekiq"
|
||||
invoke_task "ofn:reset_sidekiq"
|
||||
}.to change {
|
||||
queue.count
|
||||
}.to(0)
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require 'rake'
|
||||
|
||||
RSpec.describe 'sample_data.rake' do
|
||||
before(:all) do
|
||||
Rake.application.rake_require 'tasks/sample_data'
|
||||
Rake::Task.define_task(:environment)
|
||||
end
|
||||
include_context "rake"
|
||||
|
||||
before do
|
||||
# Create seed data required by the sample data.
|
||||
@@ -16,7 +12,7 @@ RSpec.describe 'sample_data.rake' do
|
||||
end
|
||||
|
||||
it "creates some sample data to play with" do
|
||||
Rake.application.invoke_task "ofn:sample_data"
|
||||
invoke_task "ofn:sample_data"
|
||||
|
||||
expect(EnterpriseGroup.count).to eq 1
|
||||
expect(Customer.count).to eq 2
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require 'rake'
|
||||
|
||||
RSpec.describe "simplecov.rake" do
|
||||
before(:all) do
|
||||
Rake.application.rake_require("tasks/simplecov")
|
||||
end
|
||||
include_context "rake"
|
||||
|
||||
describe "simplecov:collate_results" do
|
||||
context "when there are reports to merge" do
|
||||
@@ -16,10 +13,16 @@ RSpec.describe "simplecov.rake" do
|
||||
Dir.mktmpdir do |tmp_dir|
|
||||
output_dir = File.join(tmp_dir, "output")
|
||||
|
||||
task_name = "simplecov:collate_results[#{input_dir},#{output_dir}]"
|
||||
|
||||
expect {
|
||||
Rake.application.invoke_task(
|
||||
"simplecov:collate_results[#{input_dir},#{output_dir}]"
|
||||
)
|
||||
if ENV["COVERAGE"]
|
||||
# Start task in a new process to not mess with our coverage report.
|
||||
`bundle exec rake #{task_name}`
|
||||
else
|
||||
# Use the quick standard invocation in dev.
|
||||
invoke_task(task_name)
|
||||
end
|
||||
}.to change { Dir.exist?(output_dir) }.
|
||||
from(false).
|
||||
to(true).
|
||||
|
||||
@@ -4,18 +4,14 @@ require 'spec_helper'
|
||||
require 'rake'
|
||||
|
||||
RSpec.describe 'users.rake' do
|
||||
before do
|
||||
Rake.application.rake_require 'tasks/users'
|
||||
Rake::Task.define_task(:environment)
|
||||
Rake::Task['ofn:remove_enterprise_limit'].reenable
|
||||
end
|
||||
include_context "rake"
|
||||
|
||||
describe ':remove_enterprise_limit' do
|
||||
context 'when the user exists' do
|
||||
let(:user) { create(:user) }
|
||||
|
||||
it 'sets the enterprise_limit to the maximum integer' do
|
||||
Rake.application.invoke_task "ofn:remove_enterprise_limit[#{user.id}]"
|
||||
invoke_task "ofn:remove_enterprise_limit[#{user.id}]"
|
||||
|
||||
expect(user.reload.enterprise_limit).to eq(2_147_483_647)
|
||||
end
|
||||
@@ -24,7 +20,7 @@ RSpec.describe 'users.rake' do
|
||||
context 'when the user does not exist' do
|
||||
it 'raises' do
|
||||
expect {
|
||||
Rake.application.invoke_task "ofn:remove_enterprise_limit[123]"
|
||||
invoke_task "ofn:remove_enterprise_limit[123]"
|
||||
}.to raise_error(ActiveRecord::RecordNotFound)
|
||||
end
|
||||
end
|
||||
|
||||
15
spec/models/dfc_permission_spec.rb
Normal file
15
spec/models/dfc_permission_spec.rb
Normal file
@@ -0,0 +1,15 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe DfcPermission do
|
||||
it { is_expected.to belong_to :user }
|
||||
it { is_expected.to belong_to :enterprise }
|
||||
it { is_expected.to validate_presence_of :grantee }
|
||||
it { is_expected.to validate_presence_of :scope }
|
||||
it {
|
||||
is_expected.to validate_inclusion_of(:scope)
|
||||
.in_array(%w[ReadEnterprise ReadProducts ReadOrders])
|
||||
.in_array(%w[WriteEnterprise WriteProducts WriteOrders])
|
||||
}
|
||||
end
|
||||
35
spec/support/shared_contexts/rake.rb
Normal file
35
spec/support/shared_contexts/rake.rb
Normal file
@@ -0,0 +1,35 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Let this context take care of Rake testing gotchas.
|
||||
#
|
||||
# ```rb
|
||||
# RSpec.describe "my_task.rake" do
|
||||
# include_context "rake"
|
||||
# # ..
|
||||
# ```
|
||||
#
|
||||
shared_context "rake" do
|
||||
before(:all) do
|
||||
# Make sure that Rake tasks are only loaded once.
|
||||
# Otherwise we lose code coverage data.
|
||||
if Rake::Task.tasks.empty?
|
||||
Openfoodnetwork::Application.load_tasks
|
||||
Rake::Task.define_task(:environment)
|
||||
end
|
||||
end
|
||||
|
||||
# Use the same task string as you would on the command line.
|
||||
#
|
||||
# ```rb
|
||||
# invoke_task "example:task[arg1,arg2]"
|
||||
# ```
|
||||
#
|
||||
# This helper makes sure that you can run a task multiple times,
|
||||
# even within the same test example.
|
||||
def invoke_task(task_string)
|
||||
Rake.application.invoke_task(task_string)
|
||||
ensure
|
||||
name, _args = Rake.application.parse_task_string(task_string)
|
||||
Rake::Task[name].reenable
|
||||
end
|
||||
end
|
||||
88
spec/system/admin/enterprises/dfc_permissions_spec.rb
Normal file
88
spec/system/admin/enterprises/dfc_permissions_spec.rb
Normal file
@@ -0,0 +1,88 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "system_helper"
|
||||
|
||||
RSpec.describe "DFC Permissions", feature: "cqcm-dev", vcr: true do
|
||||
let(:enterprise) { create(:enterprise) }
|
||||
|
||||
before do
|
||||
login_as enterprise.owner
|
||||
end
|
||||
|
||||
it "is not visible when no platform is enabled" do
|
||||
Flipper.disable("cqcm-dev")
|
||||
visit edit_admin_enterprise_path(enterprise)
|
||||
expect(page).not_to have_content "CONNECTED APPS"
|
||||
end
|
||||
|
||||
it "can share data with another platform" do
|
||||
visit edit_admin_enterprise_path(enterprise)
|
||||
|
||||
scroll_to :bottom
|
||||
click_link "Connected apps"
|
||||
|
||||
# The component displays something and then replaces it with the real
|
||||
# list. That leads to a race condition and we have to just wait until
|
||||
# the component is loaded. :-(
|
||||
wait_for_component_loaded
|
||||
|
||||
within(platform_list("without-permissions")) do
|
||||
expect(page).to have_content "Proxy Dev Portal"
|
||||
|
||||
# NotSupportedError: Failed to execute 'evaluate' on 'Document':
|
||||
# The node provided is '#document-fragment', which is not a valid context node type.
|
||||
#
|
||||
# click_on "Agree and share"
|
||||
|
||||
# This hack works
|
||||
find("button", text: "Agree and share").native.trigger("click")
|
||||
end
|
||||
|
||||
within_platform_list("approved") do
|
||||
expect(page).to have_content "Proxy Dev Portal"
|
||||
find("button", text: "Stop sharing").native.trigger("click")
|
||||
end
|
||||
|
||||
within_platform_list("without-permissions") do
|
||||
expect(page).to have_content "Proxy Dev Portal"
|
||||
find("button", text: "Agree and share").native.trigger("click")
|
||||
end
|
||||
|
||||
within_platform_list("approved") do
|
||||
expect(page).to have_content "Proxy Dev Portal"
|
||||
end
|
||||
end
|
||||
|
||||
def wait_for_component_loaded
|
||||
retry_expectations do
|
||||
within(page.find('solid-permissioning').shadow_root) do
|
||||
expect(page).to have_content "APPROVED PLATFORMS"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def within_platform_list(variant, &block)
|
||||
retry_expectations(on: Ferrum::JavaScriptError) do
|
||||
within(platform_list(variant), &block)
|
||||
end
|
||||
end
|
||||
|
||||
# Handy helper adopted from CERES Fair Food and modified.
|
||||
# We may want to share this but don't have a need for it now.
|
||||
def retry_expectations(on: RSpec::Expectations::ExpectationNotMetError)
|
||||
start = Time.now.utc
|
||||
finish = start + Capybara.default_max_wait_time
|
||||
|
||||
yield
|
||||
rescue on
|
||||
raise if Time.now.utc > finish
|
||||
|
||||
sleep 0.1
|
||||
retry
|
||||
end
|
||||
|
||||
def platform_list(variant)
|
||||
page.find('solid-permissioning').shadow_root
|
||||
.find("platform-block[variant='#{variant}']").shadow_root
|
||||
end
|
||||
end
|
||||
@@ -20,6 +20,12 @@ Capybara.register_driver(:cuprite_ofn) do |app|
|
||||
url_whitelist: [
|
||||
%r{^http://localhost}, %r{^http://0.0.0.0}, %r{http://127.0.0.1},
|
||||
|
||||
# Testing the DFC Permissions component by Startin'Blox:
|
||||
%r{^https://cdn.jsdelivr.net/npm/@startinblox/},
|
||||
%r{^https://cdn.startinblox.com/},
|
||||
%r{^https://data-server.cqcm.startinblox.com/scopes$},
|
||||
%r{^https://api.proxy-dev.cqcm.startinblox.com/profile$},
|
||||
|
||||
# Just for testing external connections: spec/system/billy_spec.rb
|
||||
%r{^https?://deb.debian.org},
|
||||
],
|
||||
@@ -44,6 +50,7 @@ RSpec.configure do |config|
|
||||
original_host = Rails.application.default_url_options[:host]
|
||||
Rails.application.default_url_options[:host] =
|
||||
"#{Capybara.current_session.server.host}:#{Capybara.current_session.server.port}"
|
||||
DfcProvider::Engine.routes.default_url_options = Rails.application.default_url_options
|
||||
example.run
|
||||
Rails.application.default_url_options[:host] = original_host
|
||||
remove_downloaded_files
|
||||
|
||||
122
swagger/dfc.yaml
122
swagger/dfc.yaml
@@ -151,9 +151,6 @@ paths:
|
||||
value:
|
||||
"@context": https://www.datafoodconsortium.org
|
||||
"@graph":
|
||||
- "@id": http://test.host/api/dfc/persons/12345
|
||||
"@type": dfc-b:Person
|
||||
dfc-b:affiliates: http://test.host/api/dfc/enterprises/10000
|
||||
- "@id": http://test.host/api/dfc/enterprises/10000
|
||||
"@type": dfc-b:Enterprise
|
||||
dfc-b:hasAddress: http://test.host/api/dfc/addresses/40000
|
||||
@@ -558,6 +555,125 @@ paths:
|
||||
"@type": dfc-b:Person
|
||||
'404':
|
||||
description: not found
|
||||
"/api/dfc/enterprises/{enterprise_id}/platforms":
|
||||
parameters:
|
||||
- name: enterprise_id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
get:
|
||||
summary: List platforms with scopes
|
||||
tags:
|
||||
- Platforms
|
||||
responses:
|
||||
'200':
|
||||
description: successful
|
||||
content:
|
||||
application/json:
|
||||
examples:
|
||||
test_example:
|
||||
value:
|
||||
"@context": https://cdn.startinblox.com/owl/context-bis.jsonld
|
||||
"@id": http://test.host/api/dfc/enterprises/10000/platforms
|
||||
dfc-t:platforms:
|
||||
"@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
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
- name: platform_id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
get:
|
||||
summary: Show platform scopes
|
||||
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": []
|
||||
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://example.com/scopes/ReadEnterprise
|
||||
"@type": dfc-t:Scope
|
||||
dfc-t:scope: ReadEnterprise
|
||||
- "@id": https://example.com/scopes/WriteEnterprise
|
||||
"@type": dfc-t:Scope
|
||||
dfc-t:scope: WriteEnterprise
|
||||
- "@id": https://example.com/scopes/ReadProducts
|
||||
"@type": dfc-t:Scope
|
||||
dfc-t:scope: ReadProducts
|
||||
- "@id": https://example.com/scopes/WriteProducts
|
||||
"@type": dfc-t:Scope
|
||||
dfc-t:scope: WriteProducts
|
||||
- "@id": https://example.com/scopes/ReadOrders
|
||||
"@type": dfc-t:Scope
|
||||
dfc-t:scope: ReadOrders
|
||||
- "@id": https://example.com/scopes/WriteOrders
|
||||
"@type": dfc-t:Scope
|
||||
dfc-t:scope: WriteOrders
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user