Compare commits

...

130 Commits

Author SHA1 Message Date
Maikel Linke
9bf2dad343 Update all locales with the latest Transifex translations 2025-08-29 15:15:19 +10:00
David Cook
05b3417f77 Merge pull request #13512 from mkllnk/remove-timecop-usage
Remove remaining Timecop usage
2025-08-29 14:09:50 +10:00
Maikel Linke
403aa6ac6f Remove remaining Timecop usage 2025-08-29 11:16:20 +10:00
Filipe
fbad3ee9f4 Merge pull request #13484 from cesarlr/patch-1
Update Gemfile.lock
2025-08-28 19:38:59 +01:00
Filipe
ddb8b2d08f Merge pull request #13496 from dacook/fix-link
Fix link to enterprise payment methods tab
2025-08-28 19:17:37 +01:00
Filipe
42c9ee033a Merge pull request #13503 from AndreyUsyaev/usandy/fix-i18n-sells-options
Fix missed I18n translations for enterprises sells options
2025-08-28 18:50:07 +01:00
Maikel Linke
524634b4ea Bump wkhtmltopdf-binary from 0.12.6.9 to 0.12.6.10 to support Debian 13 2025-08-28 11:46:21 +01:00
César López Ramírez
0b97171bb0 Update Gemfile.lock
Upgrade wkhtmltopdf-binary to support Ubuntu 24.04
2025-08-28 11:46:21 +01:00
Filipe
b0c7e29b0d Merge pull request #13468 from mkllnk/rails-config-updates
Add Rails 7.0 and 7.1 framework defaults
2025-08-28 11:44:44 +01:00
Andrey Usyaev
3d7799df19 Fix code review remarks 2025-08-27 13:21:44 +03:00
Andrey Usyaev
5f02d88a86 Fix missed I18n translations for enterprises sells options 2025-08-27 13:21:44 +03:00
Maikel
bdae8e6478 Merge pull request #13475 from mkllnk/dfc-sib-tokens
Accept tokens from Startin'Blox OIDC server
2025-08-27 14:55:30 +10:00
Gaetan Craig-Riou
053ef05baf Merge pull request #13480 from mkllnk/time-travel
Replace Timecop with Rails' time helpers
2025-08-27 09:34:58 +10:00
Ahmed Ejaz
7fcb31d563 Update all locales with the latest Transifex translations 2025-08-25 11:49:44 +05:00
Gaetan Craig-Riou
31a7374808 Merge pull request #13444 from garethdavisrogers/fix-docker-dependency-and-db-dev-env
Added cmake dep to dockerfile and added script for db:schema:load tha…
2025-08-25 14:10:10 +10:00
Gareth
e5ce06ae39 Updated branch 2025-08-22 12:49:24 -04:00
Gareth Rogers
5f64204d51 Merge branch 'master' into fix-docker-dependency-and-db-dev-env 2025-08-22 08:31:27 -04:00
Maikel Linke
94b75540e4 Replace Timecop with Rails' time helpers
Rails 4.1 added time helpers but we never bothered using them. But now
I'm getting rid of the Timecop dependency and use standard helpers.

Beware though that the new helpers always freeze time. When you travel
to a certain date then the clock stops ticking while Timecop maintained
the passing of time.

The freezing of time could cause problems if you are trying to enforce a
timeout. But all current specs don't seem affected.

In most cases, the freezing will make it easier to avoid flaky specs.
2025-08-22 16:57:04 +10:00
Maikel Linke
6e489d7770 Enforce required DFC permissions 2025-08-22 16:46:59 +10:00
Maikel Linke
81b1169e77 Configure undercover to exclude files 2025-08-22 16:13:20 +10:00
Maikel
4b558b4820 Merge pull request #13501 from openfoodfoundation/dependabot/npm_and_yarn/sha.js-2.4.12
Bump sha.js from 2.4.11 to 2.4.12
2025-08-22 16:12:26 +10:00
Maikel
e224b8f63b Merge pull request #13500 from openfoodfoundation/dependabot/npm_and_yarn/cipher-base-1.0.6
Bump cipher-base from 1.0.4 to 1.0.6
2025-08-22 16:11:30 +10:00
Maikel
80bb0606b4 Merge pull request #13499 from openfoodfoundation/dependabot/npm_and_yarn/floating-ui/dom-1.7.4
Bump @floating-ui/dom from 1.7.3 to 1.7.4
2025-08-22 15:50:47 +10:00
dependabot[bot]
499fcc791e Bump sha.js from 2.4.11 to 2.4.12
Bumps [sha.js](https://github.com/crypto-browserify/sha.js) from 2.4.11 to 2.4.12.
- [Changelog](https://github.com/browserify/sha.js/blob/master/CHANGELOG.md)
- [Commits](https://github.com/crypto-browserify/sha.js/compare/v2.4.11...v2.4.12)

---
updated-dependencies:
- dependency-name: sha.js
  dependency-version: 2.4.12
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-21 15:48:41 +00:00
dependabot[bot]
30dae3c3ea Bump cipher-base from 1.0.4 to 1.0.6
Bumps [cipher-base](https://github.com/crypto-browserify/cipher-base) from 1.0.4 to 1.0.6.
- [Changelog](https://github.com/browserify/cipher-base/blob/master/CHANGELOG.md)
- [Commits](https://github.com/crypto-browserify/cipher-base/compare/v1.0.4...v1.0.6)

---
updated-dependencies:
- dependency-name: cipher-base
  dependency-version: 1.0.6
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-21 15:23:41 +00:00
dependabot[bot]
af247c32a3 Bump @floating-ui/dom from 1.7.3 to 1.7.4
Bumps [@floating-ui/dom](https://github.com/floating-ui/floating-ui/tree/HEAD/packages/dom) from 1.7.3 to 1.7.4.
- [Release notes](https://github.com/floating-ui/floating-ui/releases)
- [Changelog](https://github.com/floating-ui/floating-ui/blob/master/packages/dom/CHANGELOG.md)
- [Commits](https://github.com/floating-ui/floating-ui/commits/@floating-ui/dom@1.7.4/packages/dom)

---
updated-dependencies:
- dependency-name: "@floating-ui/dom"
  dependency-version: 1.7.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-21 09:48:24 +00:00
Gareth
6f9dcf7e27 remove bundle check 2025-08-20 11:04:40 -04:00
Gareth
2d064bab64 Created a bundler service that runs once removing responsibilities from any other services. The bundler service always runs install which should still be pretty fast if nothing or only a few gems have changed. A healthcheck won't work unless bundler runs continuously which is impractical. Instead, a checksum is generated on bundle install and sentinels in the other services have a definite confirmation that bundle is complete. The nice thing about this approach is that web, webpack, and sidekiq (which share the same bundles dependencies) will not concurrently run bundle install solving dep install redundancies. 2025-08-20 10:13:20 -04:00
Gareth
b69eb9bdff Specified BUNDLE_PATH AND BUNDLE_APP_CONFIG in Dockerfile 2025-08-20 08:48:21 -04:00
David Cook
f79c1879bd Test that you can actually get to Stripe to connect your account
Well.. almost.
2025-08-20 13:06:59 +10:00
David Cook
646d538a3d Fix broken link
This link would go to the enterprise edit screen, but didn't successfully select the payment methods panel.

Ideally, the spec would try to follow the link and verify that you can see the Connect with Stripe button. But it opens the link in a new tab and I'm not sure how to test that.
2025-08-20 11:54:47 +10:00
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
Gareth
b95d798a27 Fixed webpack service so that web relies on its bundles. This has re-enabled JS 2025-08-18 12:24:27 -04:00
Gareth
e1e4aeac1f Added conditions to sidekiq too as it races db as well. Everything seems functional now 2025-08-18 11:52:52 -04:00
Gareth
c7ae47053e Added health check to avoid docker container racing 2025-08-18 11:38:57 -04:00
Gareth Rogers
5892ae1800 Merge branch 'master' into fix-docker-dependency-and-db-dev-env 2025-08-18 09:32:21 -04: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
Gareth
74368f939b By creating the db in the container on composition, the first migration file rejects the schema of the empty database. All I had to do was remove db creation from docker so that db:prepare will default to creating open_food_network_dev from schema.rb rather than perceiving a mismatch from the precreated docker db 2025-08-15 14:23:13 -04:00
Gareth
cb02cd39fe Reverting unexpected change to schema.rb as requested 2025-08-15 12:27:10 -04: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 Linke
1d2115766a Show product groups to platform user
I removed the caching of `managed_enterprises` in Permissions because
it's just a scope and calling it again is very cheap. And that makes the
method a lot easier to read now that we have a conditional here.

Accessing the managed enterprises via the user instead of a separate
scope on the Enterprise model also reduce the SQL queries. We may want
to use this method in more places. I prefer to keep the
admin-conditional in a permissions class instead of in the model.
2025-08-13 15:06:31 +10:00
Maikel Linke
6814ef43f4 Show addresses to platform users 2025-08-13 15:06:25 +10:00
Maikel Linke
c9e8294561 DRY with shared context 2025-08-13 15:02:09 +10:00
Maikel Linke
82d0e1bf68 Show enterprise to authorised platform user 2025-08-13 15:02:09 +10:00
Maikel Linke
b16e541a81 Show DFC catalog to authorised platform 2025-08-13 15:02:09 +10:00
Maikel Linke
c12d494de3 Demonstrate authentication as DFC client app 2025-08-13 15:02:09 +10:00
Maikel Linke
9be27842e1 Accepts tokens from Startin'Blox OIDC server
The API controllers don't know the new type of user yet and will raise
errors but we can work on that bit by bit.
2025-08-13 15:02:09 +10:00
Maikel Linke
2a7754edbf Add test for current token validation 2025-08-13 15:02:09 +10:00
Maikel Linke
cfeafbfc51 Update API docs with latest version 2025-08-13 15:02:08 +10: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
Maikel Linke
05b00f16ad Move config option to a better place 2025-08-12 20:24:16 +10:00
Maikel Linke
78fdaa68c8 Update config files with Rails 7.1 templates 2025-08-12 20:24:16 +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
Maikel Linke
e8813833fa Add Rails 7.1 framework defaults template 2025-08-12 15:43:45 +10: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
a5f44cb9b2 Update inflection config to Rails 7.0 template 2025-08-12 12:49:06 +10:00
Maikel Linke
97d21d8cbe Update parameter filtering to Rails 7.0 template 2025-08-12 12:45:48 +10:00
Maikel Linke
7afdd13b64 Update CSP config with Rails 7.0 template 2025-08-12 12:41:24 +10:00
Maikel Linke
54c446f0a3 Update asset config to Rails 7.0 templates 2025-08-12 12:30:30 +10:00
Maikel Linke
4454c90575 Update test config with Rails 7.0 template 2025-08-12 12:22:23 +10:00
Maikel Linke
dd3a61acdf Update production config with Rails 7.0 default 2025-08-12 12:10:22 +10:00
Maikel Linke
6d8ddd1eda Update development config with Rails 7.0 defaults 2025-08-12 12:10:19 +10:00
Maikel Linke
b8e8ab15d1 Update environment config with Rails 7.0 default 2025-08-12 11:06:33 +10:00
Maikel Linke
bf1d2f3620 Update boot config from Rails 7.0 template 2025-08-12 10:59:46 +10:00
Maikel Linke
43026ddc6a Update application config with Rails 7.0 defaults 2025-08-12 10:56:34 +10:00
Maikel Linke
18b83d2423 Add Rails 7.0 framework defaults templates 2025-08-12 10:42:37 +10: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
Gareth
3750898c44 Looks like db:prepare never fully ran and that's why it did not work. The issue seems to be using foreman with web, webpack, and sidekiq in the same script. Though not dependent on each other, the build order or port assignment was causing web to exit early upon build 2025-08-06 15:21:30 -04:00
Gareth
d34f8900d7 divided foreman queued services into 3 containers. Web was exiting seemingly at random and seems to be a conflict between web, web-pack, and sidekiq being run through foreman. The division into 3 dev containers has been very consistent in building the project correctly 2025-08-06 15:05:45 -04: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
Gareth
addf36a304 dummy commit for docker token check 2025-07-30 20:44:05 -04:00
Gareth
6a912b7d8c Added cmake dep to dockerfile and added script for db:schema:load that runs only if the schema is different than the latest migration 2025-07-30 20:12:53 -04:00
105 changed files with 56258 additions and 471 deletions

View File

@@ -2,13 +2,17 @@
# frozen_string_literal: true
SimpleCov.start 'rails' do
# The rails profile contains some filters already:
#
# - "/test/"
# - "/features/"
# - "/spec/"
# - "/autotest/"
# - /^\/config\//
# - /^\/db\//
add_filter '/bin/'
add_filter '/config/'
add_filter '/config/' # to include engine config
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

@@ -1,4 +1,9 @@
#!/bin/env ruby
# frozen_string_literal: true
-c master
--compare master
# This shouldn't be needed in undercover > 0.7.4
#
# * https://github.com/grodowski/undercover/issues/233
--exclude-files "bin/*,db/*,config/*,spec/*,engines/*/config/*,engines/*/spec/*"

View File

@@ -2,7 +2,9 @@ FROM ruby:3.1.4-alpine3.19 AS base
ENV LANG=C.UTF-8 \
LC_ALL=C.UTF-8 \
TZ=Europe/London \
RAILS_ROOT=/usr/src/app
RAILS_ROOT=/usr/src/app \
BUNDLE_PATH=/bundles \
BUNDLE_APP_CONFIG=/bundles
RUN apk --no-cache upgrade && \
apk add --no-cache tzdata postgresql-client imagemagick imagemagick-jpeg && \
apk add --no-cache --virtual wkhtmltopdf
@@ -14,7 +16,7 @@ FROM base AS development-base
RUN apk add --no-cache --virtual .build-deps \
build-base postgresql-dev git nodejs yarn && \
apk add --no-cache --virtual .dev-utils \
bash curl less vim chromium-chromedriver zlib-dev openssl-dev \
bash curl less vim chromium-chromedriver zlib-dev openssl-dev cmake\
readline-dev yaml-dev sqlite-dev libxml2-dev libxslt-dev libffi-dev vips-dev && \
curl -o /usr/local/bin/wait-for-it https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh && \
chmod +x /usr/local/bin/wait-for-it

View File

@@ -25,7 +25,8 @@ RUN apt-get update && apt-get install -y \
libjemalloc-dev \
libssl-dev \
ca-certificates \
gnupg
gnupg \
cmake
# Setup ENV variables
ENV PATH /usr/local/src/rbenv/shims:/usr/local/src/rbenv/bin:/usr/local/src/nodenv/shims:/usr/local/src/nodenv/bin:$PATH

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'
@@ -166,7 +167,6 @@ group :test, :development do
gem 'rswag'
gem 'shoulda-matchers'
gem 'stimulus_reflex_testing', github: "podia/stimulus_reflex_testing", branch: :main
gem 'timecop'
end
group :test do

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,12 @@ 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)
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 +862,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 +903,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)
@@ -909,7 +911,7 @@ GEM
chronic (>= 0.6.3)
wicked_pdf (2.8.1)
activesupport
wkhtmltopdf-binary (0.12.6.7)
wkhtmltopdf-binary (0.12.6.10)
xml-simple (1.1.8)
xpath (3.2.0)
nokogiri (~> 1.8)
@@ -941,6 +943,7 @@ DEPENDENCIES
cable_ready
cancancan (~> 1.15.0)
capybara
capybara-shadowdom
catalog!
coffee-rails (~> 5.0.0)
combine_pdf
@@ -1045,7 +1048,6 @@ DEPENDENCIES
stimulus_reflex_testing!
stringex (~> 2.8.5)
stripe
timecop
turbo-rails
turbo_power
undercover

View File

@@ -15,4 +15,4 @@ angular.module("admin.paymentMethods").controller "StripeController", ($scope, $
permalink = shops.filter((shop) ->
shop.id == $scope.paymentMethod.preferred_enterprise_id
)[0].permalink
"/admin/enterprises/#{permalink}/edit#/payment_methods"
"/admin/enterprises/#{permalink}/edit#/payment_methods_panel"

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
@@ -63,6 +71,11 @@ module Admin
"#{enterprise_attachment_removal_panel}_panel"
end
def enterprise_sells_options
scope = "admin.enterprises.admin_index.sells_options"
Enterprise::SELLS.map { |s| [I18n.t(s, scope:), s] }
end
private
def build_enterprise_side_menu_items(is_shop:, show_options: ) # rubocop:disable Metrics/MethodLength

View File

@@ -9,6 +9,7 @@ class ApplicationRecord < ActiveRecord::Base
include ArelHelpers::JoinAssociation
self.abstract_class = true
self.include_root_in_json = true
def self.image_service
ENV["S3_BUCKET"].present? ? :amazon_public : :local

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

@@ -75,6 +75,7 @@ class Enterprise < ApplicationRecord
has_one :stripe_account, dependent: :destroy
has_many :vouchers, dependent: :restrict_with_exception
has_many :connected_apps, dependent: :destroy
has_many :dfc_permissions, dependent: :destroy
has_one :custom_tab, dependent: :destroy
delegate :latitude, :longitude, :city, :state_name, to: :address

View File

@@ -28,7 +28,7 @@
= enterprise_form.check_box :is_primary_producer
= t('.producer')
- if spree_current_user.admin?
%td= enterprise_form.select :sells, Enterprise::SELLS, {}, class: 'select2 fullwidth'
%td= enterprise_form.select :sells, enterprise_sells_options, {}, class: 'select2 fullwidth'
%td= enterprise_form.check_box :visible, {}, 'public', 'hidden'
- if spree_current_user.admin?
%td= enterprise_form.select :owner_id, enterprise.users.map{ |e| [ e.email, e.id ] }, {}, class: "select2 fullwidth"

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

@@ -5,20 +5,36 @@ services:
environment:
POSTGRES_PASSWORD: f00d
POSTGRES_USER: ofn
POSTGRES_DB: open_food_network_dev
ports:
- 5432:5432
volumes:
- 'postgres:/var/lib/postgresql/data'
healthcheck:
test: ["CMD-SHELL", "PGPASSWORD=$$POSTGRES_PASSWORD pg_isready -q -h 127.0.0.1 -p 5432 -U $$POSTGRES_USER || exit 1"]
interval: 5s
timeout: 10s
retries: 10
redis:
image: redis
bundler:
build: .
# Runs once: installs gems into /bundles, writes a checksum sentinel, then exits
command: >
sh -lc 'bundle install --jobs 4 --retry 3 --quiet;
sha256sum Gemfile.lock > /bundles/.Gemfile.lock.sha'
volumes:
- .:/usr/src/app
- gems:/bundles
restart: "no"
web:
tty: true
stdin_open: true
build: .
ports:
- 3000:3000
- 3035:3035
volumes:
- .:/usr/src/app
- gems:/bundles
@@ -26,20 +42,69 @@ services:
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
depends_on:
- db
- redis
db:
condition: service_healthy
redis:
condition: service_started
webpack:
condition: service_started
environment:
DOCKER: true
DEV_CACHING: true
OFN_DB_HOST: db
OFN_REDIS_URL: redis://redis/
OFN_REDIS_JOBS_URL: redis://redis
OFN_REDIS_TEST_URL: redis://redis/3
WEBPACKER_DEV_SERVER_HOST: webpack
WEBPACKER_DEV_SERVER_PORT: 3035
WEBPACKER_DEV_SERVER_PUBLIC: localhost:3035
command: >
bash -c "rm -f tmp/pids/server.pid &&
(bundle check || bundle install) &&
bundle exec rake db:create &&
yarn install &&
bundle exec foreman start -f Procfile.docker"
sh -lc 'rm -f tmp/pids/server.pid;
until [ -f /bundles/.Gemfile.lock.sha ] && sha256sum -c /bundles/.Gemfile.lock.sha >/dev/null 2>&1; do sleep 0.5; done;
bundle exec rails db:prepare &&
yarn install &&
exec bundle exec rails s -b 0.0.0.0 -p 3000'
sidekiq:
build: .
command: >
sh -lc 'until [ -f /bundles/.Gemfile.lock.sha ] && sha256sum -c /bundles/.Gemfile.lock.sha >/dev/null 2>&1; do sleep 0.5; done;
exec bundle exec sidekiq'
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
volumes:
- .:/usr/src/app
- gems:/bundles
environment:
DOCKER: true
DEV_CACHING: true
OFN_DB_HOST: db
OFN_REDIS_URL: redis://redis/
OFN_REDIS_JOBS_URL: redis://redis
OFN_REDIS_TEST_URL: redis://redis/3
webpack:
build: .
command: >
sh -lc 'until [ -f /bundles/.Gemfile.lock.sha ] && sha256sum -c /bundles/.Gemfile.lock.sha >/dev/null 2>&1; do sleep 0.5; done;
exec ./bin/webpack-dev-server'
ports:
- "3035:3035"
volumes:
- .:/usr/src/app
- gems:/bundles
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://localhost:3035/webpack-dev-server >/dev/null || wget -qO- http://localhost:3035/sockjs-node/info >/dev/null"]
interval: 5s
timeout: 3s
retries: 30
environment:
WEBPACKER_DEV_SERVER_HOST: 0.0.0.0
volumes:
gems:
postgres:

View File

@@ -1,24 +1,19 @@
require_relative 'boot'
require_relative "boot"
require "rails"
[
"active_record/railtie",
"active_storage/engine",
"action_controller/railtie",
"action_view/railtie",
"action_mailer/railtie",
"active_job/railtie",
"action_cable/engine",
# "action_mailbox/engine",
# "action_text/engine",
"rails/test_unit/railtie",
"sprockets/railtie" # Disable this after migrating to Webpacker
].each do |railtie|
begin
require railtie
rescue LoadError
end
end
# Pick the frameworks you want:
require "active_model/railtie"
require "active_job/railtie"
require "active_record/railtie"
require "active_storage/engine"
require "action_controller/railtie"
require "action_mailer/railtie"
# require "action_mailbox/engine"
# require "action_text/engine"
require "action_view/railtie"
require "action_cable/engine"
require "rails/test_unit/railtie"
require "sprockets/railtie" # Disable this after migrating to Webpacker
require_relative "../lib/open_food_network/i18n_config"
require_relative '../lib/spree/core/environment'
@@ -26,15 +21,34 @@ require_relative '../lib/spree/core/mail_interceptor'
require_relative "../lib/i18n_digests"
require_relative "../lib/git_utils"
if defined?(Bundler)
# If you precompile assets before deploying to production, use this line
Bundler.require(*Rails.groups(:assets => %w(development test)))
# If you want your assets lazily compiled in production, use this line
# Bundler.require(:default, :assets, Rails.env)
end
# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups(:assets => %w(development test)))
module Openfoodnetwork
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 6.1
config.action_view.form_with_generates_remote_forms = false
config.active_record.cache_versioning = false
config.active_record.has_many_inversing = false
config.active_record.yaml_column_permitted_classes = [BigDecimal, Symbol, Time,
ActiveSupport::TimeWithZone,
ActiveSupport::TimeZone]
# Please, add to the `ignore` list any other `lib` subdirectories that do
# not contain `.rb` files, or that should not be reloaded or eager loaded.
# Common ones are `templates`, `generators`, or `middleware`, for example.
# config.autoload_lib(ignore: %w(assets tasks))
# Configuration for the application, engines, and railties goes here.
#
# These settings can be overridden in specific environments using the files
# in config/environments, which are processed later.
#
config.time_zone = ENV["TIMEZONE"]
# config.eager_load_paths << Rails.root.join("extras")
# Store a description of the current version
config.x.git_version = GitUtils::git_version
@@ -71,16 +85,6 @@ module Openfoodnetwork
end
end
# filter sensitive information during logging
initializer "spree.params.filter" do |app|
app.config.filter_parameters += [
:password,
:password_confirmation,
:number,
:verification_value
]
end
initializer "load_spree_calculators" do |app|
# Register Spree calculators
Rails.application.reloader.to_prepare do
@@ -161,10 +165,6 @@ module Openfoodnetwork
# Activate observers that should always be running.
# config.active_record.observers = :cacher, :garbage_collector, :forum_observer
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
config.time_zone = ENV["TIMEZONE"]
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
config.i18n.default_locale = OpenFoodNetwork::I18nConfig.default_locale
@@ -184,38 +184,14 @@ module Openfoodnetwork
# Enable the asset pipeline
config.assets.enabled = true
# Version of your assets, change this if you want to expire all your assets
config.assets.version = '1.2'
config.assets.initialize_on_precompile = true
# Unset X-Frame-Options header for embedded pages.
config.action_dispatch.default_headers.except! "X-Frame-Options"
# css and js files other than application.* are not precompiled by default
# Instead, they must be explicitly included below
# http://stackoverflow.com/questions/8012434/what-is-the-purpose-of-config-assets-precompile
config.assets.initialize_on_precompile = true
config.assets.precompile += ['admin/*.js', 'admin/**/*.js', 'admin_minimal.js']
config.assets.precompile += ['web/all.js']
config.assets.precompile += ['darkswarm/all.js']
config.assets.precompile += ['shared/*']
config.assets.precompile += ['mail.scss']
config.assets.precompile += ['*.jpg', '*.jpeg', '*.png', '*.gif' '*.svg']
# Highlight code that triggered database queries in logs.
config.active_record.verbose_query_logs = ENV.fetch("VERBOSE_QUERY_LOGS", false)
# Apply framework defaults. New recommended defaults are successively added with each Rails version and
# include the defaults from previous versions. For more info see:
# https://guides.rubyonrails.org/configuring.html#results-of-config-load-defaults
config.load_defaults 6.1
config.action_view.form_with_generates_remote_forms = false
config.active_record.cache_versioning = false
config.active_record.has_many_inversing = false
config.active_record.yaml_column_permitted_classes = [BigDecimal, Symbol, Time,
ActiveSupport::TimeWithZone,
ActiveSupport::TimeZone]
config.active_support.escape_html_entities_in_json = true
config.active_job.queue_adapter = :sidekiq

View File

@@ -1,7 +1,4 @@
require 'rubygems'
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
# Set up gems listed in the Gemfile.
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
require 'bootsnap/setup'
require "bundler/setup" # Set up gems listed in the Gemfile.
require "bootsnap/setup" # Speed up boot time by caching expensive operations.

View File

@@ -1,7 +1,5 @@
# Load the rails application
require_relative 'application'
# Load the Rails application.
require_relative "application"
# Initialize the rails application
Openfoodnetwork::Application.initialize!
ActiveRecord::Base.include_root_in_json = true
# Initialize the Rails application.
Rails.application.initialize!

View File

@@ -1,40 +1,87 @@
Openfoodnetwork::Application.configure do
config.action_controller.default_url_options = {host: "localhost", port: 3000}
# Settings specified here will take precedence over those in config/application.rb
#
require "active_support/core_ext/integer/time"
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# PROFILE switches several settings to a more "production-like" value
# for profiling and benchmarking the application locally. All changes you
# make to the app will require restart.
# In the development environment your application's code is reloaded on
# every request. This slows down response time but is perfect for development
# In the development environment your application's code is reloaded any time
# it changes. This slows down response time but is perfect for development
# since you don't have to restart the web server when you make code changes.
config.cache_classes = !!ENV["PROFILE"]
config.action_controller.default_url_options = {host: "localhost", port: 3000}
# Do not eager load code on boot.
config.eager_load = false
# Show full error reports.
config.consider_all_requests_local = true
# Enable server timing
config.server_timing = true
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
#
# To override this, set the appropriate locale in .env[.*] file.
config.time_zone = ENV.fetch("TIMEZONE", "UTC")
config.log_level = ENV.fetch("DEV_LOG_LEVEL", :debug)
# Enable/disable caching. By default caching is disabled.
# Run rails dev:cache to toggle caching.
if Rails.root.join("tmp/caching-dev.txt").exist? || !ENV["PROFILE"] || !!ENV["DEV_CACHING"]
config.action_controller.perform_caching = true
config.action_controller.enable_fragment_cache_logging = true
# :file_store is used by default when no cache store is specifically configured.
if !!ENV["PROFILE"] || !!ENV["DEV_CACHING"]
config.cache_store = :redis_cache_store, {
url: ENV.fetch("OFN_REDIS_URL", "redis://localhost:6379/1"),
expires_in: 90.minutes
}
config.public_file_server.headers = {
"Cache-Control" => "public, max-age=#{2.days.to_i}"
}
else
config.action_controller.perform_caching = false
config.cache_store = :null_store
end
config.eager_load = false
config.action_controller.default_url_options = {host: "localhost", port: 3000}
# Show full error reports and disable caching
config.consider_all_requests_local = true
config.action_controller.perform_caching = !!ENV["PROFILE"] || !!ENV["DEV_CACHING"]
# Store uploaded files on the local file system (see config/storage.yml for options).
# config.active_storage.service = :local
# Don't care if the mailer can't send
# Don't care if the mailer can't send.
config.action_mailer.raise_delivery_errors = false
# Print deprecation notices to the Rails logger
config.action_mailer.perform_caching = false
# Show emails using Letter Opener
config.action_mailer.delivery_method = :letter_opener
config.action_mailer.default_url_options = { host: "localhost:3000" }
# Print deprecation notices to the Rails logger.
config.active_support.deprecation = :log
# Only use best-standards-support built into browsers
config.action_dispatch.best_standards_support = :builtin
# Raise exceptions for disallowed deprecations.
config.active_support.disallowed_deprecation = :raise
# Tell Active Support which deprecation messages to disallow.
config.active_support.disallowed_deprecation_warnings = []
# Raise an error on page load if there are pending migrations.
config.active_record.migration_error = :page_load
# Highlight code that triggered database queries in logs.
config.active_record.verbose_query_logs = true
# Highlight code that enqueued background job in logs.
config.active_job.verbose_enqueue_logs = true
# Suppress logger output for asset requests.
config.assets.quiet = true
# Do not compress assets
config.assets.compress = false
@@ -59,17 +106,17 @@ Openfoodnetwork::Application.configure do
# $ bundle exec rake assets:clean
config.assets.debug = !!ENV["DEBUG_ASSETS"]
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
#
# To override this, set the appropriate locale in .env[.*] file.
config.time_zone = ENV.fetch("TIMEZONE", "UTC")
# Raises error for missing translations.
# config.i18n.raise_on_missing_translations = true
config.i18n.fallbacks = [:en]
# Show emails using Letter Opener
config.action_mailer.delivery_method = :letter_opener
config.action_mailer.default_url_options = { host: "localhost:3000" }
# Annotate rendered view with file names.
# config.action_view.annotate_rendered_view_with_filenames = true
config.log_level = ENV.fetch("DEV_LOG_LEVEL", :debug)
# Uncomment if you wish to allow Action Cable access from any origin.
# config.action_cable.disable_request_forgery_protection = true
# Raise error when a before_action's only/except options reference missing actions
# config.action_controller.raise_on_missing_callback_actions = true
end

View File

@@ -1,69 +1,113 @@
Openfoodnetwork::Application.configure do
# Settings specified here will take precedence over those in config/application.rb
require "active_support/core_ext/integer/time"
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# Code is not reloaded between requests.
config.enable_reloading = false
# Eager load code on boot. This eager loads most of Rails and
# your application in memory, allowing both threaded web servers
# and those relying on copy on write to perform better.
# Rake tasks automatically ignore this option for performance.
config.eager_load = true
# Code is not reloaded between requests
config.cache_classes = true
# Full error reports are disabled and caching is turned on
config.consider_all_requests_local = false
# Full error reports are disabled and caching is turned on.
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
# Disable Rails's static asset server (Apache or nginx will already do this)
# Ensures that a master key has been made available in ENV["RAILS_MASTER_KEY"], config/master.key, or an environment
# key such as config/credentials/production.key. This key is used to decrypt credentials (and other encrypted files).
# config.require_master_key = true
# Disable serving static files from `public/`, relying on NGINX/Apache to do so instead.
config.public_file_server.enabled = false
# Compress CSS using a preprocessor.
# config.assets.css_compressor = :sass
# Do not fall back to assets pipeline if a precompiled asset is missed.
config.assets.compile = false
# Enable serving of images, stylesheets, and JavaScripts from an asset server.
# config.asset_host = "http://assets.example.com"
# Compress JavaScripts and CSS
config.assets.compress = true
# Don't fallback to assets pipeline if a precompiled asset is missed
config.assets.compile = false
# Generate digests for assets URLs
config.assets.digest = true
# Defaults to Rails.root.join("public/assets")
# config.assets.manifest = YOUR_PATH
# Specifies the header that your server uses for sending files.
# config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache
# config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX
# Specifies the header that your server uses for sending files
# config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
# Store uploaded files on the local file system (see config/storage.yml for options).
# We set it in application.rb.
# config.active_storage.service = :local
# Mount Action Cable outside main process or domain.
# config.action_cable.mount_path = nil
# config.action_cable.url = "wss://example.com/cable"
# config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ]
config.action_cable.url = "#{ENV['OFN_URL']}/cable"
config.action_cable.allowed_request_origins = [/http:\/\/#{ENV['OFN_URL']}\/*/, /https:\/\/#{ENV['OFN_URL']}\/*/]
# Assume all access to the app is happening through a SSL-terminating reverse proxy.
# Can be used together with config.force_ssl for Strict-Transport-Security and secure cookies.
# config.assume_ssl = true
# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
config.force_ssl = true
# Use https in email links
config.action_mailer.default_url_options = { protocol: 'https' }
# Log to STDOUT by default
config.logger = ActiveSupport::Logger.new(STDOUT)
.tap { |logger| logger.formatter = ::Logger::Formatter.new }
.then { |logger| ActiveSupport::TaggedLogging.new(logger) }
# Set log level (default is :debug in Rails 4)
config.log_level = :info
# Configure logging:
config.log_formatter = Logger::Formatter.new.tap { |f| f.datetime_format = "%Y-%m-%d %H:%M:%S" }
# Prepend all log lines with the following tags.
config.log_tags = [:request_id]
# Use a different cache store in production
# "info" includes generic and useful information about system operation, but avoids logging too much
# information to avoid inadvertent exposure of personally identifiable information (PII). If you
# want to log everything, set the level to "debug".
config.log_level = ENV.fetch("RAILS_LOG_LEVEL", "info")
# Use a different cache store in production.
# config.cache_store = :mem_cache_store
config.cache_store = :redis_cache_store, {
url: ENV.fetch("OFN_REDIS_URL", "redis://localhost:6380/0"),
reconnect_attempts: 1
}
config.action_cable.url = "#{ENV['OFN_URL']}/cable"
config.action_cable.allowed_request_origins = [/http:\/\/#{ENV['OFN_URL']}\/*/, /https:\/\/#{ENV['OFN_URL']}\/*/]
# Use a real queuing backend for Active Job (and separate queues per environment).
# config.active_job.queue_adapter = :resque
# config.active_job.queue_name_prefix = "openfoodnetwork_production"
# Enable serving of images, stylesheets, and JavaScripts from an asset server
# config.action_controller.asset_host = "http://assets.example.com"
config.action_mailer.perform_caching = false
# Disable delivery errors, bad email addresses will be ignored
# Ignore bad email addresses and do not raise email delivery errors.
# Set this to true and configure the email server for immediate delivery to raise delivery errors.
# config.action_mailer.raise_delivery_errors = false
# Enable threaded mode
# config.threadsafe!
# Use https in email links
config.action_mailer.default_url_options = { protocol: 'https' }
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# the I18n.default_locale when a translation can not be found)
# the I18n.default_locale when a translation cannot be found).
config.i18n.fallbacks = [:en]
# Send deprecation notices to registered listeners
config.active_support.deprecation = :notify
# Do not dump schema after migrations.
config.active_record.dump_schema_after_migration = false
# Enable DNS rebinding protection and other `Host` header attacks.
# config.hosts = [
# "example.com", # Allow requests from example.com
# /.*\.example\.com/ # Allow requests from subdomains like `www.example.com`
# ]
# Skip DNS rebinding protection for the default health check endpoint.
# config.host_authorization = { exclude: ->(request) { request.path == "/up" } }
end

View File

@@ -1,17 +1,38 @@
Openfoodnetwork::Application.configure do
# Settings specified here will take precedence over those in config/application.rb
require "active_support/core_ext/integer/time"
# The test environment is used exclusively to run your application's
# test suite. You never need to work with it otherwise. Remember that
# your test database is "scratch space" for the test suite and is wiped
# and recreated between test runs. Don't rely on the data there!
# The test environment is used exclusively to run your application's
# test suite. You never need to work with it otherwise. Remember that
# your test database is "scratch space" for the test suite and is wiped
# and recreated between test runs. Don't rely on the data there!
Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb.
# While tests run files are not watched, reloading is not necessary.
config.enable_reloading = false
# StimulusReflex requires caching to be enabled.
config.cache_classes = false
# Eager loading loads your entire application. When running a single test locally,
# this is usually not necessary, and can slow down your test suite. However, it's
# recommended that you enable it in continuous integration systems to ensure eager
# loading is working properly before deploying your code.
# config.eager_load = ENV["CI"].present?
config.eager_load = false
# Configure static asset server for tests with Cache-Control for performance
config.time_zone = ENV.fetch("TIMEZONE", "UTC")
# Configure public file server for tests with Cache-Control for performance.
config.public_file_server.enabled = true
config.public_file_server.headers = { 'Cache-Control' => 'public, max-age=3600' }
config.public_file_server.headers = {
"Cache-Control" => "public, max-age=#{1.hour.to_i}"
}
# Show full error reports and disable caching.
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
# config.cache_store = :null_store
# Separate cache stores when running in parallel
config.cache_store = :redis_cache_store, {
@@ -20,25 +41,61 @@ Openfoodnetwork::Application.configure do
reconnect_attempts: 1
}
# Show full error reports and disable caching
config.consider_all_requests_local = true
config.action_controller.perform_caching = false
# Render exception templates for rescuable exceptions and raise for other exceptions.
config.action_dispatch.show_exceptions = :rescuable
# Raise exceptions instead of rendering exception templates
config.action_dispatch.show_exceptions = false
# Disable request forgery protection in test environment.
config.action_controller.allow_forgery_protection = false
# Disable request forgery protection in test environment
config.action_controller.allow_forgery_protection = false
# Store uploaded files on the local file system in a temporary directory.
# config.active_storage.service = :test
config.action_mailer.perform_caching = false
# Tell Action Mailer not to deliver emails to the real world.
# The :test delivery method accumulates sent emails in the
# ActionMailer::Base.deliveries array.
config.action_mailer.delivery_method = :test
# Tests should fail when translations are missing.
config.i18n.raise_on_missing_translations = true
# Print deprecation notices to the stderr.
# config.active_support.deprecation = :stderr
config.time_zone = ENV.fetch("TIMEZONE", "UTC")
# Raise exceptions for disallowed deprecations.
config.active_support.disallowed_deprecation = :raise
# Tell Active Support which deprecation messages to disallow.
config.active_support.disallowed_deprecation_warnings = []
# 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
# Raises error for missing translations.
config.i18n.raise_on_missing_translations = true
# Tests assume English text on the site.
config.i18n.default_locale = "en"
@@ -46,13 +103,11 @@ Openfoodnetwork::Application.configure do
config.i18n.fallbacks = [:en]
I18n.locale = config.i18n.locale = config.i18n.default_locale
# Use SQL instead of Active Record's schema dumper when creating the test database.
# This is necessary if your schema can't be completely dumped by the schema dumper,
# like if you have constraints or database-specific column types
# config.active_record.schema_format = :sql
# Annotate rendered view with file names.
# config.action_view.annotate_rendered_view_with_filenames = true
# Print deprecation notices to the stderr
# config.active_support.deprecation = :stderr
# Raise error when a before_action's only/except options reference missing actions
# config.action_controller.raise_on_missing_callback_actions = true
config.active_job.queue_adapter = :test
end

View File

@@ -1 +1,24 @@
# Be sure to restart your server when you modify this file.
# Version of your assets, change this if you want to expire all your assets.
Rails.application.config.assets.version = "1.2"
# Add additional assets to the asset load path.
Rails.application.config.assets.paths << Rails.root.join('node_modules')
# Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in the app/assets
# folder are already added.
# Rails.application.config.assets.precompile += %w( admin.js admin.css )
# css and js files other than application.* are not precompiled by default
# Instead, they must be explicitly included below
# http://stackoverflow.com/questions/8012434/what-is-the-purpose-of-config-assets-precompile
Rails.application.config.assets.precompile += [
'admin/*.js', 'admin/**/*.js', 'admin_minimal.js',
'web/all.js',
'darkswarm/all.js',
'shared/*',
'mail.scss',
'*.jpg', '*.jpeg', '*.png', '*.gif' '*.svg',
]

View File

@@ -1,8 +1,8 @@
# Be sure to restart your server when you modify this file.
# Define an application-wide content security policy
# For further information see the following documentation
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy
# Define an application-wide content security policy.
# See the Securing Rails Applications Guide for more information:
# https://guides.rubyonrails.org/security.html#content-security-policy-header
Rails.application.config.content_security_policy do |policy|
policy.default_src :self, :https
@@ -23,15 +23,11 @@ Rails.application.config.content_security_policy do |policy|
# Specify URI for violation reports
# policy.report_uri "/csp-violation-report-endpoint"
# Generate session nonces for permitted importmap, inline scripts, and inline styles.
# config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s }
# config.content_security_policy_nonce_directives = %w(script-src style-src)
# Report violations without enforcing the policy.
# config.content_security_policy_report_only = true
end
# If you are using UJS then enable automatic nonce generation
# Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) }
# Set the nonce only to specific directives
# Rails.application.config.content_security_policy_nonce_directives = %w(script-src)
# Report CSP violations to a specified URI
# For further information see the following documentation:
# https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only
# Rails.application.config.content_security_policy_report_only = true

View File

@@ -1,4 +1,12 @@
# frozen_string_literal: true
# Configure sensitive parameters which will be filtered from the log file.
Rails.application.config.filter_parameters += [:password, :vine_api_key, :vine_secret]
# Be sure to restart your server when you modify this file.
# Configure parameters to be partially matched (e.g. passw matches password) and filtered from the log file.
# Use this to limit dissemination of sensitive information.
# See the ActiveSupport::ParameterFilter documentation for supported notations and behaviors.
Rails.application.config.filter_parameters += [
:passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn,
:number, :verification_value,
:vine_api_key, :vine_secret,
]

View File

@@ -1,13 +1,20 @@
# Be sure to restart your server when you modify this file.
# Add new inflection rules using the following format
# (all these examples are active by default):
# ActiveSupport::Inflector.inflections do |inflect|
# inflect.plural /^(ox)$/i, '\1en'
# inflect.singular /^(ox)en/i, '\1'
# inflect.irregular 'person', 'people'
# Add new inflection rules using the following format. Inflections
# are locale specific, and you may define rules for as many different
# locales as you wish. All of these examples are active by default:
# ActiveSupport::Inflector.inflections(:en) do |inflect|
# inflect.plural /^(ox)$/i, "\\1en"
# inflect.singular /^(ox)en/i, "\\1"
# inflect.irregular "person", "people"
# inflect.uncountable %w( fish sheep )
# end
# These inflection rules are supported but not enabled by default:
# ActiveSupport::Inflector.inflections(:en) do |inflect|
# inflect.acronym "RESTful"
# end
Rails.autoloaders.each do |autoloader|
autoloader.inflector.inflect(
"stripe_sca" => "StripeSCA"

View File

@@ -0,0 +1,143 @@
# Be sure to restart your server when you modify this file.
#
# This file eases your Rails 7.0 framework defaults upgrade.
#
# Uncomment each configuration one by one to switch to the new default.
# Once your application is ready to run with all new defaults, you can remove
# this file and set the `config.load_defaults` to `7.0`.
#
# Read the Guide for Upgrading Ruby on Rails for more info on each option.
# https://guides.rubyonrails.org/upgrading_ruby_on_rails.html
# `button_to` view helper will render `<button>` element, regardless of whether
# or not the content is passed as the first argument or as a block.
# Rails.application.config.action_view.button_to_generates_button_tag = true
# `stylesheet_link_tag` view helper will not render the media attribute by default.
# Rails.application.config.action_view.apply_stylesheet_media_default = false
# Change the digest class for the key generators to `OpenSSL::Digest::SHA256`.
# Changing this default means invalidate all encrypted messages generated by
# your application and, all the encrypted cookies. Only change this after you
# rotated all the messages using the key rotator.
#
# See upgrading guide for more information on how to build a rotator.
# https://guides.rubyonrails.org/v7.0/upgrading_ruby_on_rails.html
# Rails.application.config.active_support.key_generator_hash_digest_class = OpenSSL::Digest::SHA256
# Change the digest class for ActiveSupport::Digest.
# Changing this default means that for example Etags change and
# various cache keys leading to cache invalidation.
# Rails.application.config.active_support.hash_digest_class = OpenSSL::Digest::SHA256
# Don't override ActiveSupport::TimeWithZone.name and use the default Ruby
# implementation.
# Rails.application.config.active_support.remove_deprecated_time_with_zone_name = true
# Calls `Rails.application.executor.wrap` around test cases.
# This makes test cases behave closer to an actual request or job.
# Several features that are normally disabled in test, such as Active Record query cache
# and asynchronous queries will then be enabled.
# Rails.application.config.active_support.executor_around_test_case = true
# Set both the `:open_timeout` and `:read_timeout` values for `:smtp` delivery method.
# Rails.application.config.action_mailer.smtp_timeout = 5
# The ActiveStorage video previewer will now use scene change detection to generate
# better preview images (rather than the previous default of using the first frame
# of the video).
# Rails.application.config.active_storage.video_preview_arguments =
# "-vf 'select=eq(n\\,0)+eq(key\\,1)+gt(scene\\,0.015),loop=loop=-1:size=2,trim=start_frame=1' -frames:v 1 -f image2"
# Automatically infer `inverse_of` for associations with a scope.
# Rails.application.config.active_record.automatic_scope_inversing = true
# Raise when running tests if fixtures contained foreign key violations
# Rails.application.config.active_record.verify_foreign_keys_for_fixtures = true
# Disable partial inserts.
# This default means that all columns will be referenced in INSERT queries
# regardless of whether they have a default or not.
# Rails.application.config.active_record.partial_inserts = false
# Protect from open redirect attacks in `redirect_back_or_to` and `redirect_to`.
# Rails.application.config.action_controller.raise_on_open_redirects = true
# Change the variant processor for Active Storage.
# Changing this default means updating all places in your code that
# generate variants to use image processing macros and ruby-vips
# operations. See the upgrading guide for detail on the changes required.
# The `:mini_magick` option is not deprecated; it's fine to keep using it.
# Rails.application.config.active_storage.variant_processor = :vips
# Enable parameter wrapping for JSON.
# Previously this was set in an initializer. It's fine to keep using that initializer if you've customized it.
# To disable parameter wrapping entirely, set this config to `false`.
# Rails.application.config.action_controller.wrap_parameters_by_default = true
# Specifies whether generated namespaced UUIDs follow the RFC 4122 standard for namespace IDs provided as a
# `String` to `Digest::UUID.uuid_v3` or `Digest::UUID.uuid_v5` method calls.
#
# See https://guides.rubyonrails.org/configuring.html#config-active-support-use-rfc4122-namespaced-uuids for
# more information.
# Rails.application.config.active_support.use_rfc4122_namespaced_uuids = true
# Change the default headers to disable browsers' flawed legacy XSS protection.
# Rails.application.config.action_dispatch.default_headers = {
# "X-Frame-Options" => "SAMEORIGIN",
# "X-XSS-Protection" => "0",
# "X-Content-Type-Options" => "nosniff",
# "X-Download-Options" => "noopen",
# "X-Permitted-Cross-Domain-Policies" => "none",
# "Referrer-Policy" => "strict-origin-when-cross-origin"
# }
# ** Please read carefully, this must be configured in config/application.rb **
# Change the format of the cache entry.
# Changing this default means that all new cache entries added to the cache
# will have a different format that is not supported by Rails 6.1 applications.
# Only change this value after your application is fully deployed to Rails 7.0
# and you have no plans to rollback.
# When you're ready to change format, add this to `config/application.rb` (NOT this file):
# config.active_support.cache_format_version = 7.0
# Cookie serializer: 2 options
#
# If you're upgrading and haven't set `cookies_serializer` previously, your cookie serializer
# is `:marshal`. The default for new apps is `:json`.
#
# Rails.application.config.action_dispatch.cookies_serializer = :json
#
#
# To migrate an existing application to the `:json` serializer, use the `:hybrid` option.
#
# Rails transparently deserializes existing (Marshal-serialized) cookies on read and
# re-writes them in the JSON format.
#
# It is fine to use `:hybrid` long term; you should do that until you're confident *all* your cookies
# have been converted to JSON. To keep using `:hybrid` long term, move this config to its own
# initializer or to `config/application.rb`.
#
# Rails.application.config.action_dispatch.cookies_serializer = :hybrid
#
#
# If your cookies can't yet be serialized to JSON, keep using `:marshal` for backward-compatibility.
#
# If you have configured the serializer elsewhere, you can remove this section of the file.
#
# See https://guides.rubyonrails.org/action_controller_overview.html#cookies for more information.
# Change the return value of `ActionDispatch::Request#content_type` to the Content-Type header without modification.
# Rails.application.config.action_dispatch.return_only_request_media_type_on_content_type = false
# Active Storage `has_many_attached` relationships will default to replacing the current collection instead of appending to it.
# Thus, to support submitting an empty collection, the `file_field` helper will render an hidden field `include_hidden` by default when `multiple_file_field_include_hidden` is set to `true`.
# See https://guides.rubyonrails.org/configuring.html#config-active-storage-multiple-file-field-include-hidden for more information.
# Rails.application.config.active_storage.multiple_file_field_include_hidden = true
# ** Please read carefully, this must be configured in config/application.rb (NOT this file) **
# Disables the deprecated #to_s override in some Ruby core classes
# See https://guides.rubyonrails.org/configuring.html#config-active-support-disable-to-s-conversion for more information.
# config.active_support.disable_to_s_conversion = true

View File

@@ -0,0 +1,280 @@
# Be sure to restart your server when you modify this file.
#
# This file eases your Rails 7.1 framework defaults upgrade.
#
# Uncomment each configuration one by one to switch to the new default.
# Once your application is ready to run with all new defaults, you can remove
# this file and set the `config.load_defaults` to `7.1`.
#
# Read the Guide for Upgrading Ruby on Rails for more info on each option.
# https://guides.rubyonrails.org/upgrading_ruby_on_rails.html
###
# No longer add autoloaded paths into `$LOAD_PATH`. This means that you won't be able
# to manually require files that are managed by the autoloader, which you shouldn't do anyway.
#
# This will reduce the size of the load path, making `require` faster if you don't use bootsnap, or reduce the size
# of the bootsnap cache if you use it.
#
# To set this configuration, add the following line to `config/application.rb` (NOT this file):
# config.add_autoload_paths_to_load_path = false
###
# Remove the default X-Download-Options headers since it is used only by Internet Explorer.
# If you need to support Internet Explorer, add back `"X-Download-Options" => "noopen"`.
#++
# Rails.application.config.action_dispatch.default_headers = {
# "X-Frame-Options" => "SAMEORIGIN",
# "X-XSS-Protection" => "0",
# "X-Content-Type-Options" => "nosniff",
# "X-Permitted-Cross-Domain-Policies" => "none",
# "Referrer-Policy" => "strict-origin-when-cross-origin"
# }
###
# Do not treat an `ActionController::Parameters` instance
# as equal to an equivalent `Hash` by default.
#++
# Rails.application.config.action_controller.allow_deprecated_parameters_hash_equality = false
###
# Active Record Encryption now uses SHA-256 as its hash digest algorithm.
#
# There are 3 scenarios to consider.
#
# 1. If you have data encrypted with previous Rails versions, and you have
# +config.active_support.key_generator_hash_digest_class+ configured as SHA1 (the default
# before Rails 7.0), you need to configure SHA-1 for Active Record Encryption too:
#++
# Rails.application.config.active_record.encryption.hash_digest_class = OpenSSL::Digest::SHA1
#
# 2. If you have +config.active_support.key_generator_hash_digest_class+ configured as SHA256 (the new default
# in 7.0), then you need to configure SHA-256 for Active Record Encryption:
#++
# Rails.application.config.active_record.encryption.hash_digest_class = OpenSSL::Digest::SHA256
#
# 3. If you don't currently have data encrypted with Active Record encryption, you can disable this setting to
# configure the default behavior starting 7.1+:
#++
# Rails.application.config.active_record.encryption.support_sha1_for_non_deterministic_encryption = false
###
# No longer run after_commit callbacks on the first of multiple Active Record
# instances to save changes to the same database row within a transaction.
# Instead, run these callbacks on the instance most likely to have internal
# state which matches what was committed to the database, typically the last
# instance to save.
#++
# Rails.application.config.active_record.run_commit_callbacks_on_first_saved_instances_in_transaction = false
###
# Configures SQLite with a strict strings mode, which disables double-quoted string literals.
#
# SQLite has some quirks around double-quoted string literals.
# It first tries to consider double-quoted strings as identifier names, but if they don't exist
# it then considers them as string literals. Because of this, typos can silently go unnoticed.
# For example, it is possible to create an index for a non existing column.
# See https://www.sqlite.org/quirks.html#double_quoted_string_literals_are_accepted for more details.
#++
# Rails.application.config.active_record.sqlite3_adapter_strict_strings_by_default = true
###
# Disable deprecated singular associations names.
#++
# Rails.application.config.active_record.allow_deprecated_singular_associations_name = false
###
# Enable the Active Job `BigDecimal` argument serializer, which guarantees
# roundtripping. Without this serializer, some queue adapters may serialize
# `BigDecimal` arguments as simple (non-roundtrippable) strings.
#
# When deploying an application with multiple replicas, old (pre-Rails 7.1)
# replicas will not be able to deserialize `BigDecimal` arguments from this
# serializer. Therefore, this setting should only be enabled after all replicas
# have been successfully upgraded to Rails 7.1.
#++
# Rails.application.config.active_job.use_big_decimal_serializer = true
###
# Specify if an `ArgumentError` should be raised if `Rails.cache` `fetch` or
# `write` are given an invalid `expires_at` or `expires_in` time.
# Options are `true`, and `false`. If `false`, the exception will be reported
# as `handled` and logged instead.
#++
# Rails.application.config.active_support.raise_on_invalid_cache_expiration_time = true
###
# Specify whether Query Logs will format tags using the SQLCommenter format
# (https://open-telemetry.github.io/opentelemetry-sqlcommenter/), or using the legacy format.
# Options are `:legacy` and `:sqlcommenter`.
#++
# Rails.application.config.active_record.query_log_tags_format = :sqlcommenter
###
# Specify the default serializer used by `MessageEncryptor` and `MessageVerifier`
# instances.
#
# The legacy default is `:marshal`, which is a potential vector for
# deserialization attacks in cases where a message signing secret has been
# leaked.
#
# In Rails 7.1, the new default is `:json_allow_marshal` which serializes and
# deserializes with `ActiveSupport::JSON`, but can fall back to deserializing
# with `Marshal` so that legacy messages can still be read.
#
# In Rails 7.2, the default will become `:json` which serializes and
# deserializes with `ActiveSupport::JSON` only.
#
# Alternatively, you can choose `:message_pack` or `:message_pack_allow_marshal`,
# which serialize with `ActiveSupport::MessagePack`. `ActiveSupport::MessagePack`
# can roundtrip some Ruby types that are not supported by JSON, and may provide
# improved performance, but it requires the `msgpack` gem.
#
# For more information, see
# https://guides.rubyonrails.org/v7.1/configuring.html#config-active-support-message-serializer
#
# If you are performing a rolling deploy of a Rails 7.1 upgrade, wherein servers
# that have not yet been upgraded must be able to read messages from upgraded
# servers, first deploy without changing the serializer, then set the serializer
# in a subsequent deploy.
#++
# Rails.application.config.active_support.message_serializer = :json_allow_marshal
###
# Enable a performance optimization that serializes message data and metadata
# together. This changes the message format, so messages serialized this way
# cannot be read by older versions of Rails. However, messages that use the old
# format can still be read, regardless of whether this optimization is enabled.
#
# To perform a rolling deploy of a Rails 7.1 upgrade, wherein servers that have
# not yet been upgraded must be able to read messages from upgraded servers,
# leave this optimization off on the first deploy, then enable it on a
# subsequent deploy.
#++
# Rails.application.config.active_support.use_message_serializer_for_metadata = true
###
# Set the maximum size for Rails log files.
#
# `config.load_defaults 7.1` does not set this value for environments other than
# development and test.
#++
# if Rails.env.local?
# Rails.application.config.log_file_size = 100 * 1024 * 1024
# end
###
# Enable raising on assignment to attr_readonly attributes. The previous
# behavior would allow assignment but silently not persist changes to the
# database.
#++
# Rails.application.config.active_record.raise_on_assign_to_attr_readonly = true
###
# Enable validating only parent-related columns for presence when the parent is mandatory.
# The previous behavior was to validate the presence of the parent record, which performed an extra query
# to get the parent every time the child record was updated, even when parent has not changed.
#++
# Rails.application.config.active_record.belongs_to_required_validates_foreign_key = false
###
# Enable precompilation of `config.filter_parameters`. Precompilation can
# improve filtering performance, depending on the quantity and types of filters.
#++
# Rails.application.config.precompile_filter_parameters = true
###
# Enable before_committed! callbacks on all enrolled records in a transaction.
# The previous behavior was to only run the callbacks on the first copy of a record
# if there were multiple copies of the same record enrolled in the transaction.
#++
# Rails.application.config.active_record.before_committed_on_all_records = true
###
# Disable automatic column serialization into YAML.
# To keep the historic behavior, you can set it to `YAML`, however it is
# recommended to explicitly define the serialization method for each column
# rather than to rely on a global default.
#++
# Rails.application.config.active_record.default_column_serializer = nil
###
# Enable a performance optimization that serializes Active Record models
# in a faster and more compact way.
#
# To perform a rolling deploy of a Rails 7.1 upgrade, wherein servers that have
# not yet been upgraded must be able to read caches from upgraded servers,
# leave this optimization off on the first deploy, then enable it on a
# subsequent deploy.
#++
# Rails.application.config.active_record.marshalling_format_version = 7.1
###
# Run `after_commit` and `after_*_commit` callbacks in the order they are defined in a model.
# This matches the behaviour of all other callbacks.
# In previous versions of Rails, they ran in the inverse order.
#++
# Rails.application.config.active_record.run_after_transaction_callbacks_in_order_defined = true
###
# Whether a `transaction` block is committed or rolled back when exited via `return`, `break` or `throw`.
#++
# Rails.application.config.active_record.commit_transaction_on_non_local_return = true
###
# Controls when to generate a value for <tt>has_secure_token</tt> declarations.
#++
# Rails.application.config.active_record.generate_secure_token_on = :initialize
###
# ** Please read carefully, this must be configured in config/application.rb **
#
# Change the format of the cache entry.
#
# Changing this default means that all new cache entries added to the cache
# will have a different format that is not supported by Rails 7.0
# applications.
#
# Only change this value after your application is fully deployed to Rails 7.1
# and you have no plans to rollback.
# When you're ready to change format, add this to `config/application.rb` (NOT
# this file):
# config.active_support.cache_format_version = 7.1
###
# Configure Action View to use HTML5 standards-compliant sanitizers when they are supported on your
# platform.
#
# `Rails::HTML::Sanitizer.best_supported_vendor` will cause Action View to use HTML5-compliant
# sanitizers if they are supported, else fall back to HTML4 sanitizers.
#
# In previous versions of Rails, Action View always used `Rails::HTML4::Sanitizer` as its vendor.
#++
# Rails.application.config.action_view.sanitizer_vendor = Rails::HTML::Sanitizer.best_supported_vendor
###
# Configure Action Text to use an HTML5 standards-compliant sanitizer when it is supported on your
# platform.
#
# `Rails::HTML::Sanitizer.best_supported_vendor` will cause Action Text to use HTML5-compliant
# sanitizers if they are supported, else fall back to HTML4 sanitizers.
#
# In previous versions of Rails, Action Text always used `Rails::HTML4::Sanitizer` as its vendor.
#++
# Rails.application.config.action_text.sanitizer_vendor = Rails::HTML::Sanitizer.best_supported_vendor
###
# Configure the log level used by the DebugExceptions middleware when logging
# uncaught exceptions during requests.
#++
# Rails.application.config.action_dispatch.debug_exception_log_level = :error
###
# Configure the test helpers in Action View, Action Dispatch, and rails-dom-testing to use HTML5
# parsers.
#
# Nokogiri::HTML5 isn't supported on JRuby, so JRuby applications must set this to :html4.
#
# In previous versions of Rails, these test helpers always used an HTML4 parser.
#++
# Rails.application.config.dom_testing_default_html_version = :html5

View File

@@ -0,0 +1,13 @@
# Be sure to restart your server when you modify this file.
# Define an application-wide HTTP permissions policy. For further
# information see: https://developers.google.com/web/updates/2018/06/feature-policy
# Rails.application.config.permissions_policy do |policy|
# policy.camera :none
# policy.gyroscope :none
# policy.microphone :none
# policy.usb :none
# policy.fullscreen :self
# policy.payment :self, "https://secure.example.com"
# end

View File

@@ -1446,6 +1446,8 @@ cy:
visible: Gweladwy?
owner: Perchennog
producer: Cynhyrchydd
sells_options:
none: dim
change_type_form:
producer_profile: Proffil Cynhyrchydd
connect_ofn: Cysylltu trwy'r Open Food Network

View File

@@ -1518,6 +1518,11 @@ en:
visible: Visible?
owner: Owner
producer: Producer
sells_options:
unspecified: unspecified
none: none
own: own
any: any
change_type_form:
producer_profile: Producer Profile
connect_ofn: Connect through OFN

View File

@@ -1447,6 +1447,8 @@ en_CA:
visible: Visible?
owner: Owner
producer: Producer
sells_options:
none: none
change_type_form:
producer_profile: Producer Profile
connect_ofn: Connect through OFN
@@ -3618,7 +3620,7 @@ en_CA:
removed_terms_and_conditions_successfully: "Terms and Conditions file removed successfully"
insufficient_stock: "Insufficient stock available, only %{on_hand} remaining"
out_of_stock:
reduced_stock_available: Reduced stock available
reduced_stock_available: 'Reduced stock '
out_of_stock_text: >
While you've been shopping, the stock levels for one or more of the products
in your cart have reduced. Here's what's changed:

View File

@@ -1447,6 +1447,8 @@ en_FR:
visible: Visible?
owner: Owner
producer: Producer
sells_options:
none: none
change_type_form:
producer_profile: Producer Profile
connect_ofn: Connect through OFN

View File

@@ -1447,6 +1447,8 @@ en_GB:
visible: Visible?
owner: Owner
producer: Producer
sells_options:
none: none
change_type_form:
producer_profile: Producer Profile
connect_ofn: Connect through OFN

View File

@@ -1445,6 +1445,8 @@ fi:
visible: Näkyvissä?
owner: Omistaja
producer: Tuottaja
sells_options:
none: ei yhtään
change_type_form:
producer_profile: Tuottajan profiili
connect_ofn: Yhdistä OFN:n kautta

View File

@@ -1449,6 +1449,8 @@ fr:
visible: Visible?
owner: Gestionnaire principal
producer: Producteur
sells_options:
none: aucun
change_type_form:
producer_profile: Profil simple
connect_ofn: Pour apparaître sur la carte et la liste des producteurs

View File

@@ -1451,6 +1451,8 @@ fr_CA:
visible: Visible?
owner: Gérant
producer: Producteur
sells_options:
none: aucun
change_type_form:
producer_profile: Profil producteur
connect_ofn: Gagnez en visibilité via OFN

View File

@@ -1383,6 +1383,8 @@ hu:
visible: Látható?
owner: Tulajdonos
producer: Termelő
sells_options:
none: n.a.
change_type_form:
producer_profile: Termelői Profil
connect_ofn: Csatlakozás OFN-en keresztül

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

@@ -30,8 +30,7 @@ module DfcProvider
# - Spree::Shipment
# - Subscription
def authorized(address)
current_user.ship_address_id == address.id ||
current_user.bill_address_id == address.id ||
user_address(address) ||
[
customer_address(address),
public_enterprise_group_address(address),
@@ -40,6 +39,13 @@ module DfcProvider
].any?(&:exists?)
end
def user_address(address)
return false if current_user.is_a? ApiUser
current_user.ship_address_id == address.id ||
current_user.bill_address_id == address.id
end
def customer_address(address)
current_user.customers.where(bill_address: address).or(
current_user.customers.where(ship_address: address)

View File

@@ -3,12 +3,15 @@
# Controller used to provide the API products for the DFC application
module DfcProvider
class ApplicationController < ActionController::Base
class Unauthorized < StandardError; end
include ActiveStorage::SetCurrent
protect_from_forgery with: :null_session
rescue_from ActiveRecord::RecordNotFound, with: :not_found
rescue_from CanCan::AccessDenied, with: :unauthorized
rescue_from Unauthorized, with: :unauthorized
before_action :check_authorization
@@ -16,6 +19,13 @@ module DfcProvider
private
def require_permission(scope)
return if current_user.is_a? Spree::User
return if current_user.permissions(scope).where(enterprise: current_enterprise).exists?
raise Unauthorized
end
def check_authorization
unauthorized if current_user.nil?
end
@@ -63,5 +73,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,14 @@ module DfcProvider
before_action :check_enterprise
def index
person = PersonBuilder.person(current_user)
require_permission "ReadProducts"
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

@@ -0,0 +1,36 @@
# frozen_string_literal: true
# Authorised user or client using the API
class ApiUser
CLIENT_MAP = {
"https://waterlooregionfood.ca/portal/profile" => "cqcm-dev",
}.freeze
def self.from_client_id(client_id)
id = CLIENT_MAP[client_id]
new(id) if id
end
attr_reader :id
def initialize(id)
@id = id
end
def admin?
false
end
def customers
Customer.none
end
def enterprises
Enterprise.where(dfc_permissions: permissions("ReadEnterprise"))
end
def permissions(scope)
DfcPermission.where(grantee: id, scope:)
end
end

View File

@@ -1,17 +1,29 @@
# frozen_string_literal: true
# Service used to authorize the user on DCF Provider API
# Authorize the user on the DFC API
#
# It controls an OICD Access token and an enterprise.
class AuthorizationControl
# Copied from: https://login.lescommuns.org/auth/realms/data-food-consortium/
LES_COMMUNES_PUBLIC_KEY = <<~KEY
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl68JGqAILFzoi/1+6siXXp2vylu+7mPjYKjKelTtHFYXWVkbmVptCsamHlY3jRhqSQYe6M1SKfw8D+uXrrWsWficYvpdlV44Vm7uETZOr1/XBOjpWOi1vLmBVtX6jFeqN1BxfE1PxLROAiGn+MeMg90AJKShD2c5RoNv26e20dgPhshRVFPUGru+0T1RoKyIa64z/qcTcTVD2V7KX+ANMweRODdoPAzQFGGjTnL1uUqIdUwSfHSpXYnKxXOsnPC3Mowkv8UIGWWDxS/yzhWc7sOk1NmC7pb+Cg7G8NKj+Pp9qQZnXF39Dg95ZsxJrl6fyPFvTo3zf9CPG/fUM1CkkwIDAQAB
-----END PUBLIC KEY-----
KEY
PUBLIC_KEYS = {
# Copied from: https://login.lescommuns.org/auth/realms/data-food-consortium/
"https://login.lescommuns.org/auth/realms/data-food-consortium" => <<~KEY,
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl68JGqAILFzoi/1+6siXXp2vylu+7mPjYKjKelTtHFYXWVkbmVptCsamHlY3jRhqSQYe6M1SKfw8D+uXrrWsWficYvpdlV44Vm7uETZOr1/XBOjpWOi1vLmBVtX6jFeqN1BxfE1PxLROAiGn+MeMg90AJKShD2c5RoNv26e20dgPhshRVFPUGru+0T1RoKyIa64z/qcTcTVD2V7KX+ANMweRODdoPAzQFGGjTnL1uUqIdUwSfHSpXYnKxXOsnPC3Mowkv8UIGWWDxS/yzhWc7sOk1NmC7pb+Cg7G8NKj+Pp9qQZnXF39Dg95ZsxJrl6fyPFvTo3zf9CPG/fUM1CkkwIDAQAB
-----END PUBLIC KEY-----
KEY
def self.public_key
OpenSSL::PKey::RSA.new(LES_COMMUNES_PUBLIC_KEY)
# Copied from: https://kc.cqcm.startinblox.com/realms/startinblox
"https://kc.cqcm.startinblox.com/realms/startinblox" => <<~KEY,
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqtvdb3BdHoLnNeMLaWd7nugPwdRAJJpdSySTtttEQY2/v1Q3byJ/kReSNGrUNkPVkOeDN3milgN5Apz+sNCwbtzOCulyFMmvuIOZFBqz5tcgwjZinSwpGBXpn6ehXyCET2LlcfLYAPA9axtaNg9wBLIHoxIPWpa2LcZstogyZY/yKUZXQTDqM5B5TyUkPN89xHFdq8SQuXPasbpYl7mGhZHkTDHiKZ9VK7K5tqsEZTD9dCuTGMKsthbOrlDnc9bAJ3PyKLRdib21Y1GGlTozo4Y/1q448E/DFp5rVC6jG6JFnsEnP0WVn+6qz7yxI7IfUU2YSAGgtGYaQkWtEfED0QIDAQAB
-----END PUBLIC KEY-----
KEY
}.freeze
def self.public_key(token)
unverified_payload = JWT.decode(token, nil, false, { algorithm: "RS256" }).first
key = PUBLIC_KEYS[unverified_payload["iss"]]
OpenSSL::PKey::RSA.new(key)
end
def initialize(request)
@@ -27,7 +39,11 @@ class AuthorizationControl
private
def oidc_user
find_ofn_user(decode_token) if access_token
return unless access_token
payload = decode_token
find_ofn_user(payload) || client_user(payload)
end
def ofn_api_user
@@ -41,7 +57,7 @@ class AuthorizationControl
def decode_token
JWT.decode(
access_token,
self.class.public_key,
self.class.public_key(access_token),
true, { algorithm: "RS256" }
).first
end
@@ -59,4 +75,8 @@ class AuthorizationControl
OidcAccount.find_by(uid: payload["email"])&.user
end
def client_user(payload)
ApiUser.from_client_id(payload["client_id"])
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

@@ -3,6 +3,7 @@
require_relative "../swagger_helper"
RSpec.describe "CatalogItems", swagger_doc: "dfc.yaml" do
let(:Authorization) { nil }
let(:user) { create(:oidc_user, id: 12_345) }
let(:enterprise) {
create(
@@ -35,8 +36,15 @@ RSpec.describe "CatalogItems", swagger_doc: "dfc.yaml" do
get "List CatalogItems" do
produces "application/json"
security [oidc_token: []]
response "404", "not found" do
context "as platform user" do
include_context "authenticated as platform"
let(:enterprise_id) { 10_000 }
run_test!
end
context "without enterprises" do
let(:enterprise_id) { "default" }
@@ -53,6 +61,25 @@ RSpec.describe "CatalogItems", swagger_doc: "dfc.yaml" do
response "200", "success" do
before { product }
context "as platform user" do
include_context "authenticated as platform"
let(:enterprise_id) { 10_000 }
before {
DfcPermission.create!(
user:, enterprise_id:,
scope: "ReadEnterprise", grantee: "cqcm-dev",
)
DfcPermission.create!(
user:, enterprise_id:,
scope: "ReadProducts", grantee: "cqcm-dev",
)
}
run_test!
end
context "with default enterprise id" do
let(:enterprise_id) { "default" }
@@ -75,11 +102,31 @@ RSpec.describe "CatalogItems", swagger_doc: "dfc.yaml" do
end
response "401", "unauthorized" do
let(:enterprise_id) { "default" }
context "as platform user" do
include_context "authenticated as platform"
before { login_as nil }
let(:enterprise_id) { 10_000 }
run_test!
before {
product
DfcPermission.create!(
user:, enterprise_id:,
scope: "ReadEnterprise", grantee: "cqcm-dev",
)
# But no ReadProducts permission.
}
run_test!
end
context "without authorisation" do
let(:enterprise_id) { "default" }
before { login_as nil }
run_test!
end
end
end
end

View File

@@ -3,6 +3,7 @@
require_relative "../swagger_helper"
RSpec.describe "Enterprises", swagger_doc: "dfc.yaml" do
let(:Authorization) { nil }
let!(:user) { create(:oidc_user) }
let!(:enterprise) do
create(
@@ -51,6 +52,21 @@ RSpec.describe "Enterprises", swagger_doc: "dfc.yaml" do
produces "application/json"
response "200", "successful" do
context "as platform user" do
include_context "authenticated as platform"
let(:id) { 10_000 }
before {
DfcPermission.create!(
user:, enterprise_id: id,
scope: "ReadEnterprise", grantee: "cqcm-dev",
)
}
run_test!
end
context "without enterprise id" do
let(:id) { "default" }

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

@@ -13,6 +13,7 @@ RSpec.describe "ProductGroups", swagger_doc: "dfc.yaml" do
variants: [variant]
)
}
let(:Authorization) { nil }
let(:variant) {
build(:base_variant, id: 10_001, unit_value: 1, primary_taxon: taxon, supplier: enterprise)
}
@@ -34,10 +35,28 @@ RSpec.describe "ProductGroups", swagger_doc: "dfc.yaml" do
get "Show ProductGroup" do
produces "application/json"
security [oidc_token: []]
response "200", "success" do
let(:id) { product.id }
context "as platform user" do
include_context "authenticated as platform"
before {
DfcPermission.create!(
user:, enterprise_id:,
scope: "ReadEnterprise", grantee: "cqcm-dev",
)
DfcPermission.create!(
user:, enterprise_id:,
scope: "ReadProducts", grantee: "cqcm-dev",
)
}
run_test!
end
run_test! do
expect(json_response["@id"]).to eq "http://test.host/api/dfc/product_groups/90000"

View File

@@ -11,11 +11,11 @@ RSpec.describe AffiliateSalesQuery do
let(:yesterday) { Time.zone.yesterday }
let(:tomorrow) { Time.zone.tomorrow }
around do |example|
before do
# Query dates are interpreted as UTC while the spec runs in
# Melbourne time. At noon in Melbourne, the date is the same.
# That simplifies the spec.
Timecop.travel(Time.zone.today.noon, &example)
travel_to(Time.zone.today.noon)
end
it "returns data" do

View File

@@ -0,0 +1,13 @@
# frozen_string_literal: true
require_relative "../spec_helper"
RSpec.describe ApiUser do
subject(:user) { described_class.new("cqcm-dev") }
describe "#customers" do
it "returns nothing" do
expect(user.customers).to be_empty
end
end
end

View File

@@ -8,6 +8,23 @@ RSpec.describe AuthorizationControl do
let(:user) { create(:oidc_user) }
describe "with OIDC token" do
it "accepts a token from Les Communs" do
user.oidc_account.update!(uid: "testdfc@protonmail.com")
lc_token = file_fixture("les_communs_access_token.jwt").read
travel_to(Date.parse("2025-06-13")) do
expect(auth(oidc_token: lc_token).user).to eq user
end
end
it "accepts a token from Startin'Blox" do
sib_token = file_fixture("startinblox_access_token.jwt").read
travel_to(Date.parse("2025-06-13")) do
expect(auth(oidc_token: sib_token).user.id).to eq "cqcm-dev"
end
end
it "finds the right user" do
create(:oidc_user) # another user
token = allow_token_for(email: user.email)

View File

@@ -0,0 +1,16 @@
# frozen_string_literal: true
# Authenticate via Authoriztion token
RSpec.shared_context "authenticated as platform" do
let(:Authorization) {
"Bearer #{file_fixture('startinblox_access_token.jwt').read}"
}
before do
# Once upon a time when the access token hadn't expired yet...
travel_to(Date.parse("2025-06-13"))
# Reset any login via session cookie.
login_as nil
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

@@ -113,7 +113,9 @@ module OpenFoodNetwork
end
def managed_enterprises
@managed_enterprises ||= Enterprise.managed_by(@user)
return Enterprise.all if admin?
@user.enterprises
end
def coordinated_order_cycles

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

@@ -10,7 +10,7 @@
"pretty-quick": "pretty-quick"
},
"dependencies": {
"@floating-ui/dom": "^1.7.3",
"@floating-ui/dom": "^1.7.4",
"@hotwired/stimulus": "^3.2",
"@hotwired/turbo": "^8.0.13",
"@rails/webpacker": "5.4.4",

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.
@@ -260,6 +257,7 @@ RSpec.configure do |config|
config.include OpenFoodNetwork::FiltersHelper
config.include OpenFoodNetwork::EnterpriseGroupsHelper
config.include OpenFoodNetwork::HtmlHelper
config.include ActiveSupport::Testing::TimeHelpers
config.include ActionView::Helpers::DateHelper
config.include OpenFoodNetwork::PerformanceHelper
config.include ActiveJob::TestHelper

View File

@@ -142,7 +142,7 @@ RSpec.describe Admin::OrderCyclesController do
select: {
enterprise_fees: 3,
enterprise_groups: 1,
enterprises: 22,
enterprises: 19,
exchanges: 7,
order_cycles: 6,
proxy_orders: 1,

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

View File

@@ -0,0 +1 @@
eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJKVjg1bVRtUmh1MGtSeGNNb0FGUFl5azJMbS1WTExYV25HOG9HbUxNUkowIn0.eyJleHAiOjE3NDk3ODkyMzYsImlhdCI6MTc0OTc4NzQzNiwiYXV0aF90aW1lIjoxNzQ5Nzg3NDMzLCJqdGkiOiJmM2Q2ZGNmMi1lNGMwLTQyNzItODQzNC00NWFhZDczOTllYzUiLCJpc3MiOiJodHRwczovL2xvZ2luLmxlc2NvbW11bnMub3JnL2F1dGgvcmVhbG1zL2RhdGEtZm9vZC1jb25zb3J0aXVtIiwiYXVkIjoiYWNjb3VudCIsInN1YiI6IjVmZjNhZjc4LTk0YTItNGI1Yi04ZGFkLWE3YzFkZWE4ODE2YSIsInR5cCI6IkJlYXJlciIsImF6cCI6ImNvb3BjaXJjdWl0cyIsIm5vbmNlIjoiMTZkNmM3OGZkNTcwOWRkMjVkNzNkYzYwMmViNDBiZGYiLCJzZXNzaW9uX3N0YXRlIjoiYmE4Y2M0ZWYtMDJmMC00ZjVmLWFiMWEtMDUyNGRiNGViNzI5IiwiYWxsb3dlZC1vcmlnaW5zIjpbIiJdLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsib2ZmbGluZV9hY2Nlc3MiLCJ1bWFfYXV0aG9yaXphdGlvbiJdfSwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJzaWQiOiJiYThjYzRlZi0wMmYwLTRmNWYtYWIxYS0wNTI0ZGI0ZWI3MjkiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsIm5hbWUiOiJ0ZXN0IGRmYyIsInByZWZlcnJlZF91c2VybmFtZSI6InRlc3RkZmNAcHJvdG9ubWFpbC5jb20iLCJsb2NhbGUiOiJlbiIsImdpdmVuX25hbWUiOiJ0ZXN0IiwiZmFtaWx5X25hbWUiOiJkZmMiLCJlbWFpbCI6InRlc3RkZmNAcHJvdG9ubWFpbC5jb20ifQ.NTuzVgy8es0GHKqGPmHgVaV8Kzz9uuFAiWgixLubfh8fl2OccFDxccNKyiTczj4wHD4jItdHPIxz-x9ZX2Ao7lwMFLno69KWjAK2eLpA8Fnu4stftlswfHqD0W-wzG0Cx24H6jXZbsM5tm1FYgQYwrlZ-uqwQOabN_cA_cTrwHmMTNVCjwCisScq7Np7r1me-4YEABmTGR362_eJVn2bRppG_7s12yjEAH_mcTyALXqlXNaF0XihDCxjmK8ybJiGy6_QwhEJci6EWqJ-w9H6ckheq94xTM5WpanQ4-ZHEm2TZlq2MOfMBVsknhwnGI0b-GbtSJrs7urWsopQyWSuhw

View File

@@ -0,0 +1 @@
eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJRRlJES1daQ2hzMllQYnRqYl9yQUtwQzNzMFo0T2FCMEtFQ056NnlxWHQ0In0.eyJleHAiOjE3NDk3ODk3MDcsImlhdCI6MTc0OTc4OTQwNywianRpIjoiOWE4ODU4NDAtODhjNy00OTliLWIyOGUtMmE5ZmViM2EyNmU0IiwiaXNzIjoiaHR0cHM6Ly9rYy5jcWNtLnN0YXJ0aW5ibG94LmNvbS9yZWFsbXMvc3RhcnRpbmJsb3giLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiNWZlM2MyNmMtMjczNi00OGE0LWI2Y2YtYTllM2JjZmNkZjAwIiwidHlwIjoiQmVhcmVyIiwiYXpwIjoiaHR0cHM6Ly93YXRlcmxvb3JlZ2lvbmZvb2QuY2EvcG9ydGFsL3Byb2ZpbGUiLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsib2ZmbGluZV9hY2Nlc3MiLCJ1bWFfYXV0aG9yaXphdGlvbiIsImRlZmF1bHQtcm9sZXMtc3RhcnRpbmJsb3giXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6IlJlYWRFbnRlcnByaXNlIFJlYWRQcm9kdWN0cyIsImNsaWVudEhvc3QiOiIxNzIuMTguMC4xIiwiY2xpZW50QWRkcmVzcyI6IjE3Mi4xOC4wLjEiLCJjbGllbnRfaWQiOiJodHRwczovL3dhdGVybG9vcmVnaW9uZm9vZC5jYS9wb3J0YWwvcHJvZmlsZSJ9.Ln7wY0_ptRAza7M8w3yXU02TvluH028uaoJ5VHiN9-PnakokzHve7SCuSd1hvVikYAivWFIBRP97vwfpb_DW-d9Afk_XcQqcA0L36ynUIZ69X5uQ2zakEW0kB6pwqd8AL8tlWVUg2PixBXJ6daJcgWNF7RlKXg6wgy4JYL_VxD3VJjST911-z4_TMuQ2OC-3SJNwNv3BspSmUXm7F6y8xGFN7wuCPjU90WIiZ_vxTbVdM0zNtBM0uMJFeFv2_ZzoJIIiNHYLWtD3LrKcXePLSejpo-DPVWR_lGdDdM7BmzOHPKZ9KMaV-oa3lYNYC5shhJOpoB3vHngtdYdv8jq7Cg

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,22 @@ 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
describe '#enterprise_sells_options' do
it 'returns sells options with translations' do
expect(helper.enterprise_sells_options.map(&:first)).to eq %w[unspecified none own any]
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

@@ -8,8 +8,8 @@ RSpec.describe HeartbeatJob do
before { Spree::Config.last_job_queue_heartbeat_at = nil }
around do |example|
Timecop.freeze(run_time) { example.run }
before do
travel_to(run_time)
end
it "updates the last_job_queue_heartbeat_at config var" do

View File

@@ -7,8 +7,8 @@ RSpec.describe OpenOrderCycleJob do
let(:order_cycle) { create(:simple_order_cycle, orders_open_at: now) }
subject { OpenOrderCycleJob.perform_now(order_cycle.id) }
around do |example|
Timecop.freeze(now) { example.run }
before do
freeze_time
end
it "marks as open" do

View File

@@ -23,7 +23,7 @@ RSpec.describe WebhookDeliveryJob do
end
it "delivers a payload" do
Timecop.freeze do
freeze_time do
expected_body = {
id: /.+/,
at: at.to_s,

View File

@@ -80,7 +80,7 @@ require "spec_helper"
# end
# it "generates filename correctly" do
# Timecop.freeze(Time.zone.local(2018, 10, 9, 7, 30, 0)) do
# travel_to(Time.zone.local(2018, 10, 9, 7, 30, 0)) do
# filename = renderer.__send__(:filename)
# expect(filename).to eq("enterprise_fee_summary_20181009.csv")
# end

View File

@@ -13,7 +13,7 @@ module Reporting
describe "option defaults" do
let(:report) { Base.new user }
around { |example| Timecop.travel(Time.zone.local(2015, 5, 5, 14, 0, 0)) { example.run } }
before { travel_to(Time.zone.local(2015, 5, 5, 14, 0, 0)) }
it "uses defaults when blank params are passed" do
expect(report.params).to eq(invoice_date: Date.civil(2015, 5, 5),

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

@@ -149,6 +149,6 @@ RSpec.describe Enterprise do
end
def later(&)
Timecop.travel(1.day.from_now, &)
travel(1.day, &)
end
end

View File

@@ -304,7 +304,7 @@ RSpec.describe OrderCycle do
let(:oc) { build_stubbed(:simple_order_cycle) }
it "reports status when an order cycle is upcoming" do
Timecop.freeze(oc.orders_open_at - 1.second) do
travel_to(oc.orders_open_at - 1.second) do
expect(oc).not_to be_undated
expect(oc).to be_dated
expect(oc).to be_upcoming
@@ -322,7 +322,7 @@ RSpec.describe OrderCycle do
end
it "reports status when an order cycle has closed" do
Timecop.freeze(oc.orders_close_at + 1.second) do
travel_to(oc.orders_close_at + 1.second) do
expect(oc).not_to be_undated
expect(oc).to be_dated
expect(oc).not_to be_upcoming

View File

@@ -7,10 +7,8 @@ RSpec.describe ProxyOrder do
let(:order_cycle) { create(:simple_order_cycle) }
let(:subscription) { create(:subscription) }
around do |example|
# We are testing if database columns have been set to "now".
Timecop.freeze(Time.zone.now) { example.run }
end
# We are testing if database columns have been set to "now".
before { freeze_time }
context "when the order cycle is not yet closed" do
let(:proxy_order) {
@@ -94,9 +92,7 @@ RSpec.describe ProxyOrder do
let(:proxy_order) { create(:proxy_order, order:, canceled_at: Time.zone.now) }
let(:order_cycle) { proxy_order.order_cycle }
around do |example|
Timecop.freeze(Time.zone.now) { example.run }
end
before { freeze_time }
context "when the order cycle is not yet closed" do
before { order_cycle.update(orders_open_at: 1.day.ago, orders_close_at: 3.days.from_now) }

View File

@@ -40,7 +40,7 @@ RSpec.describe TermsOfServiceFile do
let(:subject) { TermsOfServiceFile.updated_at }
it "gives the most conservative time if not known" do
Timecop.freeze do
freeze_time do
expect(subject).to eq Time.zone.now
end
end

View File

@@ -21,7 +21,7 @@ RSpec.describe Vine::JwtService do
it "includes issuing time" do
generate_time = Time.zone.now
Timecop.freeze(generate_time) do
travel_to(generate_time) do
token = subject.generate_token
payload = decode(token, vine_secret)
@@ -32,7 +32,7 @@ RSpec.describe Vine::JwtService do
it "includes expirations time" do
generate_time = Time.zone.now
Timecop.freeze(generate_time) do
travel_to(generate_time) do
token = subject.generate_token
payload = decode(token, vine_secret)

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

@@ -1,3 +0,0 @@
# frozen_string_literal: true
Timecop.safe_mode = true

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

@@ -34,7 +34,7 @@ RSpec.describe "Uploading Terms and Conditions PDF" do
attach_file "enterprise[terms_and_conditions]", original_terms, make_visible: true
time = Time.zone.local(2002, 4, 13, 0, 0, 0)
Timecop.freeze(run_time = time) do
travel_to(run_time = time) do
click_button "Update"
expect(distributor.reload.terms_and_conditions_blob.created_at).to eq run_time
end

View File

@@ -73,10 +73,24 @@ RSpec.describe '
select2_select "Missing", from: "payment_method_preferred_enterprise_id"
expect(page).to have_selector "#stripe-account-status .alert-box.error",
text: 'No Stripe account exists for this enterprise.'
connect_one = 'Connect One'
expect(page).to have_link connect_one,
href: edit_admin_enterprise_path(missing_account_enterprise,
anchor: "/payment_methods")
click_link 'Connect One' # opens in new tab
new_window = windows.last
page.within_window new_window do
expect(page).to have_content "Settings: Missing"
# we should be on the Payment Methods tab already
expect(page).to have_content "Use the button to the right to get started."
page.find("a", text: "Connect with Stripe").click # it's not a proper link without href
expect(page).to have_content "connect your Stripe account to the OFN."
href = connect_admin_stripe_accounts_path(enterprise_id: missing_account_enterprise)
expect(page).to have_link "I Agree", href:
# Blocked by capybara. probably don't need to test this.
# click_link "I Agree"
# expect(page).to have_current_path("https://connect.stripe.com/", url: true)
end
new_window.close
select2_select "Revoked", from: "payment_method_preferred_enterprise_id"
expect(page).to have_selector "#stripe-account-status .alert-box.error",

View File

@@ -13,10 +13,6 @@ RSpec.describe "Orders And Distributors" do
let!(:distributor2) { create(:distributor_enterprise, name: "By Moto") }
let!(:completed_at) { Time.zone.now.to_fs(:db) }
around do |example|
Timecop.travel(completed_at) { example.run }
end
let!(:order) {
create(:order_ready_to_ship, distributor_id: distributor.id, completed_at:)
}
@@ -25,6 +21,10 @@ RSpec.describe "Orders And Distributors" do
}
let(:variant) { order.variants.first }
before do
travel_to(completed_at)
end
context "as an enterprise user" do
let(:header) {
["Order date", "Order Id", "Customer Name", "Customer Email", "Customer Phone",

View File

@@ -116,9 +116,10 @@ RSpec.describe "Orders And Fulfillment" do
let(:datetime_start1) { 1600.hours.ago } # 1600 hours in the past
let(:datetime_start2) { 1800.hours.ago } # 1600 hours in the past
let(:datetime_end) { 1400.hours.ago } # 1400 hours in the past
before do
Timecop.travel(completed_at1) { order1.finalize! }
Timecop.travel(completed_at2) { order2.finalize! }
travel_to(completed_at1) { order1.finalize! }
travel_to(completed_at2) { order2.finalize! }
end
it "is precise to time of day, not just date" do

View File

@@ -6,8 +6,8 @@ RSpec.describe "Packing Reports" do
include AuthenticationHelper
include WebHelper
around do |example|
Timecop.freeze(Time.zone.now.strftime("%Y-%m-%d 00:00")) { example.run }
before do
travel_to(Time.zone.now.strftime("%Y-%m-%d 00:00"))
end
let!(:open_datetime) { 1.month.ago.strftime("%Y-%m-%d 00:00") }

View File

@@ -102,13 +102,13 @@ RSpec.describe '
expect(content).to match "<th>\nFirst Name\n</th>"
# Let's also check the expiry of the emailed link:
Timecop.travel(3.days.from_now) do
travel(3.days) do
content = URI.parse(report_link).read
expect(content).to match "<th>\nFirst Name\n</th>"
end
# The link should still expire though:
Timecop.travel(3.months.from_now) do
travel(3.months) do
expect { URI.parse(report_link).read }
.to raise_error OpenURI::HTTPError, "404 Not Found"
end
@@ -625,15 +625,13 @@ RSpec.describe '
order1.update_order!
order1.update!(email: 'customer@email.com')
order1.shipment.update(included_tax_total: 10.06)
Timecop.travel(Time.zone.local(2021, 4, 25, 14, 0, 0)) { order1.finalize! }
travel_to(Time.zone.local(2021, 4, 25, 14, 0, 0)) { order1.finalize! }
order1.reload
order1.create_tax_charge!
end
around do |example|
Timecop.travel(Time.zone.local(2021, 4, 26, 14, 0, 0)) do
example.run
end
before do
travel_to(Time.zone.local(2021, 4, 26, 14, 0, 0))
end
context "summary report" do

Some files were not shown because too many files have changed in this diff Show More