Compare commits

...

66 Commits

Author SHA1 Message Date
David Cook
90288b8cbf Merge pull request #13492 from chahmedejaz/revert/dependabot/bundler/rexml-3.3.9
500 Error preventing check out with Stripe payment method
2025-08-19 10:50:09 +10:00
Ahmed Ejaz
c821b0a285 revert "Bump rexml from 3.2.9 to 3.3.9" 2025-08-19 05:27:58 +05:00
Gaetan Craig-Riou
c37376d67e Merge pull request #13485 from openfoodfoundation/dependabot/bundler/bullet-8.0.8
Bump bullet from 7.1.6 to 8.0.8
2025-08-18 13:58:39 +10:00
dependabot[bot]
49ec5b2089 Bump bullet from 7.1.6 to 8.0.8
Bumps [bullet](https://github.com/flyerhzm/bullet) from 7.1.6 to 8.0.8.
- [Changelog](https://github.com/flyerhzm/bullet/blob/main/CHANGELOG.md)
- [Commits](https://github.com/flyerhzm/bullet/compare/7.1.6...8.0.8)

---
updated-dependencies:
- dependency-name: bullet
  dependency-version: 8.0.8
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-15 09:56:17 +00:00
Maikel
92ef5fe3d5 Merge pull request #13483 from openfoodfoundation/dependabot/bundler/pdf-reader-2.15.0
Bump pdf-reader from 2.12.0 to 2.15.0
2025-08-15 10:29:09 +10:00
Filipe
ae477b7e52 Merge pull request #13455 from kirst-n/13366-only-load-necessary-flatpickr
Optimise loading of language-specific date pickers
2025-08-14 23:24:59 +01:00
Filipe
0e191e5fca Merge pull request #13459 from rioug/13454-fix-redeemeing-voucher-when-using-paypal
[VINE] Redeem voucher before redirecting to payment url
2025-08-14 16:30:22 +01:00
dependabot[bot]
64f9ea6fc0 Bump pdf-reader from 2.12.0 to 2.15.0
Bumps [pdf-reader](https://github.com/yob/pdf-reader) from 2.12.0 to 2.15.0.
- [Changelog](https://github.com/yob/pdf-reader/blob/main/CHANGELOG)
- [Commits](https://github.com/yob/pdf-reader/compare/v2.12.0...v2.15.0)

---
updated-dependencies:
- dependency-name: pdf-reader
  dependency-version: 2.15.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-14 10:01:32 +00:00
Maikel
058c6749da Merge pull request #13477 from openfoodfoundation/dependabot/bundler/timecop-0.9.10
Bump timecop from 0.9.8 to 0.9.10
2025-08-14 13:20:18 +10:00
Maikel
2d15ec4458 Merge pull request #13478 from openfoodfoundation/dependabot/bundler/activerecord-7.1.5.2
Bump activerecord from 7.1.5.1 to 7.1.5.2
2025-08-14 13:18:58 +10:00
dependabot[bot]
56eaa8bb98 Bump activerecord from 7.1.5.1 to 7.1.5.2
Bumps [activerecord](https://github.com/rails/rails) from 7.1.5.1 to 7.1.5.2.
- [Release notes](https://github.com/rails/rails/releases)
- [Changelog](https://github.com/rails/rails/blob/v8.0.2.1/activerecord/CHANGELOG.md)
- [Commits](https://github.com/rails/rails/compare/v7.1.5.1...v7.1.5.2)

---
updated-dependencies:
- dependency-name: activerecord
  dependency-version: 7.1.5.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-14 01:21:32 +00:00
dependabot[bot]
1e1f1e1e1b Bump timecop from 0.9.8 to 0.9.10
Bumps [timecop](https://github.com/travisjeffery/timecop) from 0.9.8 to 0.9.10.
- [Changelog](https://github.com/travisjeffery/timecop/blob/master/History.md)
- [Commits](https://github.com/travisjeffery/timecop/compare/v0.9.8...v0.9.10)

---
updated-dependencies:
- dependency-name: timecop
  dependency-version: 0.9.10
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-13 09:58:01 +00:00
Maikel
1f8a9f9c76 Merge pull request #13470 from openfoodfoundation/dependabot/bundler/rack-2.2.14
Bump rack from 2.2.11 to 2.2.14
2025-08-13 12:45:59 +10:00
Maikel
b1893942ac Merge pull request #13469 from openfoodfoundation/dependabot/bundler/net-imap-0.4.20
Bump net-imap from 0.4.10 to 0.4.20
2025-08-13 12:40:50 +10:00
dependabot[bot]
ad59ed4d40 Bump rack from 2.2.11 to 2.2.14
Bumps [rack](https://github.com/rack/rack) from 2.2.11 to 2.2.14.
- [Release notes](https://github.com/rack/rack/releases)
- [Changelog](https://github.com/rack/rack/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rack/rack/compare/v2.2.11...v2.2.14)

---
updated-dependencies:
- dependency-name: rack
  dependency-version: 2.2.14
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-13 00:02:14 +00:00
Maikel
8491a167ed Merge pull request #13350 from mkllnk/dfc-ui
Add permission module with example data
2025-08-13 10:00:53 +10:00
dependabot[bot]
59277292fb Bump net-imap from 0.4.10 to 0.4.20
Bumps [net-imap](https://github.com/ruby/net-imap) from 0.4.10 to 0.4.20.
- [Release notes](https://github.com/ruby/net-imap/releases)
- [Commits](https://github.com/ruby/net-imap/compare/v0.4.10...v0.4.20)

---
updated-dependencies:
- dependency-name: net-imap
  dependency-version: 0.4.20
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-12 06:54:11 +00:00
Gaetan Craig-Riou
354a7ab687 Merge pull request #13465 from openfoodfoundation/dependabot/bundler/fugit-1.11.1
Bump fugit from 1.8.1 to 1.11.1
2025-08-12 15:06:20 +10:00
Gaetan Craig-Riou
a5a1ee9bd9 Merge pull request #13462 from openfoodfoundation/dependabot/bundler/thor-1.4.0
Bump thor from 1.3.1 to 1.4.0
2025-08-12 15:02:23 +10:00
Gaetan Craig-Riou
ad3f78ef69 Merge pull request #13466 from openfoodfoundation/dependabot/bundler/uri-0.13.2
Bump uri from 0.13.0 to 0.13.2
2025-08-12 14:58:40 +10:00
Gaetan Craig-Riou
e02497b163 Merge pull request #13467 from openfoodfoundation/dependabot/bundler/rails-html-sanitizer-1.6.1
Bump rails-html-sanitizer from 1.6.0 to 1.6.1
2025-08-12 14:57:59 +10:00
Gaetan Craig-Riou
7d2d94398f Merge pull request #13464 from openfoodfoundation/dependabot/bundler/cgi-0.3.7
Bump cgi from 0.3.6 to 0.3.7
2025-08-12 14:49:47 +10:00
Gaetan Craig-Riou
0ecf004ff2 Merge pull request #13463 from openfoodfoundation/dependabot/bundler/rexml-3.3.9
Bump rexml from 3.2.9 to 3.3.9
2025-08-12 14:48:06 +10:00
dependabot[bot]
444f448207 Bump rails-html-sanitizer from 1.6.0 to 1.6.1
Bumps [rails-html-sanitizer](https://github.com/rails/rails-html-sanitizer) from 1.6.0 to 1.6.1.
- [Release notes](https://github.com/rails/rails-html-sanitizer/releases)
- [Changelog](https://github.com/rails/rails-html-sanitizer/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rails/rails-html-sanitizer/compare/v1.6.0...v1.6.1)

---
updated-dependencies:
- dependency-name: rails-html-sanitizer
  dependency-version: 1.6.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-12 04:31:53 +00:00
dependabot[bot]
d9381b23d7 Bump uri from 0.13.0 to 0.13.2
Bumps [uri](https://github.com/ruby/uri) from 0.13.0 to 0.13.2.
- [Release notes](https://github.com/ruby/uri/releases)
- [Commits](https://github.com/ruby/uri/compare/v0.13.0...v0.13.2)

---
updated-dependencies:
- dependency-name: uri
  dependency-version: 0.13.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-12 04:31:50 +00:00
dependabot[bot]
6a9a2884d6 Bump fugit from 1.8.1 to 1.11.1
Bumps [fugit](https://github.com/floraison/fugit) from 1.8.1 to 1.11.1.
- [Changelog](https://github.com/floraison/fugit/blob/master/CHANGELOG.md)
- [Commits](https://github.com/floraison/fugit/compare/v1.8.1...v1.11.1)

---
updated-dependencies:
- dependency-name: fugit
  dependency-version: 1.11.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-12 04:31:11 +00:00
dependabot[bot]
70edd4b898 Bump cgi from 0.3.6 to 0.3.7
Bumps [cgi](https://github.com/ruby/cgi) from 0.3.6 to 0.3.7.
- [Release notes](https://github.com/ruby/cgi/releases)
- [Commits](https://github.com/ruby/cgi/compare/v0.3.6...v0.3.7)

---
updated-dependencies:
- dependency-name: cgi
  dependency-version: 0.3.7
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-12 04:31:07 +00:00
dependabot[bot]
b57a2befd9 Bump rexml from 3.2.9 to 3.3.9
Bumps [rexml](https://github.com/ruby/rexml) from 3.2.9 to 3.3.9.
- [Release notes](https://github.com/ruby/rexml/releases)
- [Changelog](https://github.com/ruby/rexml/blob/master/NEWS.md)
- [Commits](https://github.com/ruby/rexml/compare/v3.2.9...v3.3.9)

---
updated-dependencies:
- dependency-name: rexml
  dependency-version: 3.3.9
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-12 04:27:20 +00:00
dependabot[bot]
fef9a78198 Bump thor from 1.3.1 to 1.4.0
Bumps [thor](https://github.com/rails/thor) from 1.3.1 to 1.4.0.
- [Release notes](https://github.com/rails/thor/releases)
- [Commits](https://github.com/rails/thor/compare/v1.3.1...v1.4.0)

---
updated-dependencies:
- dependency-name: thor
  dependency-version: 1.4.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-12 04:24:48 +00:00
Maikel
dd86736170 Merge pull request #13461 from openfoodfoundation/dependabot/bundler/webrick-1.8.2
Bump webrick from 1.8.1 to 1.8.2
2025-08-12 13:54:23 +10:00
Maikel
0d8c7ef118 Merge pull request #13460 from openfoodfoundation/dependabot/bundler/nokogiri-1.18.9
Bump nokogiri from 1.16.5 to 1.18.9
2025-08-12 13:52:57 +10:00
dependabot[bot]
20730b8768 Bump webrick from 1.8.1 to 1.8.2
Bumps [webrick](https://github.com/ruby/webrick) from 1.8.1 to 1.8.2.
- [Release notes](https://github.com/ruby/webrick/releases)
- [Commits](https://github.com/ruby/webrick/compare/v1.8.1...v1.8.2)

---
updated-dependencies:
- dependency-name: webrick
  dependency-version: 1.8.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-12 03:43:07 +00:00
dependabot[bot]
ad7c69189b Bump nokogiri from 1.16.5 to 1.18.9
Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.16.5 to 1.18.9.
- [Release notes](https://github.com/sparklemotion/nokogiri/releases)
- [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.16.5...v1.18.9)

---
updated-dependencies:
- dependency-name: nokogiri
  dependency-version: 1.18.9
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-12 03:22:15 +00:00
Maikel Linke
3a72aefc1c Fail test when timeout reached
In this example it didn't matter but if we re-use the helper then it
needs to raise an error after the timeout has been reached.
2025-08-12 09:54:48 +10:00
David Cook
e855ea0dbd Merge pull request #13453 from mkllnk/rails-7.1
Allow only existing deprecations in Rails 7.1
2025-08-12 09:44:25 +10:00
David Cook
1eba950e19 Merge pull request #13451 from mkllnk/remove-person
Remove Person from product catalog
2025-08-12 09:42:40 +10:00
David Cook
9cd04c087e Merge pull request #13450 from mkllnk/engine-ruby-version
Losen engine gemspec requirement for Dependabot
2025-08-12 09:40:01 +10:00
David Cook
459d25e533 Merge pull request #13447 from mkllnk/cover-rake
Report code coverage on rake tasks
2025-08-12 09:37:51 +10:00
Kirst
b06e562425 Remove flatpickr controller test that isn't useful based on feedback 2025-08-11 20:29:11 +10:00
Kirst
2936cfebca Remove I18n assignment from flatpickr controller test from feedback 2025-08-11 20:29:11 +10:00
Kirst
b8ad428b5d Load only specified flatpickr locale
Dynamically import only the requested flatpickr locale.

English locale is bundled by default, so passing null triggers flatpickr's built-in English fallback without an explicit import.
2025-08-11 20:28:47 +10:00
Maikel Linke
ca34d24847 Replace long waits with better polling
Capybara polls under the hood as well. So we do something similar here
but tailored to the tested code. This reduced the test run time on my
machine from 35 seconds to 15 seconds.
2025-08-11 17:07:44 +10:00
Maikel Linke
6e581fce75 Remove unnecessary styling
The early dev versions of the DPM needed these styles. Now the module
looks fine without any additional styles.
2025-08-11 16:29:08 +10:00
Gaetan Craig-Riou
66041061fb Redeem VINE voucher before redirecting to payment url
When using paypal, we need to redeem the voucher before redirecting to
the payment gateway url, otherwise the voucher will never get redeemed.
2025-08-11 16:28:04 +10:00
Maikel Linke
e54c27c900 Use more precise regex 2025-08-11 16:23:08 +10:00
Maikel Linke
b3d3d6bf06 Allow DPM feature for specific users 2025-08-11 15:25:50 +10:00
Maikel Linke
5876c52318 Test all known scopes 2025-08-11 15:15:00 +10:00
Maikel Linke
842f4ae40e Re-enable CSRF check supported by DPM now 2025-08-11 15:13:35 +10:00
Maikel Linke
342ef4e9eb Complete smoke test of DFC data sharing
Working within a shadow root of the web component isn't well supported
by Capybara and I needed to find some workarounds. It's not pretty but
it works (on my machine). *fingers crossed*
2025-08-08 14:00:41 +10:00
Maikel Linke
210201514e Add gem capybara-shadowdom to access web component 2025-08-08 14:00:41 +10:00
Maikel Linke
2d3f18a71b Load DFC Permissions module in system spec
But we can't access the inside of the component yet.
2025-08-08 14:00:41 +10:00
Maikel Linke
9d284b7110 Set language to display scope labels 2025-08-08 14:00:41 +10:00
Maikel Linke
994f1ca6c6 Update scope ids 2025-08-08 14:00:41 +10:00
Maikel Linke
f65e4797cf Add feature toggle for DFC dev platform 2025-08-08 14:00:40 +10:00
Maikel Linke
52aeec5ac4 Update and list scopes for real 2025-08-08 14:00:40 +10:00
Maikel Linke
7032b3f463 Add endpoint to update scopes of platform
Dummy implementation only.
2025-08-08 14:00:40 +10:00
Maikel Linke
c26686b430 Add DfcPermission model to persist granted scopes 2025-08-08 14:00:38 +10:00
Maikel Linke
60c8f4ee20 Add DFC API endpoint for listing platforms
Only listing example JSON for now.

This is not part of the official DFC API but it's a DFC-related API and
therefore we put it in the same namespace.

The DFC Permission Module will make authenticated requests to grant
certain platforms certain permissions.
2025-08-08 14:00:01 +10:00
Maikel Linke
25f396c126 Add permission module with example data
It's basically just copied from the Readme file still pointing to the
development server and it's not interacting with OFN just yet.
2025-08-08 14:00:01 +10:00
Maikel Linke
0166abcd2a Remove deprecated and unnecessary config 2025-08-08 11:18:34 +10:00
Maikel Linke
4cd0071dd4 Allow only existing deprecations
* Allow deprecated cache_format_version
* Allow deprecated Rails.application.secrets
* Allow deprecated Passing the class as positional argument
* Allow deprecated alias_attribute with non-attribute targets
* Allow deprecated model aliases
* Allow deprecated action_dispatch.show_exceptions
2025-08-08 11:17:41 +10:00
Maikel Linke
1ec570375f Remove Person from product catalog
Early versions of the DFC standard demanded that all data is published
in relationship to the authenticated user. But that is not necessary
anymore and can add complications when a platform is authenticated as
client user.
2025-08-07 14:56:35 +10:00
Maikel Linke
75c33b29d5 Losen engine gemspec requirement for Dependabot
Dependabot doesn't seem to be able to resolve the version correctly. We
got this message:

```
Could not find compatible versions

Because every version of web depends on Ruby = 0.0.1
  and Gemfile depends on web >= 0,
  Ruby = 0.0.1 is required.
So, because current Ruby version is = 3.1.4,
  version solving has failed.
```
2025-08-07 12:59:32 +10:00
Maikel
910ded1a8c Typo
[skip ci]
2025-08-05 13:49:44 +10:00
Maikel Linke
2555a9e710 Ignore breaking code coverage for coverage spec
When we test our code coverage compilation, it breaks the code coverage
report for the current rspec process. By running that code separately,
we gain a correct coverage report for the rest of the code again.

So unfortunately, we can't report on the code coverage of this
particular task and have to ignore it. But at least CI depends on the
correct function of this task and would fail if it didn't work.
2025-08-05 12:45:05 +10:00
Maikel Linke
f532c4712e Load rake tasks only once for code coverage
Apparently, Rake's way of reloading the task code confuses the code
coverage report. Code tested by rake task specs was not recognised as
covered even though it was.
2025-08-05 12:44:13 +10:00
41 changed files with 55101 additions and 190 deletions

View File

@@ -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

View File

@@ -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'

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View 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

View File

@@ -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?

View 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"}

View File

@@ -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;
}
}
}

View File

@@ -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

View 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

View File

@@ -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"

View File

@@ -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'

View File

@@ -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

View File

@@ -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),

View File

@@ -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

View File

@@ -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

View File

@@ -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']

View 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

View File

@@ -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'

View File

@@ -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'

View File

@@ -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.

View File

@@ -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

View File

@@ -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.

View File

@@ -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

File diff suppressed because one or more lines are too long

View 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

View File

@@ -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

View 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");
});
});
});

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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).

View File

@@ -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

View 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

View 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

View 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

View File

@@ -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

View File

@@ -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