diff --git a/.github/workflows/ci_cd.yml b/.github/workflows/ci_cd.yml new file mode 100644 index 000000000..84389ae8b --- /dev/null +++ b/.github/workflows/ci_cd.yml @@ -0,0 +1,201 @@ +env: + CI: true + COVERAGE: true + +name: CI - CD +on: [push] +jobs: + security: + name: Brakeman + if: "${{ github.actor != 'dependabot[bot]' }}" + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: 3.2.1 + + - name: Brakeman + uses: reviewdog/action-brakeman@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + bundler-cache: true + cache-version: 321 + + - name: Run RuboCop + run: bundle exec rubocop --parallel + + tests: + name: Tests + runs-on: ubuntu-latest + timeout-minutes: 30 + services: + postgres: + image: postgres:latest + env: + POSTGRES_USER: admin_apientreprise + POSTGRES_PASSWORD: wow*verysecret + POSTGRES_DB: admin_apientreprise_test + POSTGRES_PORT: 5432 + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + redis: + image: redis + ports: ["6379:6379"] + options: --entrypoint redis-server + + steps: + - name: Dump Github context + env: + GITHUB_CONTEXT: ${{ toJson(github) }} + run: echo "$GITHUB_CONTEXT" + + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup ruby + uses: ruby/setup-ruby@v1 + with: + bundler-cache: true + cache-version: 322 + + - name: Setup Nodejs + uses: actions/setup-node@v3 + + - name: Install mjml dependency + run: npm install mjml + + - name: Install postgres client #and imagemagick + run: sudo apt-get install libpq-dev #imagemagick + + - name: Create database users + env: + POSTGRES_USER: admin_apientreprise + POSTGRES_DB: admin_apientreprise_test + PGPASSWORD: wow*verysecret + run: | + psql -h localhost -U ${{ env.POSTGRES_USER }} -d ${{ env.POSTGRES_DB }} -f `pwd`/postgresql_setup.txt + + - name: Create database + run: bundle exec rails db:create db:schema:load RAILS_ENV=test + + - name: Run tests + run: bundle exec rspec + + - uses: joshmfrankel/simplecov-check-action@main + if: "${{ github.actor != 'dependabot[bot]' }}" + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + minimum_suite_coverage: 95 + + merge-with-master: + name: Merge develop with master + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/develop' + needs: + - security + - lint + - tests + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Import GPG key to sign master push + if: github.ref == 'refs/heads/develop' + id: import_gpg + uses: crazy-max/ghaction-import-gpg@v6 + with: + gpg_private_key: ${{ secrets.GPG_SECRET_KEY }} + passphrase: ${{ secrets.GPG_PASSPHRASE }} + git_user_signingkey: true + git_commit_gpgsign: true + + - name: Force push develop to master + if: github.ref == 'refs/heads/develop' + run: | + git reset --hard && \ + git push --force origin develop:master && \ + git fetch && \ + [[ ! -s \"$(git rev-parse --git-dir)/shallow\" ]] || git fetch --unshallow + exit 0 + + continuous-deployment-staging: + name: Continuous deployment on staging + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/develop' + needs: + - security + - lint + - tests + - merge-with-master + timeout-minutes: 10 + strategy: + matrix: + host: [watchdoge1, watchdoge2, watchdoge3, watchdoge4] + fail-fast: false + environment: staging + env: + DEPLOY_HTTPS_LOGIN: ${{ secrets.DEPLOY_HTTPS_LOGIN }} + DEPLOY_HTTPS_PASSWORD: ${{ secrets.DEPLOY_HTTPS_PASSWORD }} + DEPLOY_HTTPS_REQUEST_URL: ${{ vars.DEPLOY_HTTPS_REQUEST_URL }} + DEPLOY_HTTPS_RESPONSE_URL: ${{ vars.DEPLOY_HTTPS_RESPONSE_URL }} + DEPLOY_HOST: host_${{ matrix.host }} + DEPLOY_APP: admin_apientreprise_staging + steps: + - name: Download and run deploy script + shell: bash + run: | + git clone https://github.com/etalab/api-entreprise-integration + cd api-entreprise-integration + ./deploy-parteprise.sh + + continuous-deployment-production: + name: Continuous deployment on production + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/develop' + needs: + - security + - lint + - tests + - merge-with-master + - continuous-deployment-staging + timeout-minutes: 20 + strategy: + matrix: + host: [watchdoge1, watchdoge2, watchdoge3, watchdoge4] + deploy_env: [production] + fail-fast: false + environment: production + env: + DEPLOY_HTTPS_LOGIN: ${{ secrets.DEPLOY_HTTPS_LOGIN }} + DEPLOY_HTTPS_PASSWORD: ${{ secrets.DEPLOY_HTTPS_PASSWORD }} + DEPLOY_HTTPS_REQUEST_URL: ${{ vars.DEPLOY_HTTPS_REQUEST_URL }} + DEPLOY_HTTPS_RESPONSE_URL: ${{ vars.DEPLOY_HTTPS_RESPONSE_URL }} + DEPLOY_HOST: host_${{ matrix.host }} + DEPLOY_APP: admin_apientreprise_${{ matrix.deploy_env }} + steps: + - name: Download and run deploy script + shell: bash + run: | + git clone https://github.com/etalab/api-entreprise-integration + cd api-entreprise-integration + ./deploy-parteprise.sh diff --git a/.github/workflows/https-deploy-production.yaml b/.github/workflows/https-deploy-production.yaml index 72c8a454c..f6d703542 100644 --- a/.github/workflows/https-deploy-production.yaml +++ b/.github/workflows/https-deploy-production.yaml @@ -9,7 +9,7 @@ jobs: timeout-minutes: 20 strategy: matrix: - host: [watchdoge1, watchdoge2, watchdoge3, watchdoge4, watchdoge5] + host: [watchdoge1, watchdoge2, watchdoge3, watchdoge4] deploy_env: [staging, production] fail-fast: false environment: production diff --git a/.github/workflows/https-deploy-sandbox.yaml b/.github/workflows/https-deploy-sandbox.yaml index d2fbb70e2..83904b94b 100644 --- a/.github/workflows/https-deploy-sandbox.yaml +++ b/.github/workflows/https-deploy-sandbox.yaml @@ -11,7 +11,7 @@ jobs: timeout-minutes: 10 strategy: matrix: - host: [watchdoge1, watchdoge2, watchdoge3, watchdoge4, watchdoge5] + host: [watchdoge1, watchdoge2, watchdoge3, watchdoge4] fail-fast: false environment: sandbox env: diff --git a/.github/workflows/https-deploy-staging.yaml b/.github/workflows/https-deploy-staging.yaml index 5de4b627a..6574b9add 100644 --- a/.github/workflows/https-deploy-staging.yaml +++ b/.github/workflows/https-deploy-staging.yaml @@ -9,7 +9,7 @@ jobs: timeout-minutes: 10 strategy: matrix: - host: [watchdoge1, watchdoge2, watchdoge3, watchdoge4, watchdoge5] + host: [watchdoge1, watchdoge2, watchdoge3, watchdoge4] fail-fast: false environment: staging env: diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml deleted file mode 100644 index cbdd39819..000000000 --- a/.github/workflows/lint.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: RuboCop - -on: [push] - -jobs: - lint: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - - name: Set up Ruby - uses: ruby/setup-ruby@v1 - with: - bundler-cache: true - cache-version: 321 - - - name: Run RuboCop - run: bundle exec rubocop --parallel diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml deleted file mode 100644 index f799586ce..000000000 --- a/.github/workflows/security.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Security - -on: [push] - -jobs: - security: - name: Brakeman (Static security) - if: "${{ github.actor != 'dependabot[bot]' }}" - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up Ruby - uses: ruby/setup-ruby@v1 - with: - ruby-version: 3.2.1 - - - name: Brakeman - uses: reviewdog/action-brakeman@v2 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml deleted file mode 100644 index dcc848bf5..000000000 --- a/.github/workflows/tests.yml +++ /dev/null @@ -1,94 +0,0 @@ -env: - CI: true - COVERAGE: true - -name: Tests + merge develop->master -on: [push] -jobs: - test: - name: Tests (RSpec) - runs-on: ubuntu-latest - timeout-minutes: 30 - services: - postgres: - image: postgres:latest - env: - POSTGRES_USER: admin_apientreprise - POSTGRES_PASSWORD: wow*verysecret - POSTGRES_DB: admin_apientreprise_test - POSTGRES_PORT: 5432 - ports: - - 5432:5432 - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - - redis: - image: redis - ports: ["6379:6379"] - options: --entrypoint redis-server - - steps: - - name: Dump Github context - env: - GITHUB_CONTEXT: ${{ toJson(github) }} - run: echo "$GITHUB_CONTEXT" - - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup ruby - uses: ruby/setup-ruby@v1 - with: - bundler-cache: true - cache-version: 322 - - - name: Setup Nodejs - uses: actions/setup-node@v3 - - - name: Install mjml dependency - run: npm install mjml - - - name: Install postgres client #and imagemagick - run: sudo apt-get install libpq-dev #imagemagick - - - name: Create database users - env: - POSTGRES_USER: admin_apientreprise - POSTGRES_DB: admin_apientreprise_test - PGPASSWORD: wow*verysecret - run: | - psql -h localhost -U ${{ env.POSTGRES_USER }} -d ${{ env.POSTGRES_DB }} -f `pwd`/postgresql_setup.txt - - - name: Create database - run: bundle exec rails db:create db:schema:load RAILS_ENV=test - - - name: Run tests - run: bundle exec rspec - - - uses: joshmfrankel/simplecov-check-action@main - if: "${{ github.actor != 'dependabot[bot]' }}" - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - minimum_suite_coverage: 95 - - - name: Import GPG key to sign master push - if: github.ref == 'refs/heads/develop' - id: import_gpg - uses: crazy-max/ghaction-import-gpg@v6 - with: - gpg_private_key: ${{ secrets.GPG_SECRET_KEY }} - passphrase: ${{ secrets.GPG_PASSPHRASE }} - git_user_signingkey: true - git_commit_gpgsign: true - - - name: Force push develop to master - if: github.ref == 'refs/heads/develop' - run: | - git reset --hard && \ - git push --force origin develop:master && \ - git fetch && \ - [[ ! -s \"$(git rev-parse --git-dir)/shallow\" ]] || git fetch --unshallow - exit 0 diff --git a/.rubocop.yml b/.rubocop.yml index 41ffc3e03..fad8c07b2 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -93,6 +93,10 @@ Metrics/MethodLength: RSpec/NestedGroups: Enabled: false +RSpec/SpecFilePathFormat: + Exclude: + - "spec/**/*hubee*" + Naming/VariableNumber: Enabled: false diff --git a/.ruby-version b/.ruby-version index 619b53766..9c25013db 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -3.3.3 +3.3.6 diff --git a/Gemfile b/Gemfile index 7ca3b51a6..6183661a7 100644 --- a/Gemfile +++ b/Gemfile @@ -6,7 +6,7 @@ git_source(:github) do |repo_name| end # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '~> 7.1' +gem 'rails', '~> 8.0' # Use postgresql as the database for Active Record gem 'pg' # Use Puma as the app server @@ -40,7 +40,7 @@ gem 'sitemap_generator' gem 'pastel' -gem 'rails-i18n', '~> 7.0.9' +gem 'rails-i18n' # Use Active Storage variant # gem 'image_processing', '~> 1.2' @@ -76,6 +76,13 @@ gem 'ransack' gem 'wicked' +gem 'rest-client' +gem 'faraday' +gem 'faraday-gzip' +gem 'faraday-net_http' +gem 'faraday-retry' +gem 'faraday-encoding' + group :development, :test do gem 'awesome_print' gem 'brakeman' @@ -99,10 +106,10 @@ group :development do # Can be configured to work on production as well see: https://github.com/MiniProfiler/rack-mini-profiler/blob/master/README.md gem 'rack-mini-profiler', '~> 3.3' gem 'rubocop', require: false - gem 'rubocop-rails' - gem 'rubocop-rspec' gem 'rubocop-capybara' gem 'rubocop-factory_bot' + gem 'rubocop-rails' + gem 'rubocop-rspec' gem 'rubocop-rspec_rails' gem 'better_errors' @@ -114,7 +121,7 @@ group :test do gem 'cuprite' gem 'rspec-collection_matchers' gem 'rspec-its' - gem 'rspec-rails', '6.1.3' + gem 'rspec-rails', '7.1.0' gem 'rspec-retry' gem 'shoulda-matchers' gem 'simplecov', require: false diff --git a/Gemfile.lock b/Gemfile.lock index 8dab8384f..239305ec2 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,93 +1,90 @@ GEM remote: https://rubygems.org/ specs: - actioncable (7.1.3.4) - actionpack (= 7.1.3.4) - activesupport (= 7.1.3.4) + actioncable (8.0.0) + actionpack (= 8.0.0) + activesupport (= 8.0.0) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (7.1.3.4) - actionpack (= 7.1.3.4) - activejob (= 7.1.3.4) - activerecord (= 7.1.3.4) - activestorage (= 7.1.3.4) - activesupport (= 7.1.3.4) - mail (>= 2.7.1) - net-imap - net-pop - net-smtp - actionmailer (7.1.3.4) - actionpack (= 7.1.3.4) - actionview (= 7.1.3.4) - activejob (= 7.1.3.4) - activesupport (= 7.1.3.4) - mail (~> 2.5, >= 2.5.4) - net-imap - net-pop - net-smtp + actionmailbox (8.0.0) + actionpack (= 8.0.0) + activejob (= 8.0.0) + activerecord (= 8.0.0) + activestorage (= 8.0.0) + activesupport (= 8.0.0) + mail (>= 2.8.0) + actionmailer (8.0.0) + actionpack (= 8.0.0) + actionview (= 8.0.0) + activejob (= 8.0.0) + activesupport (= 8.0.0) + mail (>= 2.8.0) rails-dom-testing (~> 2.2) - actionpack (7.1.3.4) - actionview (= 7.1.3.4) - activesupport (= 7.1.3.4) + actionpack (8.0.0) + actionview (= 8.0.0) + activesupport (= 8.0.0) nokogiri (>= 1.8.5) - racc rack (>= 2.2.4) rack-session (>= 1.0.1) rack-test (>= 0.6.3) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - actiontext (7.1.3.4) - actionpack (= 7.1.3.4) - activerecord (= 7.1.3.4) - activestorage (= 7.1.3.4) - activesupport (= 7.1.3.4) + useragent (~> 0.16) + actiontext (8.0.0) + actionpack (= 8.0.0) + activerecord (= 8.0.0) + activestorage (= 8.0.0) + activesupport (= 8.0.0) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.1.3.4) - activesupport (= 7.1.3.4) + actionview (8.0.0) + activesupport (= 8.0.0) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - activejob (7.1.3.4) - activesupport (= 7.1.3.4) + activejob (8.0.0) + activesupport (= 8.0.0) globalid (>= 0.3.6) - activemodel (7.1.3.4) - activesupport (= 7.1.3.4) + activemodel (8.0.0) + activesupport (= 8.0.0) activemodel-serializers-xml (1.0.2) activemodel (> 5.x) activesupport (> 5.x) builder (~> 3.1) - activerecord (7.1.3.4) - activemodel (= 7.1.3.4) - activesupport (= 7.1.3.4) + activerecord (8.0.0) + activemodel (= 8.0.0) + activesupport (= 8.0.0) timeout (>= 0.4.0) - activestorage (7.1.3.4) - actionpack (= 7.1.3.4) - activejob (= 7.1.3.4) - activerecord (= 7.1.3.4) - activesupport (= 7.1.3.4) + activestorage (8.0.0) + actionpack (= 8.0.0) + activejob (= 8.0.0) + activerecord (= 8.0.0) + activesupport (= 8.0.0) marcel (~> 1.0) - activesupport (7.1.3.4) + activesupport (8.0.0) base64 + benchmark (>= 0.3) bigdecimal - concurrent-ruby (~> 1.0, >= 1.0.2) + concurrent-ruby (~> 1.0, >= 1.3.1) connection_pool (>= 2.2.5) drb i18n (>= 1.6, < 2) + logger (>= 1.4.2) minitest (>= 5.1) - mutex_m - tzinfo (~> 2.0) - addressable (2.8.6) - public_suffix (>= 2.0.2, < 6.0) - algolia (2.3.4) - faraday (>= 0.15, < 3) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + uri (>= 0.13.1) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) + algolia (3.5.4) + base64 (>= 0.2.0, < 1) + faraday (>= 1.0.1, < 3.0) faraday-net_http_persistent (>= 0.15, < 3) - multi_json (~> 1.0) net-http-persistent - algoliasearch-rails (2.3.2) - algolia (< 3.0.0) + algoliasearch-rails (3.0.0) + algolia (>= 3.5.2) json (>= 1.5.1) anchored (1.1.0) ansi (1.5.0) @@ -96,6 +93,7 @@ GEM awesome_print (1.9.2) base64 (0.2.0) bcrypt (3.1.20) + benchmark (0.4.0) better_errors (2.10.1) erubi (>= 1.0.0) rack (>= 0.9.0) @@ -104,12 +102,12 @@ GEM bindex (0.8.1) binding_of_caller (1.0.1) debug_inspector (>= 1.2.0) - bootsnap (1.18.3) + bootsnap (1.18.4) msgpack (~> 1.2) - brakeman (6.1.2) + brakeman (6.2.2) racc builder (3.3.0) - bullet (7.2.0) + bullet (8.0.0) activesupport (>= 3.0.0) uniform_notifier (~> 1.11) byebug (11.1.3) @@ -125,7 +123,7 @@ GEM chronic (0.10.2) coderay (1.1.3) colorize (1.1.0) - concurrent-ruby (1.3.3) + concurrent-ruby (1.3.4) connection_pool (2.4.1) crack (1.0.0) bigdecimal @@ -134,10 +132,10 @@ GEM cuprite (0.15.1) capybara (~> 3.0) ferrum (~> 0.15.0) - date (3.3.4) + date (3.4.0) debug_inspector (1.2.0) diff-lcs (1.5.1) - docile (1.4.0) + docile (1.4.1) domain_name (0.6.20240107) draper (4.0.2) actionpack (>= 5.0) @@ -150,18 +148,27 @@ GEM erubi (1.13.0) et-orbi (1.2.11) tzinfo - factory_bot (6.4.5) + factory_bot (6.5.0) activesupport (>= 5.0.0) - factory_bot_rails (6.4.3) - factory_bot (~> 6.4) + factory_bot_rails (6.4.4) + factory_bot (~> 6.5) railties (>= 5.0.0) - faraday (2.9.0) - faraday-net_http (>= 2.0, < 3.2) - faraday-net_http (3.1.0) + faraday (2.12.0) + faraday-net_http (>= 2.0, < 3.4) + json + logger + faraday-encoding (0.0.6) + faraday + faraday-gzip (2.0.1) + faraday (>= 1.0) + zlib (~> 3.0) + faraday-net_http (3.3.0) net-http - faraday-net_http_persistent (2.1.0) + faraday-net_http_persistent (2.3.0) faraday (~> 2.5) - net-http-persistent (~> 4.0) + net-http-persistent (>= 4.0.4, < 5) + faraday-retry (2.2.1) + faraday (~> 2.0) ferrum (0.15) addressable (~> 2.5) concurrent-ruby (~> 1.1) @@ -169,14 +176,14 @@ GEM websocket-driver (~> 0.7) ffi (1.16.3) formatador (1.1.0) - fugit (1.11.0) + fugit (1.11.1) et-orbi (~> 1, >= 1.2.11) raabro (~> 1.4) gaffe (1.2.0) rails (>= 4.0.0) globalid (1.2.1) activesupport (>= 6.1) - good_job (3.99.0) + good_job (3.99.1) activejob (>= 6.0.0) activerecord (>= 6.0.0) concurrent-ruby (>= 1.0.2) @@ -197,13 +204,13 @@ GEM guard (~> 2.1) guard-compat (~> 1.1) rspec (>= 2.99.0, < 4.0) - hashdiff (1.1.0) + hashdiff (1.1.1) hashie (5.0.0) highline (3.0.1) http-accept (1.7.0) - http-cookie (1.0.5) + http-cookie (1.0.7) domain_name (~> 0.5) - i18n (1.14.5) + i18n (1.14.6) concurrent-ruby (~> 1.0) i18n-tasks (1.0.14) activesupport (>= 4.0.2) @@ -218,11 +225,11 @@ GEM interactor (3.1.2) io-console (0.7.2) ip_anonymizer (0.3.0) - irb (1.14.0) + irb (1.14.1) rdoc (>= 4.0.0) reline (>= 0.4.2) - json (2.7.2) - jwt (2.8.2) + json (2.8.2) + jwt (2.9.3) base64 kaminari (1.2.2) activesupport (>= 4.1.0) @@ -244,10 +251,11 @@ GEM listen (3.9.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) + logger (1.6.1) logstasher (2.1.5) activesupport (>= 5.2) request_store - loofah (2.22.0) + loofah (2.23.1) crass (~> 1.0.2) nokogiri (>= 1.12.0) lumberjack (1.2.9) @@ -256,45 +264,42 @@ GEM net-imap net-pop net-smtp - mailjet (1.7.11) + mailjet (1.8.0) activesupport (>= 5.0.0) + faraday (~> 2.1) rack (>= 1.4.0) - rest-client (>= 2.1.0) yajl-ruby marcel (1.0.4) matrix (0.4.2) method_source (1.1.0) mime-types (3.5.2) mime-types-data (~> 3.2015) - mime-types-data (3.2024.0305) + mime-types-data (3.2024.0820) mini_mime (1.1.5) - minitest (5.24.1) - mjml-rails (4.11.0) + minitest (5.25.1) + mjml-rails (4.12.1) msgpack (1.7.2) - multi_json (1.15.0) multi_xml (0.6.0) - mutex_m (0.2.0) nenv (0.3.0) net-http (0.4.1) uri - net-http-persistent (4.0.2) + net-http-persistent (4.0.4) connection_pool (~> 2.2) - net-imap (0.4.11) + net-imap (0.5.1) date net-protocol net-pop (0.1.2) - net-protocol net-protocol (0.2.2) timeout net-smtp (0.5.0) net-protocol netrc (0.11.0) - nio4r (2.7.3) - nokogiri (1.16.6-aarch64-linux) + nio4r (2.7.4) + nokogiri (1.16.8-aarch64-linux) racc (~> 1.4) - nokogiri (1.16.6-arm64-darwin) + nokogiri (1.16.8-arm64-darwin) racc (~> 1.4) - nokogiri (1.16.6-x86_64-linux) + nokogiri (1.16.8-x86_64-linux) racc (~> 1.4) notiffany (0.1.3) nenv (~> 0.1) @@ -316,16 +321,16 @@ GEM omniauth-rails_csrf_protection (1.0.2) actionpack (>= 4.2) omniauth (~> 2.0) - optimist (3.1.0) - parallel (1.25.1) - parser (3.3.4.0) + optimist (3.2.0) + parallel (1.26.3) + parser (3.3.6.0) ast (~> 2.4.1) racc pastel (0.8.0) tty-color (~> 0.5) patience_diff (1.2.0) optimist (~> 3.0) - pg (1.5.6) + pg (1.5.9) pretender (0.5.0) actionpack (>= 6.1) pry (0.14.2) @@ -336,16 +341,16 @@ GEM pry (>= 0.13, < 0.15) pry-rails (0.3.11) pry (>= 0.13.0) - psych (5.1.2) + psych (5.2.0) stringio - public_suffix (5.1.0) - puma (6.4.2) + public_suffix (6.0.1) + puma (6.5.0) nio4r (~> 2.0) - pundit (2.3.2) + pundit (2.4.0) activesupport (>= 3.0.0) raabro (1.4.0) - racc (1.8.0) - rack (3.1.6) + racc (1.8.1) + rack (3.1.8) rack-cors (2.0.2) rack (>= 2.0.0) rack-mini-profiler (3.3.1) @@ -360,44 +365,43 @@ GEM rack_session_access (0.2.0) builder (>= 2.0.0) rack (>= 1.0.0) - rackup (2.1.0) + rackup (2.2.0) rack (>= 3) - webrick (~> 1.8) - rails (7.1.3.4) - actioncable (= 7.1.3.4) - actionmailbox (= 7.1.3.4) - actionmailer (= 7.1.3.4) - actionpack (= 7.1.3.4) - actiontext (= 7.1.3.4) - actionview (= 7.1.3.4) - activejob (= 7.1.3.4) - activemodel (= 7.1.3.4) - activerecord (= 7.1.3.4) - activestorage (= 7.1.3.4) - activesupport (= 7.1.3.4) + rails (8.0.0) + actioncable (= 8.0.0) + actionmailbox (= 8.0.0) + actionmailer (= 8.0.0) + actionpack (= 8.0.0) + actiontext (= 8.0.0) + actionview (= 8.0.0) + activejob (= 8.0.0) + activemodel (= 8.0.0) + activerecord (= 8.0.0) + activestorage (= 8.0.0) + activesupport (= 8.0.0) bundler (>= 1.15.0) - railties (= 7.1.3.4) + railties (= 8.0.0) rails-dom-testing (2.2.0) activesupport (>= 5.0.0) minitest nokogiri (>= 1.6) - rails-html-sanitizer (1.6.0) + rails-html-sanitizer (1.6.1) loofah (~> 2.21) - nokogiri (~> 1.14) - rails-i18n (7.0.9) + 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 (8.0.1) i18n (>= 0.7, < 2) - railties (>= 6.0.0, < 8) - railties (7.1.3.4) - actionpack (= 7.1.3.4) - activesupport (= 7.1.3.4) - irb + railties (>= 8.0.0, < 9) + railties (8.0.0) + actionpack (= 8.0.0) + activesupport (= 8.0.0) + irb (~> 1.13) rackup (>= 1.0.0) rake (>= 12.2) thor (~> 1.0, >= 1.2.2) zeitwerk (~> 2.6) rainbow (3.1.1) rake (13.2.1) - ransack (4.1.1) + ransack (4.2.1) activerecord (>= 6.1.5) activesupport (>= 6.1.5) i18n @@ -406,12 +410,12 @@ GEM ffi (~> 1.0) rdoc (6.7.0) psych (>= 4.0.0) - redis (5.2.0) + redis (5.3.0) redis-client (>= 0.22.0) - redis-client (0.22.1) + redis-client (0.22.2) connection_pool - regexp_parser (2.9.2) - reline (0.5.9) + regexp_parser (2.9.3) + reline (0.5.11) io-console (~> 0.5) request_store (1.5.1) rack (>= 1.4) @@ -420,8 +424,7 @@ GEM http-cookie (>= 1.0.2, < 2.0) mime-types (>= 1.16, < 4.0) netrc (~> 0.8) - rexml (3.3.1) - strscan + rexml (3.3.9) rouge (4.1.3) rspec (3.13.0) rspec-core (~> 3.13.0) @@ -429,21 +432,21 @@ GEM rspec-mocks (~> 3.13.0) rspec-collection_matchers (1.2.1) rspec-expectations (>= 2.99.0.beta1) - rspec-core (3.13.0) + rspec-core (3.13.2) rspec-support (~> 3.13.0) - rspec-expectations (3.13.1) + rspec-expectations (3.13.3) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) - rspec-its (1.3.0) - rspec-core (>= 3.0.0) - rspec-expectations (>= 3.0.0) - rspec-mocks (3.13.1) + rspec-its (2.0.0) + rspec-core (>= 3.13.0) + rspec-expectations (>= 3.13.0) + rspec-mocks (3.13.2) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) - rspec-rails (6.1.3) - actionpack (>= 6.1) - activesupport (>= 6.1) - railties (>= 6.1) + rspec-rails (7.1.0) + actionpack (>= 7.0) + activesupport (>= 7.0) + railties (>= 7.0) rspec-core (~> 3.13) rspec-expectations (~> 3.13) rspec-mocks (~> 3.13) @@ -451,29 +454,28 @@ GEM rspec-retry (0.6.2) rspec-core (> 3.3) rspec-support (3.13.1) - rubocop (1.65.0) + rubocop (1.69.0) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 2.4, < 3.0) - rexml (>= 3.2.5, < 4.0) - rubocop-ast (>= 1.31.1, < 2.0) + rubocop-ast (>= 1.36.1, < 2.0) ruby-progressbar (~> 1.7) - unicode-display_width (>= 2.4.0, < 3.0) - rubocop-ast (1.31.3) + unicode-display_width (>= 2.4.0, < 4.0) + rubocop-ast (1.36.2) parser (>= 3.3.1.0) rubocop-capybara (2.21.0) rubocop (~> 1.41) rubocop-factory_bot (2.26.1) rubocop (~> 1.61) - rubocop-rails (2.25.1) + rubocop-rails (2.27.0) activesupport (>= 4.2.0) rack (>= 1.1) - rubocop (>= 1.33.0, < 2.0) + rubocop (>= 1.52.0, < 2.0) rubocop-ast (>= 1.31.1, < 2.0) - rubocop-rspec (3.0.3) + rubocop-rspec (3.2.0) rubocop (~> 1.61) rubocop-rspec_rails (2.30.0) rubocop (~> 1.61) @@ -490,24 +492,25 @@ GEM sprockets (> 3.0) sprockets-rails tilt - sentry-rails (5.18.1) + securerandom (0.3.2) + sentry-rails (5.21.0) railties (>= 5.0) - sentry-ruby (~> 5.18.1) - sentry-ruby (5.18.1) + sentry-ruby (~> 5.21.0) + sentry-ruby (5.21.0) bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) shellany (0.0.1) - shoulda-matchers (6.2.0) + shoulda-matchers (6.4.0) activesupport (>= 5.2.0) simplecov (0.22.0) docile (~> 1.1) simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) - simplecov-console (0.9.1) + simplecov-console (0.9.2) ansi simplecov terminal-table - simplecov-html (0.12.3) + simplecov-html (0.13.1) simplecov_json_formatter (0.1.4) sitemap_generator (6.3.0) builder (~> 3.0) @@ -521,42 +524,41 @@ GEM actionpack (>= 5.2) activesupport (>= 5.2) sprockets (>= 3.0.0) - stringio (3.1.1) - strong_migrations (2.0.0) + stringio (3.1.2) + strong_migrations (2.1.0) activerecord (>= 6.1) - strscan (3.1.0) - super_diff (0.12.1) + super_diff (0.14.0) attr_extras (>= 6.2.4) diff-lcs patience_diff terminal-table (3.0.2) unicode-display_width (>= 1.1.1, < 3) - thor (1.3.1) + thor (1.3.2) tilt (2.3.0) timecop (0.9.10) - timeout (0.4.1) + timeout (0.4.2) tty-color (0.6.0) - turbo-rails (2.0.5) + turbo-rails (2.0.11) actionpack (>= 6.0.0) - activejob (>= 6.0.0) railties (>= 6.0.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) - unicode-display_width (2.5.0) + unicode-display_width (2.6.0) uniform_notifier (1.16.0) unindent (1.0) - uri (0.13.0) + uri (1.0.2) + useragent (0.16.10) version_gem (1.1.3) web-console (4.2.1) actionview (>= 6.0.0) activemodel (>= 6.0.0) bindex (>= 0.4.0) railties (>= 6.0.0) - webmock (3.23.1) + webmock (3.24.0) addressable (>= 2.8.0) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) - webrick (1.8.1) + webrick (1.9.0) websocket-driver (0.7.6) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) @@ -565,12 +567,14 @@ GEM xpath (3.2.0) nokogiri (~> 1.8) yajl-ruby (1.4.3) - zeitwerk (2.6.16) + zeitwerk (2.7.1) + zlib (3.1.1) PLATFORMS aarch64-linux arm64-darwin-22 arm64-darwin-23 + arm64-darwin-24 x86_64-linux DEPENDENCIES @@ -589,6 +593,11 @@ DEPENDENCIES cuprite draper factory_bot_rails + faraday + faraday-encoding + faraday-gzip + faraday-net_http + faraday-retry gaffe good_job (~> 3.99) guard-rspec @@ -615,13 +624,14 @@ DEPENDENCIES rack-cors rack-mini-profiler (~> 3.3) rack_session_access - rails (~> 7.1) - rails-i18n (~> 7.0.9) + rails (~> 8.0) + rails-i18n ransack redis + rest-client rspec-collection_matchers rspec-its - rspec-rails (= 6.1.3) + rspec-rails (= 7.1.0) rspec-retry rubocop rubocop-capybara diff --git a/README.md b/README.md index e5ef2453e..a5683f4c8 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ ## Requirements -- ruby 3.3.2 +- ruby 3.3.6 - redis-server >= 6 - postgresql >= 9 - Node.js >= 6 pour mjml @@ -27,6 +27,12 @@ installer les paquets et importer les tables de la base de données : Installer `Docker` et `docker-compose` (sur Mac tout est [ici](https://docs.docker.com/desktop/mac/install/)) +Pour installer l'application : + +```sh +make install +``` + Pour lancer l'application : ```sh @@ -41,12 +47,6 @@ Pour arrêter: make stop ``` -Lors du premier lancement, il faut initialiser la base de donnée (après `make start`): - -```sh -make install_database -``` - En cas de problème, pour réinstaller la base de données: ```sh @@ -118,9 +118,9 @@ Vous pouvez accéder ensuite accéder au site via les adresses suivantes: ``` # Pour visualiser le site d'API Entreprise -http://entreprise.api.localtest.me:3000/ +http://entreprise.api.localtest.me:5000/ # Pour visualiser le site d'API Particulier -http://particulier.api.localtest.me:3000/ +http://particulier.api.localtest.me:5000/ ``` ### Avec Docker diff --git a/app/assets/images/providers/api_entreprise/cibtp.png b/app/assets/images/providers/api_entreprise/cibtp.png new file mode 100644 index 000000000..c4651dba0 Binary files /dev/null and b/app/assets/images/providers/api_entreprise/cibtp.png differ diff --git a/app/assets/stylesheets/api_entreprise/pages/home/_section_developers.scss b/app/assets/stylesheets/api_entreprise/pages/home/_section_developers.scss new file mode 100644 index 000000000..87c0e88f4 --- /dev/null +++ b/app/assets/stylesheets/api_entreprise/pages/home/_section_developers.scss @@ -0,0 +1,5 @@ +#homepage #section-developers { + #hyperping-badge { + background-image: none; + } +} diff --git a/app/assets/stylesheets/dsfr-extensions.scss b/app/assets/stylesheets/dsfr-extensions.scss index 3c2e1c496..87bbea438 100644 --- a/app/assets/stylesheets/dsfr-extensions.scss +++ b/app/assets/stylesheets/dsfr-extensions.scss @@ -115,8 +115,15 @@ max-width: 100%; } -.fr-connect-moncomptepro:before { - background-image: image-url("mon_compte_pro.svg") !important; +.fr-connect-proconnect { + padding-left: 4.375em !important; +} + +.fr-connect-proconnect:before { + width: 3.375em !important; + background-size: 3.375em 3em !important; + left: 0.625em !important; + background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2254%22%20height%3D%2248%22%20viewBox%3D%220%200%2054%2048%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%3Cpath%20d%3D%22M34.992%2015.0979L19.998%206.42087L5.004%2015.1819C4.91144%2015.2346%204.83441%2015.3108%204.78069%2015.4028C4.72697%2015.4948%204.69845%2015.5993%204.698%2015.7059V32.6539C4.70386%2032.7592%204.73465%2032.8616%204.78786%2032.9527C4.84106%2033.0439%204.91514%2033.121%205.004%2033.1779L19.996%2041.7779L34.99%2033.0719C35.0789%2033.0151%2035.153%2032.9379%2035.2063%2032.8468C35.2595%2032.7557%2035.2902%2032.6532%2035.296%2032.5479V15.6259C35.2966%2015.5188%2035.2687%2015.4136%2035.2153%2015.3208C35.1619%2015.2281%2035.0848%2015.1511%2034.992%2015.0979Z%22%20fill%3D%22%23000091%22%2F%3E%0A%3Cpath%20d%3D%22M14.641%2015.5979L9.612%2024.2259L5.055%2015.0509L10.445%2011.9379L14.934%2015.0979L14.641%2015.5979ZM35.297%2032.5779V15.6199C35.297%2015.5134%2035.2686%2015.4088%2035.2149%2015.3169C35.1611%2015.225%2035.0838%2015.1491%2034.991%2015.0969L19.998%206.42087%22%20fill%3D%22%23FCC63A%22%2F%3E%0A%3Cpath%20d%3D%22M4.7%2032.5779L20%206.42087V41.7829L5.004%2033.1779C4.91514%2033.121%204.84106%2033.0439%204.78786%2032.9527C4.73465%2032.8616%204.70386%2032.7592%204.698%2032.6539V15.7059L4.7%2032.5779ZM29.369%2011.8429L34.827%2014.9979L30.338%2024.1479L24.951%2014.9119L29.369%2011.8429Z%22%20fill%3D%22%230063CB%22%2F%3E%0A%3Cpath%20d%3D%22M39.606%2012.3029L20.416%201.28287C20.2868%201.2185%2020.1444%201.185%2020%201.185C19.8556%201.185%2019.7132%201.2185%2019.584%201.28287L0.394%2012.3029C0.278488%2012.3798%200.182654%2012.4827%200.114219%2012.6034C0.0457831%2012.7242%200.00665952%2012.8593%200%2012.9979V34.9979C0.00588693%2035.1373%200.0446444%2035.2734%200.113114%2035.3951C0.181583%2035.5167%200.277826%2035.6205%200.394%2035.6979L19.583%2046.7179C19.7122%2046.7822%2019.8546%2046.8157%2019.999%2046.8157C20.1434%2046.8157%2020.2858%2046.7822%2020.415%2046.7179L39.606%2035.6979C39.7222%2035.6205%2039.8184%2035.5167%2039.8869%2035.3951C39.9554%2035.2734%2039.9941%2035.1373%2040%2034.9979V12.9979C39.9933%2012.8593%2039.9542%2012.7242%2039.8858%2012.6034C39.8173%2012.4827%2039.7215%2012.3798%2039.606%2012.3029ZM10.789%2030.0589H10.868C10.826%2030.0589%2010.789%2030.0659%2010.789%2030.1089C10.789%2030.2089%2010.94%2030.1089%2010.989%2030.2089C10.7514%2030.2154%2010.5257%2030.3144%2010.36%2030.4849C10.36%2030.5359%2010.46%2030.5359%2010.511%2030.5359C10.436%2030.6359%2010.285%2030.5859%2010.234%2030.6869C10.2611%2030.7139%2010.2961%2030.7314%2010.334%2030.7369C10.284%2030.7369%2010.234%2030.7369%2010.234%2030.7879V30.9389C10.108%2030.9389%2010.058%2031.0389%209.957%2031.0899C10.157%2031.2409%2010.284%2031.0899%2010.485%2031.0899C9.957%2031.2899%209.529%2031.5679%209.001%2031.7189C8.901%2031.7189%209.001%2031.8699%208.901%2031.8699C9.052%2031.9699%209.128%2031.8199%209.278%2031.8199C8.624%2032.1969%207.945%2032.5199%207.241%2032.9519C7.18676%2033.0059%207.15164%2033.0761%207.141%2033.1519H6.941C6.841%2033.2019%206.891%2033.3279%206.79%2033.4289C7.016%2033.5799%207.29%2033.2289%207.444%2033.4289C7.494%2033.4289%207.344%2033.4789%207.244%2033.4789C7.194%2033.4789%207.194%2033.5789%207.144%2033.5789H6.99C6.89%2033.6539%206.79%2033.7049%206.79%2033.8549C6.74664%2033.8469%206.70187%2033.8521%206.66155%2033.8699C6.62122%2033.8878%206.58723%2033.9174%206.564%2033.9549C7.63803%2033.9506%208.70269%2033.7549%209.708%2033.3769C10.4877%2032.9799%2011.1938%2032.4526%2011.796%2031.8179C11.8231%2031.8449%2011.8406%2031.88%2011.846%2031.9179C11.6989%2032.3544%2011.4166%2032.7326%2011.04%2032.9979C10.763%2033.1489%2010.562%2033.3749%2010.34%2033.4759C10.1917%2033.5588%2010.0487%2033.651%209.912%2033.7519C9.27972%2033.9486%208.63063%2034.0865%207.973%2034.1639L7.668%2034.2079C7.443%2034.2409%207.219%2034.2769%206.997%2034.3159L5.004%2033.1779C4.93108%2033.132%204.86805%2033.072%204.8186%2033.0014C4.76914%2032.9308%204.73427%2032.8511%204.716%2032.7669C4.74933%2032.749%204.78082%2032.7279%204.81%2032.7039C4.77901%2032.671%204.74011%2032.6465%204.697%2032.6329V31.9829C5.74493%2031.7965%206.76549%2031.4801%207.735%2031.0409C6.81772%2030.4034%205.78681%2029.9475%204.698%2029.6979V28.1829C5.25307%2028.2738%205.80084%2028.4049%206.337%2028.5749C6.74977%2028.7265%207.14585%2028.9202%207.519%2029.1529C7.66563%2029.2939%207.82573%2029.4201%207.997%2029.5299C8.11768%2029.5987%208.25253%2029.639%208.3912%2029.6477C8.52987%2029.6564%208.66869%2029.6332%208.797%2029.5799H9.127C9.84341%2029.4615%2010.5135%2029.1484%2011.064%2028.6749C11.064%2028.7249%2011.114%2028.7249%2011.164%2028.7249C11.0857%2029.1235%2010.941%2029.5061%2010.736%2029.8569C10.739%2029.9079%2010.688%2030.0089%2010.789%2030.0589ZM13.606%2033.6299C13.857%2033.5299%2014.006%2033.3529%2014.235%2033.2529C14.185%2033.3029%2014.185%2033.4039%2014.135%2033.4529C13.9474%2033.5701%2013.7707%2033.704%2013.607%2033.8529C13.0413%2034.3514%2012.5116%2034.8894%2012.022%2035.4629C11.77%2035.7629%2011.494%2036.0409%2011.222%2036.3179C11.1256%2036.408%2011.0219%2036.4899%2010.912%2036.5629L8.385%2035.1129C8.74443%2035.1432%209.1063%2035.1254%209.461%2035.0599C9.75543%2034.9773%2010.0416%2034.8679%2010.316%2034.7329V34.8329C11.016%2034.5559%2011.548%2033.9269%2012.253%2033.7009C12.278%2033.7009%2012.379%2033.8009%2012.479%2033.7509C12.6601%2033.5264%2012.8904%2033.3466%2013.152%2033.2252C13.4136%2033.1038%2013.6997%2033.0442%2013.988%2033.0509C13.988%2033.1009%2013.988%2033.1509%2014.038%2033.1509H14.063C13.912%2033.2769%2013.736%2033.4019%2013.563%2033.5279C13.506%2033.5799%2013.556%2033.6299%2013.606%2033.6299ZM4.698%2027.4659V27.2799C5.21615%2027.1444%205.75053%2027.0811%206.286%2027.0919C6.44434%2027.0667%206.60566%2027.0667%206.764%2027.0919C6.05844%2027.0912%205.35854%2027.2179%204.698%2027.4659ZM35.298%2032.5539C35.2922%2032.6592%2035.2615%2032.7617%2035.2083%2032.8528C35.155%2032.9439%2035.0809%2033.0211%2034.992%2033.0779L24.913%2038.9289C23.7558%2038.5977%2022.618%2038.2021%2021.505%2037.7439C21.3437%2037.3929%2021.256%2037.0127%2021.2474%2036.6266C21.2388%2036.2404%2021.3095%2035.8566%2021.455%2035.4989C21.5349%2035.1909%2021.6531%2034.8943%2021.807%2034.6159C21.832%2034.5909%2021.857%2034.5659%2021.857%2034.5399C21.8636%2034.5399%2021.87%2034.5372%2021.8747%2034.5326C21.8794%2034.5279%2021.882%2034.5215%2021.882%2034.5149C21.9931%2034.3204%2022.1191%2034.1348%2022.259%2033.9599L22.274%2033.9449L22.294%2033.9239L22.309%2033.9089C22.309%2033.8839%2022.334%2033.8589%2022.359%2033.8329C22.384%2033.7819%2022.434%2033.7569%2022.459%2033.7069C22.6346%2033.521%2022.8285%2033.3535%2023.038%2033.2069C23.2507%2033.1298%2023.4695%2033.0706%2023.692%2033.0299C24.503%2033.0896%2025.3095%2033.1991%2026.107%2033.3579C26.205%2033.3726%2026.2992%2033.4066%2026.384%2033.4579C26.6851%2033.5165%2026.9962%2033.4994%2027.289%2033.4079C27.4799%2033.373%2027.6587%2033.2897%2027.8084%2033.1662C27.9581%2033.0426%2028.0736%2032.8827%2028.144%2032.7019C28.232%2032.5407%2028.2823%2032.3616%2028.2909%2032.1781C28.2996%2031.9947%2028.2664%2031.8116%2028.194%2031.6429C28.016%2031.3669%2028.181%2031.2059%2028.375%2031.0529L28.443%2030.9979C28.5294%2030.9367%2028.6071%2030.864%2028.674%2030.7819C28.8%2030.5299%2028.574%2030.3819%2028.523%2030.1519C28.473%2030.0519%2028.297%2030.1019%2028.196%2029.9519C28.548%2029.8009%2029.051%2029.5229%2028.825%2029.0949C28.674%2028.8679%2028.448%2028.4649%2028.725%2028.2379C29.077%2028.0379%2029.58%2028.0869%2029.731%2027.7589C29.7804%2027.5682%2029.7794%2027.368%2029.7282%2027.1778C29.6771%2026.9876%2029.5774%2026.814%2029.439%2026.6739L29.364%2026.5659C29.289%2026.4589%2029.215%2026.3519%2029.153%2026.2459C28.9941%2025.9821%2028.8177%2025.7292%2028.625%2025.4889C28.405%2025.1774%2028.2275%2024.8381%2028.097%2024.4799C27.946%2024.1019%2028.147%2023.7739%2028.147%2023.3959C28.1618%2022.6677%2028.0512%2021.9425%2027.82%2021.2519C27.694%2020.8989%2027.644%2020.5209%2027.493%2020.1929C27.474%2019.9821%2027.3956%2019.781%2027.267%2019.6129C27.2422%2019.5618%2027.2292%2019.5057%2027.2292%2019.4489C27.2292%2019.3921%2027.2422%2019.336%2027.267%2019.2849C27.472%2019.1403%2027.6656%2018.9802%2027.846%2018.8059C27.9017%2018.6836%2027.9122%2018.5455%2027.8756%2018.4162C27.839%2018.2869%2027.7576%2018.1748%2027.646%2018.0999C27.319%2017.9489%2027.346%2018.4279%2027.118%2018.5289H26.967C26.917%2018.4029%2027.017%2018.3519%2027.118%2018.2519C27.118%2018.2019%2027.118%2018.1009%2027.068%2018.1009C26.868%2018.1009%2026.691%2018.0499%2026.64%2017.9499C26.158%2017.3492%2025.5113%2016.9023%2024.779%2016.6639C24.967%2016.7216%2025.1615%2016.7552%2025.358%2016.7639C25.6956%2016.8353%2026.0471%2016.8003%2026.364%2016.6639C26.591%2016.5879%2026.641%2016.1849%2026.741%2015.9579C26.7613%2015.848%2026.7583%2015.7351%2026.7323%2015.6264C26.7063%2015.5177%2026.6578%2015.4157%2026.59%2015.3269C26.3629%2014.9967%2026.0495%2014.7352%2025.684%2014.5709C25.508%2014.4949%2025.231%2014.3439%2025.005%2014.2179C24.928%2014.1637%2024.8434%2014.1212%2024.754%2014.0919C21.789%2012.6069%2015.685%2013.8919%2015.22%2014.0919H15.211C14.7825%2014.2161%2014.3648%2014.375%2013.962%2014.5669C13.4074%2014.7728%2012.9066%2015.1015%2012.497%2015.5284C12.0875%2015.9552%2011.7798%2016.4692%2011.597%2017.0319C11.026%2017.407%2010.5658%2017.928%2010.264%2018.5409C9.836%2019.3409%209.208%2020.0499%209.308%2020.9549C9.408%2021.7349%209.585%2022.4389%209.736%2023.2439C9.77894%2023.5159%209.84586%2023.7836%209.936%2024.0439C10.036%2024.3199%209.936%2024.6729%2010.087%2024.8989C10.162%2025.0499%2010.112%2025.2259%2010.314%2025.3269V25.5269C10.364%2025.5769%2010.364%2025.6269%2010.465%2025.6269V25.8269C10.8997%2026.2504%2011.2723%2026.7331%2011.572%2027.2609C11.672%2027.5369%2011.094%2027.4119%2010.872%2027.3109C10.4565%2027.0404%2010.0762%2026.7192%209.74%2026.3549C9.71248%2026.3817%209.69456%2026.4168%209.689%2026.4549C9.889%2026.8069%2010.595%2027.2349%2010.217%2027.4609C10.017%2027.5609%209.789%2027.3099%209.588%2027.5119C9.538%2027.5869%209.588%2027.6879%209.588%2027.7879C9.311%2027.5879%209.01%2027.6879%208.733%2027.5879C8.533%2027.5379%208.481%2027.1609%208.255%2027.1609C7.65851%2027.0153%207.05373%2026.9061%206.444%2026.8339C5.86788%2026.7475%205.28724%2026.6944%204.705%2026.6749V15.7059C4.70545%2015.5993%204.73397%2015.4948%204.78769%2015.4028C4.84141%2015.3108%204.91844%2015.2346%205.011%2015.1819L19.998%206.42087L34.992%2015.0979C35.0846%2015.1505%2035.1617%2015.2267%2035.2154%2015.3187C35.2692%2015.4107%2035.2977%2015.5153%2035.298%2015.6219V32.5539ZM27.344%2024.2929C27.3138%2024.3399%2027.2719%2024.3782%2027.2225%2024.4043C27.1731%2024.4304%2027.1178%2024.4434%2027.062%2024.4419C26.9618%2024.5263%2026.8676%2024.6175%2026.78%2024.7149C26.88%2024.7149%2026.78%2024.8639%2026.88%2024.8639C26.675%2025.0869%2026.957%2025.5579%2026.675%2025.6569C26.3059%2025.7558%2025.9171%2025.7558%2025.548%2025.6569C25.6029%2025.6451%2025.6589%2025.6397%2025.715%2025.6409H25.8C25.8627%2025.6484%2025.9263%2025.6404%2025.9851%2025.6173C26.0439%2025.5943%2026.0961%2025.557%2026.137%2025.5089V25.3089C26.137%2025.2589%2026.086%2025.2589%2026.037%2025.2589C26.0107%2025.287%2025.9752%2025.3047%2025.937%2025.3089C25.9345%2025.2639%2025.9185%2025.2207%2025.891%2025.185C25.8635%2025.1493%2025.8259%2025.1227%2025.783%2025.1089C25.6501%2025.1266%2025.5148%2025.1109%2025.3894%2025.0633C25.2641%2025.0156%2025.1526%2024.9375%2025.065%2024.8359C25.2006%2024.7707%2025.3542%2024.7531%2025.501%2024.7859C25.629%2024.7859%2025.578%2024.5629%2025.732%2024.4639H25.886C26.193%2024.0919%2026.757%2023.9929%2026.86%2023.6209C26.86%2023.5209%2026.578%2023.5209%2026.373%2023.4719C26.0989%2023.4383%2025.821%2023.4552%2025.553%2023.5219C25.1932%2023.5715%2024.8405%2023.6631%2024.502%2023.7949C24.7823%2023.5891%2025.094%2023.4301%2025.425%2023.3239C25.6574%2023.2344%2025.8978%2023.1674%2026.143%2023.1239L26.275%2023.0979L26.408%2023.0709C26.5894%2023.0167%2026.7826%2023.0167%2026.964%2023.0709C27.195%2023.1709%2027.579%2023.1709%2027.63%2023.3189C27.73%2023.5919%2027.476%2023.8639%2027.195%2024.0629C27.138%2024.1439%2027.344%2024.1979%2027.344%2024.2929Z%22%20fill%3D%22white%22%2F%3E%0A%3Crect%20x%3D%2224%22%20y%3D%221%22%20width%3D%2229.56%22%20height%3D%2213.302%22%20rx%3D%222%22%20fill%3D%22%23FCC63A%22%2F%3E%0A%3Cpath%20d%3D%22M26.562%2012.1676V3.31589H29.4831C30.4526%203.31589%2031.2155%203.55194%2031.7719%204.02403C32.3367%204.49612%2032.6191%205.14104%2032.6191%205.95877C32.6191%206.76807%2032.3367%207.40876%2031.7719%207.88085C31.2155%208.35295%2030.4526%208.58899%2029.4831%208.58899H28.3576V12.1676H26.562ZM29.559%204.84598H28.3576V7.05891H29.559C29.9383%207.05891%2030.2334%206.96196%2030.4441%206.76807C30.6633%206.57417%2030.7729%206.29597%2030.7729%205.93348C30.7729%205.59627%2030.6633%205.33072%2030.4441%205.13682C30.2334%204.94293%2029.9383%204.84598%2029.559%204.84598Z%22%20fill%3D%22%23161616%22%2F%3E%0A%3Cpath%20d%3D%22M34.2307%2012.1676V3.31589H36.9368C37.9063%203.31589%2038.6734%203.55194%2039.2383%204.02403C39.8031%204.49612%2040.0855%205.14104%2040.0855%205.95877C40.0855%206.48987%2039.959%206.95353%2039.7061%207.34975C39.4617%207.73754%2039.116%208.03681%2038.6692%208.24757L41.4512%2012.1676H39.3015L36.9494%208.58899H36.0263V12.1676H34.2307ZM37.038%204.84598H36.0263V7.05891H37.038C37.4173%207.05891%2037.7124%206.96196%2037.9231%206.76807C38.1339%206.57417%2038.2393%206.29597%2038.2393%205.93348C38.2393%205.59627%2038.1339%205.33072%2037.9231%205.13682C37.7124%204.94293%2037.4173%204.84598%2037.038%204.84598Z%22%20fill%3D%22%23161616%22%2F%3E%0A%3Cpath%20d%3D%22M46.5486%203.06299C47.2399%203.06299%2047.8722%203.18944%2048.4454%203.44235C49.0271%203.69525%2049.5245%204.03246%2049.9376%204.45397C50.3507%204.87548%2050.671%205.37287%2050.8986%205.94612C51.1262%206.51095%2051.24%207.10949%2051.24%207.74176C51.24%208.37402%2051.1262%208.97678%2050.8986%209.55004C50.671%2010.1149%2050.3507%2010.608%2049.9376%2011.0295C49.5245%2011.451%2049.0271%2011.7883%2048.4454%2012.0412C47.8722%2012.2941%2047.2399%2012.4205%2046.5486%2012.4205C45.8574%2012.4205%2045.2209%2012.2941%2044.6392%2012.0412C44.0575%2011.7883%2043.5601%2011.451%2043.147%2011.0295C42.734%2010.608%2042.4136%2010.1149%2042.186%209.55004C41.9584%208.97678%2041.8446%208.37402%2041.8446%207.74176C41.8446%207.10949%2041.9584%206.51095%2042.186%205.94612C42.4136%205.37287%2042.734%204.87548%2043.147%204.45397C43.5601%204.03246%2044.0575%203.69525%2044.6392%203.44235C45.2209%203.18944%2045.8574%203.06299%2046.5486%203.06299ZM46.5486%2010.7387C46.9617%2010.7387%2047.3411%2010.6628%2047.6867%2010.5111C48.0408%2010.3509%2048.34%2010.1402%2048.5845%209.87882C48.8374%209.60905%2049.0355%209.29292%2049.1789%208.93042C49.3222%208.55949%2049.3938%208.16327%2049.3938%207.74176C49.3938%207.32025%2049.3222%206.92824%2049.1789%206.56574C49.0355%206.19481%2048.8374%205.87868%2048.5845%205.61734C48.34%205.34758%2048.0408%205.13682%2047.6867%204.98508C47.3411%204.8249%2046.9617%204.74482%2046.5486%204.74482C46.1355%204.74482%2045.752%204.8249%2045.3979%204.98508C45.0438%205.13682%2044.7403%205.34758%2044.4874%205.61734C44.243%205.87868%2044.0491%206.19481%2043.9058%206.56574C43.7624%206.92824%2043.6908%207.32025%2043.6908%207.74176C43.6908%208.16327%2043.7624%208.55949%2043.9058%208.93042C44.0491%209.29292%2044.243%209.60905%2044.4874%209.87882C44.7403%2010.1402%2045.0438%2010.3509%2045.3979%2010.5111C45.752%2010.6628%2046.1355%2010.7387%2046.5486%2010.7387Z%22%20fill%3D%22%23161616%22%2F%3E%0A%3C%2Fsvg%3E") !important; } .fr-hr-or { diff --git a/app/assets/stylesheets/shared/pages/redoc.scss b/app/assets/stylesheets/shared/pages/redoc.scss new file mode 100644 index 000000000..2ad91c006 --- /dev/null +++ b/app/assets/stylesheets/shared/pages/redoc.scss @@ -0,0 +1,5 @@ +#redoc_container { + table a { + line-break: anywhere; + } +} \ No newline at end of file diff --git a/app/clients/abstract_hubee_api_client.rb b/app/clients/abstract_hubee_api_client.rb new file mode 100644 index 000000000..9081c04aa --- /dev/null +++ b/app/clients/abstract_hubee_api_client.rb @@ -0,0 +1,23 @@ +require 'faraday' + +class AbstractHubEEAPIClient + protected + + def http_connection(&block) + Faraday.new do |conn| + conn.request :retry, max: 5 + conn.response :raise_error + conn.response :json + conn.options.timeout = 2 + yield(conn) if block + end + end + + def consumer_key + Rails.application.credentials.hubee_consumer_key + end + + def consumer_secret + Rails.application.credentials.hubee_consumer_secret + end +end diff --git a/app/clients/abstract_insee_api_client.rb b/app/clients/abstract_insee_api_client.rb new file mode 100644 index 000000000..5b836e6fa --- /dev/null +++ b/app/clients/abstract_insee_api_client.rb @@ -0,0 +1,23 @@ +require 'faraday' + +class AbstractINSEEAPIClient + protected + + def http_connection(&block) + @http_connection ||= Faraday.new do |conn| + conn.request :retry, max: 5 + conn.response :raise_error + conn.response :json + conn.options.timeout = 2 + yield(conn) if block + end + end + + def consumer_key + Rails.application.credentials.insee_consumer_key + end + + def consumer_secret + Rails.application.credentials.insee_consumer_secret + end +end diff --git a/app/clients/formulaire_qf_api_client.rb b/app/clients/formulaire_qf_api_client.rb new file mode 100644 index 000000000..45cf86a64 --- /dev/null +++ b/app/clients/formulaire_qf_api_client.rb @@ -0,0 +1,33 @@ +# :nocov: +class FormulaireQFAPIClient + def create_collectivity(organization:, editor_id: nil) + params = { + siret: organization.siret, + code_cog: organization.code_commune_etablissement, + departement: organization.code_postal_etablissement[0..1], + name: organization.denomination, + status: 'active', + editor: editor_id + } + + http_connection.post("#{host}/api/collectivites", params.to_json) + end + + private + + def host + Rails.application.credentials.formulaire_qf.host + end + + def http_connection(&block) + Faraday.new do |conn| + conn.headers['Content-Type'] = 'application/json' + conn.request :authorization, 'Bearer', -> { secret } + yield(conn) if block + end + end + + def secret + Rails.application.credentials.formulaire_qf.secret + end +end diff --git a/app/clients/hubee_api_authentication.rb b/app/clients/hubee_api_authentication.rb new file mode 100644 index 000000000..e7e0a6819 --- /dev/null +++ b/app/clients/hubee_api_authentication.rb @@ -0,0 +1,29 @@ +# :nocov: +class HubEEAPIAuthentication < AbstractHubEEAPIClient + def access_token + http_connection.post( + auth_url, + 'grant_type=client_credentials&scope=ADMIN', + { + 'Authorization' => "Basic #{encoded_client_id_and_secret}" + } + ).body['access_token'] + end + + private + + def auth_url + Rails.application.credentials.hubee_auth_url + end + + def encoded_client_id_and_secret + Base64.strict_encode64("#{consumer_key}:#{consumer_secret}") + end + + def http_connection(&block) + @http_connection ||= super do |conn| + conn.response :json + yield(conn) if block + end + end +end diff --git a/app/clients/hubee_api_client.rb b/app/clients/hubee_api_client.rb new file mode 100644 index 000000000..bb90c4f46 --- /dev/null +++ b/app/clients/hubee_api_client.rb @@ -0,0 +1,131 @@ +# :nocov: +class HubEEAPIClient < AbstractHubEEAPIClient # rubocop:disable Metrics/ClassLength + class NotFound < StandardError; end + class AlreadyExists < StandardError; end + + def find_or_create_organization(organization, email_demandeur = nil) + find_organization(organization) + rescue NotFound + create_organization(organization, email_demandeur) + end + + def find_organization(organization) + http_connection.get("#{host}/referential/v1/organizations/SI-#{organization.siret}-#{organization.code_commune_etablissement}").body + rescue Faraday::ResourceNotFound + raise NotFound + end + + def create_organization(organization, email) + http_connection.post( + "#{host}/referential/v1/organizations", + { + type: 'SI', + companyRegister: organization.siret, + branchCode: organization.code_commune_etablissement, + email:, + name: organization.denomination, + country: 'France', + postalCode: organization.code_postal_etablissement, + territory: organization.code_commune_etablissement, + status: 'Actif' + }.to_json, + 'Content-Type' => 'application/json' + ).body + rescue Faraday::BadRequestError => e + raise AlreadyExists if already_exists_error?(e) + + raise + end + + def create_subscription(authorization_request, organization_payload, process_code, editor_payload = {}) + subscription_payload = find_or_create_inactive_subscription(authorization_request, organization_payload, process_code) + activate_subscription(authorization_request, subscription_payload, editor_payload) + subscription_payload + end + + def find_subscription(_authorization_request, organization_payload, process_code) + request = http_connection { |conn| conn.request :gzip }.get( + "#{host}/referential/v1/subscriptions", + companyRegister: organization_payload['companyRegister'], + processCode: process_code + ) + request.body.first + end + + protected + + def host + Rails.application.credentials.hubee_api_url + end + + def already_exists_error?(faraday_error) + faraday_error.response[:body]['errors'].any? do |error| + error['message'].include?('already exists') + end + end + + def http_connection(&block) + super do |conn| + conn.request :authorization, 'Bearer', -> { HubEEAPIAuthentication.new.access_token } + yield(conn) if block + end + end + + private + + def activate_subscription(authorization_request, subscription_payload, editor_payload = {}) # rubocop:disable Metrics/AbcSize + subscription_id = authorization_request.extra_infos['hubee_subscription_id'] + return if subscription_id.blank? + + payload = subscription_payload.with_indifferent_access.merge({ + status: 'Actif', + activateDateTime: DateTime.now.iso8601, + accessMode: 'API', + notificationFrequency: 'Aucune' + }.with_indifferent_access) + + payload.delete('id') + payload.delete('creationDateTime') + payload.merge!(editor_payload.with_indifferent_access) + + http_connection.put( + "#{host}/referential/v1/subscriptions/#{subscription_id}", + payload.to_json, + 'Content-Type' => 'application/json' + ).body + end + + def create_inactive_subscription(authorization_request, organization_payload, process_code) # rubocop:disable Metrics/AbcSize + http_connection.post( + "#{host}/referential/v1/subscriptions", + { + datapassId: authorization_request.external_id.to_i, + notificationFrequency: 'Aucune', + processCode: process_code, + subscriber: { + type: 'SI', + companyRegister: organization_payload['companyRegister'], + branchCode: organization_payload['branchCode'] + }, + email: authorization_request.demandeur.email, + status: 'Inactif', + localAdministrator: { + email: authorization_request.demandeur.email + }, + validateDateTime: DateTime.now.iso8601, + updateDateTime: DateTime.now.iso8601 + }.to_json, + 'Content-Type' => 'application/json' + ).body + rescue Faraday::BadRequestError => e + raise AlreadyExists if already_exists_error?(e) + + raise + end + + def find_or_create_inactive_subscription(authorization_request, organization_payload, process_code) + create_inactive_subscription(authorization_request, organization_payload, process_code) + rescue HubEEAPIClient::AlreadyExists + find_subscription(authorization_request, organization_payload, process_code) + end +end diff --git a/app/clients/insee_api_authentication.rb b/app/clients/insee_api_authentication.rb new file mode 100644 index 000000000..85154071c --- /dev/null +++ b/app/clients/insee_api_authentication.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class INSEEAPIAuthentication < AbstractINSEEAPIClient + def access_token + http_connection.post( + 'https://api.insee.fr/token', + 'grant_type=client_credentials', + { + 'Authorization' => "Basic #{encoded_client_id_and_secret}" + } + ).body['access_token'] + end + + private + + def encoded_client_id_and_secret + Base64.strict_encode64("#{consumer_key}:#{consumer_secret}") + end +end diff --git a/app/clients/insee_sirene_api_client.rb b/app/clients/insee_sirene_api_client.rb new file mode 100644 index 000000000..488ca977f --- /dev/null +++ b/app/clients/insee_sirene_api_client.rb @@ -0,0 +1,15 @@ +class INSEESireneAPIClient < AbstractINSEEAPIClient + def etablissement(siret:) + http_connection.get( + "https://api.insee.fr/entreprises/sirene/V3.11/siret/#{siret}" + ).body + end + + protected + + def http_connection + super do |conn| + conn.request :authorization, 'Bearer', -> { INSEEAPIAuthentication.new.access_token } + end + end +end diff --git a/app/controllers/api_entreprise/transfer_user_account_controller.rb b/app/controllers/api_entreprise/transfer_user_account_controller.rb deleted file mode 100644 index 300f32997..000000000 --- a/app/controllers/api_entreprise/transfer_user_account_controller.rb +++ /dev/null @@ -1,3 +0,0 @@ -class APIEntreprise::TransferUserAccountController < APIEntreprise::AuthenticatedUsersController - include TransferUserAccountManagement -end diff --git a/app/controllers/api_particulier/pages_controller.rb b/app/controllers/api_particulier/pages_controller.rb index 694b6b60e..da3ba88e8 100644 --- a/app/controllers/api_particulier/pages_controller.rb +++ b/app/controllers/api_particulier/pages_controller.rb @@ -29,6 +29,10 @@ def redoc render 'shared/pages/redoc' end + def redoc_v3 + render 'shared/pages/redoc_v3' + end + def mentions render 'shared/pages/mentions' end diff --git a/app/controllers/api_particulier/reporters_controller.rb b/app/controllers/api_particulier/reporters_controller.rb new file mode 100644 index 000000000..c677fc50c --- /dev/null +++ b/app/controllers/api_particulier/reporters_controller.rb @@ -0,0 +1,33 @@ +class APIParticulier::ReportersController < APIParticulier::AuthenticatedUsersController + before_action :check_if_reporter_or_admin + + helper_method :groups_for_reporter + + def index + @datapasses_for_group_url = MetabaseEmbedService.new(490, { groups: groups_for_reporter.join('|') }).url + end + + private + + def check_if_reporter_or_admin + return if current_user.admin? || reporter_emails.include?(current_user.email) + + redirect_to root_path + end + + def groups_for_reporter + if current_user.admin? + reporters_config.keys + else + reporters_config.select { |_, emails| emails.include?(current_user.email) }.keys + end + end + + def reporter_emails + reporters_config.values.flatten.uniq + end + + def reporters_config + Rails.application.credentials.api_particulier_reporters || {} + end +end diff --git a/app/controllers/api_particulier/transfer_user_account_controller.rb b/app/controllers/api_particulier/transfer_user_account_controller.rb deleted file mode 100644 index 684390f1d..000000000 --- a/app/controllers/api_particulier/transfer_user_account_controller.rb +++ /dev/null @@ -1,3 +0,0 @@ -class APIParticulier::TransferUserAccountController < APIParticulier::AuthenticatedUsersController - include TransferUserAccountManagement -end diff --git a/app/controllers/concerns/transfer_user_account_management.rb b/app/controllers/concerns/transfer_user_account_management.rb deleted file mode 100644 index 54fb72efa..000000000 --- a/app/controllers/concerns/transfer_user_account_management.rb +++ /dev/null @@ -1,38 +0,0 @@ -module TransferUserAccountManagement - extend ActiveSupport::Concern - - def new - render 'shared/transfer_user_account/new' - end - - def create - transfer = User::TransferAccount.call(transfer_account_params) - - if transfer.success? - success_message(title: t('shared.transfer_user_account.create.success.title')) - - redirect_to user_profile_path, - status: :see_other - else - error_message(title: t('shared.transfer_user_account.create.error.title', target_email: t("#{namespace}.support_email"))) - - render 'shared/transfer_user_account/new', - status: :unprocessable_entity - end - end - - private - - def transfer_account_params - { - current_owner: current_user, - target_user_email: params[:email], - authorization_requests: current_user.authorization_requests.for_api(api), - namespace: - } - end - - def api - namespace.slice(4..-1) - end -end diff --git a/app/interactors/datapass_webhook/adapt_v2_to_v1.rb b/app/interactors/datapass_webhook/adapt_v2_to_v1.rb index 4f4b117f9..3130b36e8 100644 --- a/app/interactors/datapass_webhook/adapt_v2_to_v1.rb +++ b/app/interactors/datapass_webhook/adapt_v2_to_v1.rb @@ -1,6 +1,7 @@ class DatapassWebhook::AdaptV2ToV1 < ApplicationInteractor def call context.event = context.event.sub('authorization_request', 'enrollment') + context.authorization_request_data = generic_data.dup context.data = build_data end @@ -11,6 +12,7 @@ def build_data { 'pass' => { 'id' => context.model_id, + 'public_id' => context.data['public_id'], 'intitule' => generic_data['intitule'], 'description' => generic_data['description'], 'demarche' => context.data['form_uid'], @@ -20,7 +22,8 @@ def build_data 'previous_enrollment_id' => nil, 'scopes' => generic_data['scopes'].index_with { |_scope| true }, 'team_members' => build_team_members, - 'events' => [] + 'events' => [], + 'service_provider' => context.data['service_provider'] } } end diff --git a/app/interactors/datapass_webhook/api_particulier/create_formulaire_qf_collectivity.rb b/app/interactors/datapass_webhook/api_particulier/create_formulaire_qf_collectivity.rb new file mode 100644 index 000000000..c2c3600c2 --- /dev/null +++ b/app/interactors/datapass_webhook/api_particulier/create_formulaire_qf_collectivity.rb @@ -0,0 +1,14 @@ +class DatapassWebhook::APIParticulier::CreateFormulaireQFCollectivity < ApplicationInteractor + delegate :authorization_request, to: :context + delegate :organization, to: :authorization_request, private: true + + def call + FormulaireQFAPIClient.new.create_collectivity(organization:, editor_id:) + end + + private + + def editor_id + authorization_request.extra_infos.dig('service_provider', 'id') + end +end diff --git a/app/interactors/datapass_webhook/api_particulier/create_hubee_organization.rb b/app/interactors/datapass_webhook/api_particulier/create_hubee_organization.rb new file mode 100644 index 000000000..0cda5568d --- /dev/null +++ b/app/interactors/datapass_webhook/api_particulier/create_hubee_organization.rb @@ -0,0 +1,27 @@ +class DatapassWebhook::APIParticulier::CreateHubEEOrganization < ApplicationInteractor + delegate :authorization_request, :hubee_organization_payload, to: :context + + def call + context.hubee_organization_payload = find_or_create_organization_on_hubee + save_hubee_organization_id_to_authorization_request + end + + private + + def build_hubee_organization_id + "SI-#{hubee_organization_payload['companyRegister']}-#{hubee_organization_payload['branchCode']}" + end + + def find_or_create_organization_on_hubee + hubee_api_client.find_or_create_organization(authorization_request.organization, authorization_request.demandeur.email) + end + + def hubee_api_client + @hubee_api_client ||= HubEEAPIClient.new + end + + def save_hubee_organization_id_to_authorization_request + authorization_request.extra_infos['hubee_organization_id'] = build_hubee_organization_id + authorization_request.save! + end +end diff --git a/app/interactors/datapass_webhook/api_particulier/create_hubee_subscription.rb b/app/interactors/datapass_webhook/api_particulier/create_hubee_subscription.rb new file mode 100644 index 000000000..86779ed05 --- /dev/null +++ b/app/interactors/datapass_webhook/api_particulier/create_hubee_subscription.rb @@ -0,0 +1,52 @@ +class DatapassWebhook::APIParticulier::CreateHubEESubscription < ApplicationInteractor + delegate :authorization_request, :hubee_organization_payload, :hubee_subscription_payload, to: :context + + def call + context.hubee_subscription_payload = create_subscription_on_hubee + save_hubee_subscription_id_to_authorization_request + end + + private + + def create_subscription_on_hubee + hubee_api_client.create_subscription(authorization_request, hubee_organization_payload, process_code, editor_payload) + end + + def editor_organization + @editor_organization ||= Organization.new(service_provider['siret']) + end + + def editor_payload + return {} unless editor_subscription? + + { + delegationActor: { + branchCode: editor_organization.code_commune_etablissement, + companyRegister: editor_organization.siret, + type: 'EDT' + }, + accessMode: 'API' + } + end + + def editor_subscription? + service_provider['type'] == 'editor' + end + + def hubee_api_client + @hubee_api_client ||= HubEEAPIClient.new + end + + def process_code + 'FormulaireQF' + end + + def save_hubee_subscription_id_to_authorization_request + authorization_request.extra_infos['hubee_subscription_id'] = hubee_subscription_payload['id'] + authorization_request.save! + end + + def service_provider + @service_provider ||= Hash(authorization_request.extra_infos['service_provider']) + end +end diff --git a/app/interactors/datapass_webhook/api_particulier/notify_reporters.rb b/app/interactors/datapass_webhook/api_particulier/notify_reporters.rb new file mode 100644 index 000000000..0e1addda4 --- /dev/null +++ b/app/interactors/datapass_webhook/api_particulier/notify_reporters.rb @@ -0,0 +1,34 @@ +class DatapassWebhook::APIParticulier::NotifyReporters < ApplicationInteractor + def call + return if %w[submit approve].exclude?(context.event) + return if groups_to_notify.empty? + + APIParticulier::ReportersMailer.with(groups: groups_to_notify, authorization_request:).send(context.event).deliver_later + end + + private + + def authorization_request + context.authorization_request + end + + def groups_to_notify + reporters_groups_config.select do |group_name| + scopes.any? { |scope| scope.start_with?(group_name.to_s) } + end + end + + def reporters_groups_config + reporters_config.keys + end + + def reporters_config + Rails.application.credentials.api_particulier_reporters || {} + end + + def scopes + context.data['pass']['scopes'].map { |code, bool| + code if bool + }.compact + end +end diff --git a/app/interactors/datapass_webhook/create_or_prolong_token.rb b/app/interactors/datapass_webhook/create_or_prolong_token.rb index cf67e2202..d1c7530cc 100644 --- a/app/interactors/datapass_webhook/create_or_prolong_token.rb +++ b/app/interactors/datapass_webhook/create_or_prolong_token.rb @@ -1,6 +1,11 @@ class DatapassWebhook::CreateOrProlongToken < ApplicationInteractor + before do + context.modalities ||= %w[params] + end + def call return if %w[approve validate].exclude?(context.event) + return if context.modalities.exclude?('params') token = create_or_prolong_token diff --git a/app/interactors/datapass_webhook/find_or_create_authorization_request.rb b/app/interactors/datapass_webhook/find_or_create_authorization_request.rb index 0086ea4b9..3c968ec07 100644 --- a/app/interactors/datapass_webhook/find_or_create_authorization_request.rb +++ b/app/interactors/datapass_webhook/find_or_create_authorization_request.rb @@ -11,6 +11,8 @@ def call # rubocop:disable Metrics/AbcSize create_or_update_contacts_with_roles end + flag_updates_as_requested if expecting_updates? && %w[submit].include?(context.event) + return if context.authorization_request.save fail!('Authorization request not valid', 'error', context.authorization_request.errors.to_hash) @@ -18,6 +20,15 @@ def call # rubocop:disable Metrics/AbcSize private + def flag_updates_as_requested + context.authorization_request.token.last_prolong_token_wizard.update!(status: 'updates_requested') + end + + def expecting_updates? + context.reopening && + context.authorization_request.prolong_token_expecting_updates? + end + def set_reopening_event_flag context.reopening = reopening_event? end @@ -28,7 +39,7 @@ def reopening_event? end def should_update_authorization_request? - !context.reopening || (context.reopening && %w[approve validate].include?(context.event)) + !context.reopening || (context.reopening && %w[transfer approve validate].include?(context.event)) end def create_or_update_contacts_with_roles @@ -63,6 +74,7 @@ def extract_user_from_contact_payload(contact_payload) def authorization_request_attributes context.data['pass'].slice( + 'public_id', 'intitule', 'description', 'demarche', @@ -71,10 +83,17 @@ def authorization_request_attributes ).merge(authorization_request_attributes_for_current_event).merge( 'last_update' => fired_at_as_datetime, 'previous_external_id' => context.data['pass']['copied_from_enrollment_id'], - 'api' => context.api + 'api' => context.api, + 'extra_infos' => extra_infos_with_service_provider ) end + def extra_infos_with_service_provider + context.authorization_request.extra_infos.merge({ + 'service_provider' => Hash(context.data.dig('pass', 'service_provider')) + }) + end + def authorization_request_attributes_for_current_event authorization_request_attributes_for_current_event = {} diff --git a/app/interactors/datapass_webhook/reopen_authorization_request.rb b/app/interactors/datapass_webhook/reopen_authorization_request.rb deleted file mode 100644 index 06bab0c52..000000000 --- a/app/interactors/datapass_webhook/reopen_authorization_request.rb +++ /dev/null @@ -1,19 +0,0 @@ -class DatapassWebhook::ReopenAuthorizationRequest < ApplicationInteractor - def call - return unless context.event == 'reopen' - return unless token_already_exists? - return unless prolong_token_wizard_requires_update? - - context.authorization_request.token.last_prolong_token_wizard.update!(status: 'updates_requested') - end - - private - - def token_already_exists? - context.authorization_request.token.present? - end - - def prolong_token_wizard_requires_update? - context.authorization_request.token.last_prolong_token_wizard.presence && context.authorization_request.token.last_prolong_token_wizard.requires_update? - end -end diff --git a/app/interactors/datapass_webhook/schedule_authorization_request_emails.rb b/app/interactors/datapass_webhook/schedule_authorization_request_emails.rb index cbe284136..3272d8bb3 100644 --- a/app/interactors/datapass_webhook/schedule_authorization_request_emails.rb +++ b/app/interactors/datapass_webhook/schedule_authorization_request_emails.rb @@ -11,7 +11,7 @@ def schedule_email(email_config) return unless condition_on_update_met?(email_config) return unless condition_on_authorization_met?(email_config['condition_on_authorization']) - ScheduleAuthorizationRequestEmailJob.set(wait_until: extract_when_time(email_config['when'])).perform_later( + ScheduleAuthorizationRequestEmailJob.perform_later( context.authorization_request.id, context.authorization_request.status, template_name(email_config), @@ -70,10 +70,6 @@ def default_recipients ['authorization_request.demandeur'] end - def extract_when_time(when_time) - Chronic.parse(when_time) || Time.zone.now - end - def datapass_webhooks_config_for_event datapass_webhooks_config[context.event.to_sym] || { emails: [] } end diff --git a/app/interactors/datapass_webhook/schedule_create_formulaire_qf_resources_job.rb b/app/interactors/datapass_webhook/schedule_create_formulaire_qf_resources_job.rb new file mode 100644 index 000000000..d566d84ac --- /dev/null +++ b/app/interactors/datapass_webhook/schedule_create_formulaire_qf_resources_job.rb @@ -0,0 +1,8 @@ +class DatapassWebhook::ScheduleCreateFormulaireQFResourcesJob < ApplicationInteractor + def call + return unless context.event == 'approve' + return unless context.modalities.include?('formulaire_qf') + + CreateFormulaireQFResourcesJob.perform_later(context.authorization_request.id) + end +end diff --git a/app/interactors/user/find_or_create_new_owner.rb b/app/interactors/user/find_or_create_new_owner.rb deleted file mode 100644 index 9c7b43cdf..000000000 --- a/app/interactors/user/find_or_create_new_owner.rb +++ /dev/null @@ -1,12 +0,0 @@ -class User::FindOrCreateNewOwner < ApplicationInteractor - def call - context.target_user = User.find_or_initialize_by_email(context.target_user_email) - fail!('invalid_email', 'warn', errors) unless context.target_user.save - end - - private - - def errors - context.target_user.errors.to_hash - end -end diff --git a/app/interactors/user/notify_datapass_of_token_ownership.rb b/app/interactors/user/notify_datapass_of_token_ownership.rb deleted file mode 100644 index 30e18eb6b..000000000 --- a/app/interactors/user/notify_datapass_of_token_ownership.rb +++ /dev/null @@ -1,20 +0,0 @@ -class User - class NotifyDatapassOfTokenOwnership < ApplicationInteractor - def call - return unless first_login_after_token_transfer? - - mailer_klass.notify_datapass_for_data_reconciliation(context.user, context.namespace).deliver_later - context.user.update(tokens_newly_transfered: false) - end - - private - - def mailer_klass - "#{context.namespace.classify}::UserMailer".constantize - end - - def first_login_after_token_transfer? - context.user.tokens_newly_transfered? - end - end -end diff --git a/app/interactors/user/notify_new_tokens_owner.rb b/app/interactors/user/notify_new_tokens_owner.rb deleted file mode 100644 index b6e85f048..000000000 --- a/app/interactors/user/notify_new_tokens_owner.rb +++ /dev/null @@ -1,11 +0,0 @@ -class User::NotifyNewTokensOwner < ApplicationInteractor - def call - mailer_klass.transfer_ownership(context.current_owner, context.target_user, context.namespace).deliver_later - end - - private - - def mailer_klass - "#{context.namespace.classify}::UserMailer".constantize - end -end diff --git a/app/interactors/user/transfer_tokens.rb b/app/interactors/user/transfer_tokens.rb deleted file mode 100644 index 2a29b7465..000000000 --- a/app/interactors/user/transfer_tokens.rb +++ /dev/null @@ -1,20 +0,0 @@ -class User::TransferTokens < ApplicationInteractor - def call - context.authorization_requests.each do |authorization_request| - find_or_create_user_role(context.target_user, authorization_request) - context.current_owner.user_authorization_request_roles.where(authorization_request:).delete_all - end - - context.target_user.update(tokens_newly_transfered: true) - end - - private - - def find_or_create_user_role(user, authorization_request) - UserAuthorizationRequestRole.find_or_create_by( - user_id: user.id, - authorization_request_id: authorization_request.id, - role: 'demandeur' - ) - end -end diff --git a/app/jobs/create_formulaire_qf_resources_job.rb b/app/jobs/create_formulaire_qf_resources_job.rb new file mode 100644 index 000000000..b60c13883 --- /dev/null +++ b/app/jobs/create_formulaire_qf_resources_job.rb @@ -0,0 +1,7 @@ +class CreateFormulaireQFResourcesJob < ApplicationJob + def perform(authorization_request_id) + authorization_request = AuthorizationRequest.find(authorization_request_id) + + DatapassWebhook::CreateFormulaireQFResources.call(authorization_request:) + end +end diff --git a/app/jobs/healthcheck_job.rb b/app/jobs/healthcheck_job.rb index 5f8547ffc..7af7dc9f9 100644 --- a/app/jobs/healthcheck_job.rb +++ b/app/jobs/healthcheck_job.rb @@ -7,7 +7,10 @@ def perform http.use_ssl = true if healthcheck_uri.scheme == 'https' http.head(healthcheck_uri.path) + # rubocop:disable Lint/SuppressedException + rescue Socket::ResolutionError end + # rubocop:enable Lint/SuppressedException private diff --git a/app/lib/seeds.rb b/app/lib/seeds.rb index 685c56c9b..b8bf8205d 100644 --- a/app/lib/seeds.rb +++ b/app/lib/seeds.rb @@ -215,6 +215,6 @@ def create_user_authorization_request_role(params = {}) end def load_all_models! - Dir[Rails.root.join('app/models/**/*.rb')].each { |f| require f } + Rails.root.glob('app/models/**/*.rb').each { |f| require f } end end diff --git a/app/mailers/api_entreprise/authorization_request_mailer.rb b/app/mailers/api_entreprise/authorization_request_mailer.rb index 41099ca87..45314b437 100644 --- a/app/mailers/api_entreprise/authorization_request_mailer.rb +++ b/app/mailers/api_entreprise/authorization_request_mailer.rb @@ -4,15 +4,10 @@ class APIEntreprise::AuthorizationRequestMailer < APIEntrepriseMailer include ExternalUrlHelper %w[ - enquete_satisfaction - embarquement_brouillon_en_attente - update_embarquement_brouillon_en_attente embarquement_demande_refusee update_embarquement_demande_refusee embarquement_modifications_demandees update_embarquement_modifications_demandees - embarquement_relance_modifications_demandees - update_embarquement_relance_modifications_demandees embarquement_valide_to_editeur embarquement_valide_to_demandeur_is_tech_is_metier embarquement_valide_to_demandeur_seulement @@ -23,8 +18,6 @@ class APIEntreprise::AuthorizationRequestMailer < APIEntrepriseMailer update_embarquement_valide_to_demandeur demande_recue update_demande_recue - reassurance_demande_recue - update_reassurance_demande_recue ].each do |method| send('define_method', method) do |args| @all_scopes = I18n.t('api_entreprise.tokens.token.scope') diff --git a/app/mailers/api_entreprise/user_mailer.rb b/app/mailers/api_entreprise/user_mailer.rb deleted file mode 100644 index 97150c9b0..000000000 --- a/app/mailers/api_entreprise/user_mailer.rb +++ /dev/null @@ -1,3 +0,0 @@ -class APIEntreprise::UserMailer < APIEntrepriseMailer - include UserMailerCommons -end diff --git a/app/mailers/api_particulier/authorization_request_mailer.rb b/app/mailers/api_particulier/authorization_request_mailer.rb index fd736eb08..be01a15ba 100644 --- a/app/mailers/api_particulier/authorization_request_mailer.rb +++ b/app/mailers/api_particulier/authorization_request_mailer.rb @@ -2,26 +2,18 @@ class APIParticulier::AuthorizationRequestMailer < APIParticulierMailer include ExternalUrlHelper %w[ - embarquement_brouillon_en_attente - update_embarquement_brouillon_en_attente demande_recue update_demande_recue - reassurance_demande_recue - update_reassurance_demande_recue embarquement_demande_refusee embarquement_modifications_demandees - embarquement_relance_modifications_demandees update_embarquement_demande_refusee update_embarquement_modifications_demandees - update_embarquement_relance_modifications_demandees embarquement_valide_to_demandeur_is_tech embarquement_valide_to_demandeur_seulement embarquement_valide_to_tech_cc_demandeur update_embarquement_valide_to_demandeur - - enquete_satisfaction ].each do |method| send('define_method', method) do |args| @all_scopes = I18n.t('api_particulier.tokens.token.scope') diff --git a/app/mailers/api_particulier/reporters_mailer.rb b/app/mailers/api_particulier/reporters_mailer.rb new file mode 100644 index 000000000..cb47bb9dd --- /dev/null +++ b/app/mailers/api_particulier/reporters_mailer.rb @@ -0,0 +1,50 @@ +class APIParticulier::ReportersMailer < APIParticulierMailer + skip_before_action :attach_logos + + helper_method :datapass_v2_public_authorization_request_url + + %w[ + submit + approve + ].each do |event| + define_method(event) do + return if reporters_config.blank? + + groups = params[:groups].map(&:to_sym) + + return if reporter_emails(groups).empty? + + @authorization_request = params[:authorization_request] + + mail( + bcc: reporter_emails(groups), + subject: t('.subject') + ) + end + end + + private + + def datapass_v2_public_authorization_request_url(authorization_request) + "#{datapass_v2_base_url(authorization_request.api)}/public/demandes/#{authorization_request.public_id}" + end + + def datapass_v2_base_url(api) + case Rails.env + when 'staging' + "https://staging.api-#{api}.v2.datapass.api.gouv.fr" + when 'sandbox' + "https://sandbox.api-#{api}.v2.datapass.api.gouv.fr" + else + "https://api-#{api}.v2.datapass.api.gouv.fr" + end + end + + def reporter_emails(groups) + reporters_config.values_at(*groups).flatten + end + + def reporters_config + Rails.application.credentials.api_particulier_reporters + end +end diff --git a/app/mailers/api_particulier/user_mailer.rb b/app/mailers/api_particulier/user_mailer.rb deleted file mode 100644 index 4437d80b6..000000000 --- a/app/mailers/api_particulier/user_mailer.rb +++ /dev/null @@ -1,3 +0,0 @@ -class APIParticulier::UserMailer < APIParticulierMailer - include UserMailerCommons -end diff --git a/app/mailers/concerns/user_mailer_commons.rb b/app/mailers/concerns/user_mailer_commons.rb deleted file mode 100644 index 2486a8121..000000000 --- a/app/mailers/concerns/user_mailer_commons.rb +++ /dev/null @@ -1,27 +0,0 @@ -module UserMailerCommons - include FriendlyDateHelper - - def transfer_ownership(old_owner, new_owner, namespace) - @new_owner = new_owner - @old_owner = old_owner - @login_url = "https://#{api(namespace)}.api.gouv.fr/compte/se-connecter" - @datapass_signup_url = 'https://app.moncomptepro.beta.gouv.fr/users/sign-up' - subject = "#{I18n.t("#{namespace}.name")} - Délégation d'accès" - - mail(to: @new_owner.email, subject:) - end - - def notify_datapass_for_data_reconciliation(user, namespace) - @user = user - @datapass_ids = user.authorization_requests.map(&:external_id).map(&:to_i) - - dest_address = 'datapass@api.gouv.fr' - subject = "#{I18n.t("#{namespace}.name")} - Réconciliation de demandes d'accès à un nouvel usager" - - mail(to: dest_address, subject:) - end - - def api(namespace) - namespace.slice(4..-1) - end -end diff --git a/app/models/abstract_blog_post.rb b/app/models/abstract_blog_post.rb index 2729dffe1..21eae25c8 100644 --- a/app/models/abstract_blog_post.rb +++ b/app/models/abstract_blog_post.rb @@ -21,6 +21,6 @@ def self.all end def self.blog_posts_files - Dir[Rails.root.join('config/blog_posts', api, '*.md')] + Rails.root.glob("config/blog_posts/#{api}/*.md") end end diff --git a/app/models/abstract_endpoint.rb b/app/models/abstract_endpoint.rb index 3180d3a60..eef6cc164 100644 --- a/app/models/abstract_endpoint.rb +++ b/app/models/abstract_endpoint.rb @@ -5,6 +5,7 @@ class AbstractEndpoint < ApplicationAlgoliaSearchableActiveModel attr_accessor :uid, :path, :beta, + :alert, :novelty, :ping_url, :new_version, @@ -20,15 +21,13 @@ class AbstractEndpoint < ApplicationAlgoliaSearchableActiveModel attr_writer :new_endpoint_uids, :old_endpoint_uids algoliasearch_active_model do - attributes :title, :description, :deprecated, :provider_uids, :keywords, :use_cases, :use_cases_optional + attributes :title, :description, :deprecated, :provider_uids, :keywords searchableAttributes %w[ title description provider_uids keywords - use_cases - use_cases_optional ] attributesForFaceting %w[deprecated] diff --git a/app/models/api_entreprise/endpoint.rb b/app/models/api_entreprise/endpoint.rb index 8b947dd84..62dbb5532 100644 --- a/app/models/api_entreprise/endpoint.rb +++ b/app/models/api_entreprise/endpoint.rb @@ -8,7 +8,7 @@ class APIEntreprise::Endpoint < AbstractEndpoint def initialize(params) super - load_dummy_definition! if open_api_definition.blank? || response_schema.blank? || force_dummy_load? + load_dummy_definition! if open_api_definition.blank? || response_schema.blank? end def maintenances @@ -24,7 +24,7 @@ def root_meta end def custom_provider_errors - @custom_provider_errors ||= error_examples('502').reject do |error_payload| + @custom_provider_errors ||= error_examples('502').reject { |error_payload| %w[ 000 051 @@ -34,21 +34,30 @@ def custom_provider_errors 055 999 ].include?(error_payload['code'][2..]) + }.concat(extra_provider_errors).flatten + end + + def extra_provider_errors + all_extra_provider_errors.map do |extra_provider_error| + error_examples(extra_provider_error[:status]).select do |error_payload| + error_payload['code'] == extra_provider_error[:subcode] + end end end - def force_dummy_load? - %w[ - /v3/inpi/unites_legales/{siren}/actes - ].include?(path) + def all_extra_provider_errors + [{ status: '404', subcode: '38422' }] end def load_dummy_definition! - missing_endpoints_definition = I18n.t("api_entreprise.missing_endpoints.#{path}") - raise 'Endpoint(s) not found, check endpoints paths are available in OpenAPI file or in missing_endpoints.yml' if missing_endpoints_definition.nil? + missing_endpoints_definition = I18n.t("api_entreprise.missing_endpoints.#{path}", default: nil) + + raise "Endpoint(s) #{path} not found, check endpoints paths are available in OpenAPI file or in missing_endpoints.yml" if missing_endpoints_definition.nil? @open_api_definition = missing_endpoints_definition.stringify_keys @dummy_definition = true + rescue I18n::MissingTranslationData + raise "There is no #{path} definition in OpenAPI file. Make sure path is valid or add the temporary data in config/locales/*/missing_endpoints.fr.yml" end def dummy? diff --git a/app/models/authorization_request.rb b/app/models/authorization_request.rb index 52dffdee6..d9afc014e 100644 --- a/app/models/authorization_request.rb +++ b/app/models/authorization_request.rb @@ -37,7 +37,7 @@ def self.ransackable_attributes(_) scope :not_archived, -> { where.not(status: 'archived') } scope :archived, -> { where(status: 'archived') } scope :for_api, ->(api) { where(api:) } - scope :viewable_by_users, -> { where(status: %w[archived revoked validated]) } + scope :viewable_by_users, -> { where('status in (?) or validated_at is not null', %w[archived revoked validated]) } def token active_token || most_recent_token @@ -76,6 +76,10 @@ def most_recent_token has_one :contact_technique, through: :contact_technique_authorization_request_role has_one :contact_metier, through: :contact_metier_authorization_request_role + def organization + @organization ||= Organization.new(siret) + end + def contacts_no_demandeur contacts.reject { |user| user == demandeur } end @@ -93,4 +97,9 @@ def revoke! update!(status: 'revoked') end + + def prolong_token_expecting_updates? + token&.last_prolong_token_wizard.present? && + token.last_prolong_token_wizard.requires_update? + end end diff --git a/app/models/organization.rb b/app/models/organization.rb new file mode 100644 index 000000000..d3bb2917f --- /dev/null +++ b/app/models/organization.rb @@ -0,0 +1,37 @@ +class Organization + attr_reader :siret + + def initialize(siret) + @siret = siret + end + + def denomination + unite_legale_insee_payload['denominationUniteLegale'] + end + + def code_commune_etablissement + adresse_etablissement_insee_payload['codeCommuneEtablissement'] + end + + def code_postal_etablissement + adresse_etablissement_insee_payload['codePostalEtablissement'] + end + + private + + def adresse_etablissement_insee_payload + etablissement_insee_payload['adresseEtablissement'] + end + + def etablissement_insee_payload + insee_payload['etablissement'] + end + + def unite_legale_insee_payload + etablissement_insee_payload['uniteLegale'] + end + + def insee_payload + @insee_payload ||= INSEESireneAPIClient.new.etablissement(siret:) + end +end diff --git a/app/models/prolong_token_wizard.rb b/app/models/prolong_token_wizard.rb index 90e96905e..b7b7735a1 100644 --- a/app/models/prolong_token_wizard.rb +++ b/app/models/prolong_token_wizard.rb @@ -4,7 +4,7 @@ class ProlongTokenWizard < ApplicationRecord delegate :prolong!, to: :token delegate :authorization_request, to: :token - enum status: { + enum :status, { owner: 0, project_purpose: 10, contacts: 20, diff --git a/app/organizers/api_entreprise/user/o_auth_login.rb b/app/organizers/api_entreprise/user/o_auth_login.rb index a5b1d1eff..f54a54dd4 100644 --- a/app/organizers/api_entreprise/user/o_auth_login.rb +++ b/app/organizers/api_entreprise/user/o_auth_login.rb @@ -1,5 +1,4 @@ class APIEntreprise::User::OAuthLogin < ApplicationOrganizer organize User::FindOrCreateThroughOAuth, - User::UpdateOAuthAPIGouvId, - User::NotifyDatapassOfTokenOwnership + User::UpdateOAuthAPIGouvId end diff --git a/app/organizers/api_particulier/user/o_auth_login.rb b/app/organizers/api_particulier/user/o_auth_login.rb index c8a825c23..1fa7e24ce 100644 --- a/app/organizers/api_particulier/user/o_auth_login.rb +++ b/app/organizers/api_particulier/user/o_auth_login.rb @@ -1,5 +1,4 @@ class APIParticulier::User::OAuthLogin < ApplicationOrganizer organize User::FindOrCreateThroughOAuth, - User::UpdateOAuthAPIGouvId, - User::NotifyDatapassOfTokenOwnership + User::UpdateOAuthAPIGouvId end diff --git a/app/organizers/datapass_webhook/api_entreprise.rb b/app/organizers/datapass_webhook/api_entreprise.rb index 05933f752..c03305c76 100644 --- a/app/organizers/datapass_webhook/api_entreprise.rb +++ b/app/organizers/datapass_webhook/api_entreprise.rb @@ -10,7 +10,6 @@ class APIEntreprise < ApplicationOrganizer ::DatapassWebhook::ArchivePreviousAuthorizationRequest, ::DatapassWebhook::ArchiveCurrentAuthorizationRequest, ::DatapassWebhook::RefuseCurrentAuthorizationRequest, - ::DatapassWebhook::ReopenAuthorizationRequest, ::DatapassWebhook::RevokeCurrentToken, ::DatapassWebhook::UpdateMailjetContacts, ::DatapassWebhook::ExtractMailjetVariables, diff --git a/app/organizers/datapass_webhook/api_particulier.rb b/app/organizers/datapass_webhook/api_particulier.rb index b3ada3b70..f5328703c 100644 --- a/app/organizers/datapass_webhook/api_particulier.rb +++ b/app/organizers/datapass_webhook/api_particulier.rb @@ -8,6 +8,8 @@ class APIParticulier < ApplicationOrganizer } context.api = 'particulier' + context.authorization_request_data ||= {} + context.modalities = context.authorization_request_data['modalities'].presence || %w[params] end organize ::DatapassWebhook::FindOrCreateUser, @@ -15,10 +17,11 @@ class APIParticulier < ApplicationOrganizer ::DatapassWebhook::CreateOrProlongToken, ::DatapassWebhook::ArchiveCurrentAuthorizationRequest, ::DatapassWebhook::RefuseCurrentAuthorizationRequest, - ::DatapassWebhook::ReopenAuthorizationRequest, ::DatapassWebhook::RevokeCurrentToken, ::DatapassWebhook::UpdateMailjetContacts, + ::DatapassWebhook::ScheduleCreateFormulaireQFResourcesJob, ::DatapassWebhook::ExtractMailjetVariables, - ::DatapassWebhook::ScheduleAuthorizationRequestEmails + ::DatapassWebhook::ScheduleAuthorizationRequestEmails, + ::DatapassWebhook::APIParticulier::NotifyReporters end end diff --git a/app/organizers/datapass_webhook/create_formulaire_qf_resources.rb b/app/organizers/datapass_webhook/create_formulaire_qf_resources.rb new file mode 100644 index 000000000..3d26751cb --- /dev/null +++ b/app/organizers/datapass_webhook/create_formulaire_qf_resources.rb @@ -0,0 +1,18 @@ +class DatapassWebhook::CreateFormulaireQFResources < ApplicationOrganizer + organize DatapassWebhook::APIParticulier::CreateHubEEOrganization, + DatapassWebhook::APIParticulier::CreateHubEESubscription, + DatapassWebhook::APIParticulier::CreateFormulaireQFCollectivity + + around do |interactor| + interactor.call + rescue StandardError => e + Sentry.set_context( + 'DataPass webhook: create FormulaireQF resources', + payload: { + authorization_request_id: context.authorization_request.id + } + ) + + Sentry.capture_exception(e) + end +end diff --git a/app/organizers/user/transfer_account.rb b/app/organizers/user/transfer_account.rb deleted file mode 100644 index fb460975e..000000000 --- a/app/organizers/user/transfer_account.rb +++ /dev/null @@ -1,12 +0,0 @@ -class User::TransferAccount < ApplicationOrganizer - organize User::FindOrCreateNewOwner, - User::TransferTokens, - User::NotifyNewTokensOwner - - after do - Sentry.set_extras( - current_owner_id: context.current_owner.id - ) - Sentry.capture_message('User::TransferAccount completed', level: :info) - end -end diff --git a/app/services/abstract_open_api_definition.rb b/app/services/abstract_open_api_definition.rb index af4aa7686..e2ba766cb 100644 --- a/app/services/abstract_open_api_definition.rb +++ b/app/services/abstract_open_api_definition.rb @@ -38,13 +38,17 @@ def open_api_without_deprecated_paths_definition_content backend.merge('paths' => paths).to_yaml end - # rubocop:disable Security/Open def open_api_definition_content + open_api_remote_url_definition_content(remote_url) + end + + # rubocop:disable Security/Open + def open_api_remote_url_definition_content(url) if load_local? local_path.read else - Rails.cache.fetch(remote_url, expires_in: 1.hour) do - URI.open(remote_url).read + Rails.cache.fetch(url, expires_in: 1.hour) do + URI.open(url).read end end rescue StandardError, OpenURI::HTTPError => e diff --git a/app/services/api_particulier/open_api_definition.rb b/app/services/api_particulier/open_api_definition.rb index 2b949e0c2..cc3e43943 100644 --- a/app/services/api_particulier/open_api_definition.rb +++ b/app/services/api_particulier/open_api_definition.rb @@ -1,10 +1,24 @@ class APIParticulier::OpenAPIDefinition < AbstractOpenAPIDefinition + def open_api_v3_definition_content + open_api_remote_url_definition_content(remote_url_v3) + end + protected def local_path Rails.root.join('config/api-particulier-openapi.yml') end + def remote_url_v3 + if Rails.env.sandbox? + 'https://sandbox.particulier.api.gouv.fr/api/open-api-v3.yml' + elsif Rails.env.staging? || Rails.env.development? + 'https://staging.particulier.api.gouv.fr/api/open-api-v3.yml' + else + 'https://particulier.api.gouv.fr/api/open-api-v3.yml' + end + end + def remote_url if Rails.env.sandbox? 'https://sandbox.particulier.api.gouv.fr/api/open-api.yml' diff --git a/app/services/open_bureau_date.rb b/app/services/open_bureau_date.rb index b20033129..7b9e025a9 100644 --- a/app/services/open_bureau_date.rb +++ b/app/services/open_bureau_date.rb @@ -2,36 +2,48 @@ class OpenBureauDate include DateAndTime::Calculations def next_date + date = next_theoretical_date + + date = date.next_occurring(:tuesday).next_occurring(:tuesday) while cancelled_dates.include?(date) + + date + end + + private + + def next_theoretical_date return Time.zone.today if open_bureau_today? next_tuesday = Time.zone.today.next_occurring(:tuesday) - if first_or_third_in_month?(next_tuesday) - next_tuesday - else - next_tuesday + 7 - end + return next_tuesday if first_or_third_tuesday_in_month?(next_tuesday) + + next_tuesday.next_occurring(:tuesday) end - private + def cancelled_dates + YAML.load_file(Rails.root.join('config/cancelled_open_bureau_dates.yml')).map(&:to_date) + end def open_bureau_today? today = Time.zone.today - today.tuesday? && first_or_third_in_month?(today) && before_open_bureau_time? + today.tuesday? && first_or_third_tuesday_in_month?(today) && before_open_bureau_time? end def before_open_bureau_time? Time.zone.now < '11:00 am'.in_time_zone(Time.zone) end - def first_or_third_in_month?(tuesday) - first_day_month = tuesday.at_beginning_of_month + def first_or_third_tuesday_in_month?(date) + return false unless date.tuesday? + + first_of_month = date.beginning_of_month - return true if first_day_month.tuesday? + first_tuesday = first_of_month + ((2 - first_of_month.wday) % 7) - first_tuesday_after_beginning_month = first_day_month.next_occurring(:tuesday) + third_tuesday = first_tuesday.next_occurring(:tuesday).next_occurring(:tuesday) - first_tuesday_after_beginning_month == tuesday || (first_tuesday_after_beginning_month + 14) == tuesday + date == first_tuesday || date == third_tuesday end end diff --git a/app/services/status_page.rb b/app/services/status_page.rb index 123fce8bd..772464038 100644 --- a/app/services/status_page.rb +++ b/app/services/status_page.rb @@ -32,7 +32,7 @@ def raw_current_status def retrieve_from_status_page status = page_config_data['globals']['topLevelStatus']['status'] - cache.write(cache_key, status, expires_in: 5.minutes.to_i) + cache.write(cache_key, status, expires_in: 60.minutes.to_i) status end @@ -44,7 +44,7 @@ def page_config_data end def page_config_data_body - URI.parse(page_config_data_url).open.read + URI.parse(page_config_data_url).open(open_timeout: 10, read_timeout: 10).read end def page_config_data_url diff --git a/app/views/admin/users/index.html.erb b/app/views/admin/users/index.html.erb index 7248c1159..4926380cd 100644 --- a/app/views/admin/users/index.html.erb +++ b/app/views/admin/users/index.html.erb @@ -79,7 +79,7 @@ <%= button_to 'Se connecter en tant que cet utilisateur', impersonate_admin_user_path(user), data: { turbo: false }, class: 'fr-btn', id: dom_id(user, :impersonate) %> <% end %> - + <% end %> diff --git a/app/views/api_entreprise/authorization_request_mailer/_enquete_satisfaction.html b/app/views/api_entreprise/authorization_request_mailer/_enquete_satisfaction.html deleted file mode 100644 index 4bf09493a..000000000 --- a/app/views/api_entreprise/authorization_request_mailer/_enquete_satisfaction.html +++ /dev/null @@ -1,436 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - -
- - - - - - - -
- - diff --git a/app/views/api_entreprise/authorization_request_mailer/embarquement_relance_modifications_demandees.html.mjml b/app/views/api_entreprise/authorization_request_mailer/embarquement_relance_modifications_demandees.html.mjml deleted file mode 100644 index c7fa80009..000000000 --- a/app/views/api_entreprise/authorization_request_mailer/embarquement_relance_modifications_demandees.html.mjml +++ /dev/null @@ -1,51 +0,0 @@ -<%= render partial: "shared/api_entreprise/mailers/header" %> - - - -

- Votre demande est en attente ⌛️ - elle requiert des - modifications - ✒️ -

-
-
-
- - - - <%= render partial: "greetings", locals: { entity: "demandeur" } %> -

- Nous nous permettons de vous relancer car notre service instructeur n'a pas encore reçu de réponse concernant - les - - demandes de modifications de votre demande d’habilitation API Entreprise n°<%= - @authorization_request.external_id %>. - - Il nous manque ces informations pour rendre un avis.  -

-
- -

- Répondez à notre instructeur depuis l'interface du formulaire - pour soumettre vos modifications et appuyez sur le bouton "Soumettre la demande" : -

-
- Compléter ma demande  🔑 - -

- - <% @authorization_request_datapass_url %> - -

-
- -

- À bientôt 👋 -
- API Entreprise -

-
-
-
-<%= render partial: "shared/api_entreprise/mailers/footer" %> diff --git a/app/views/api_entreprise/authorization_request_mailer/enquete_satisfaction.html.mjml b/app/views/api_entreprise/authorization_request_mailer/enquete_satisfaction.html.mjml deleted file mode 100644 index 5255d17f0..000000000 --- a/app/views/api_entreprise/authorization_request_mailer/enquete_satisfaction.html.mjml +++ /dev/null @@ -1,41 +0,0 @@ -<%= render partial: "shared/api_entreprise/mailers/header" %> - - - -

- Il y a un mois, vous avez reçu votre jeton d'accès à l'API Entreprise, - tout va bien ? -

-
-
-
- - - - <%= render partial: "greetings", locals: { entity: "demandeur" } %> -

- Il y a un mois, vous obteniez un accès 🔑 à l'API Entreprise dans le - cadre d'utilisation "<%= @authorization_request.intitule %>". -

-

- Nous vous envoyons ce mail pour - savoir si tout va bien - . Le questionnaire suivant, vous permettra de nous transmettre - votre avis, vos besoins et vos manques : -

-
-
-
- - - - <%= render partial: "enquete_satisfaction" %> -

- À bientôt 👋 -
- L'équipe API Entreprise -

-
-
-
-<%= render partial: "shared/api_entreprise/mailers/footer" %> diff --git a/app/views/api_entreprise/authorization_request_mailer/reassurance_demande_recue.html.mjml b/app/views/api_entreprise/authorization_request_mailer/reassurance_demande_recue.html.mjml deleted file mode 100644 index 0b65562a9..000000000 --- a/app/views/api_entreprise/authorization_request_mailer/reassurance_demande_recue.html.mjml +++ /dev/null @@ -1,44 +0,0 @@ -<%= render partial: "shared/api_entreprise/mailers/header" %> - - - -

- Votre demande d'accès -
- est en cours de traitement ⚙️ -
- Vous devriez recevoir prochainement une réponse. -

-
-
-
- - - - <%= render partial: "greetings", locals: { entity: "demandeur" } %> -

- - Votre demande d’habilitation API Entreprise n°<%= @authorization_request.external_id %> est en cours de - traitement par notre service juridique. - -
- Vous devriez donc recevoir une réponse de notre part dans les prochains jours. -

-
- -

- 📝 Vous pouvez continuer à consulter et modifier votre demande à tout moment en suivant le lien suivant ➡️ - - <%= @authorization_request_datapass_url %> - -

-
- -

À bientôt 👋

-
- API Entreprise -

-
-
-
-<%= render partial: "shared/api_entreprise/mailers/footer" %> diff --git a/app/views/api_entreprise/authorization_request_mailer/update_embarquement_relance_modifications_demandees.html.mjml b/app/views/api_entreprise/authorization_request_mailer/update_embarquement_relance_modifications_demandees.html.mjml deleted file mode 100644 index 9705f5bf0..000000000 --- a/app/views/api_entreprise/authorization_request_mailer/update_embarquement_relance_modifications_demandees.html.mjml +++ /dev/null @@ -1,43 +0,0 @@ -<%= render partial: "shared/api_entreprise/mailers/header" %> - - - -

- Votre demande de mise à jour est en attente ⌛️ - de modifications - ✒️ -

-
-
-
- - - - <%= render partial: "greetings", locals: { entity: "demandeur" } %> -

- Nous nous permettons de vous relancer car notre service instructeur n'a pas encore reçu de réponse concernant - - les modifications à apporter à votre demande de mise à jour de l'habilitation API Entreprise n°<%= - @authorization_request.external_id %>. - - Il nous manque ces informations pour rendre un avis.  -

-
- Compléter ma demande de mise à jour ✒️ - -

- - <% @authorization_request_datapass_url %> - -

-
- -

- À bientôt 👋 -
- API Entreprise -

-
-
-
-<%= render partial: "shared/api_entreprise/mailers/footer" %> diff --git a/app/views/api_entreprise/authorization_request_mailer/update_reassurance_demande_recue.html.mjml b/app/views/api_entreprise/authorization_request_mailer/update_reassurance_demande_recue.html.mjml deleted file mode 100644 index 02ba8a6f3..000000000 --- a/app/views/api_entreprise/authorization_request_mailer/update_reassurance_demande_recue.html.mjml +++ /dev/null @@ -1,36 +0,0 @@ -<%= render partial: "shared/api_entreprise/mailers/header" %> - - - -

- Votre demande de mise à jour -
- est en cours de traitement ⚙️ -
- Vous devriez recevoir prochainement une réponse. -

-
-
-
- - - - <%= render partial: "greetings", locals: { entity: "demandeur" } %> -

- - Votre demande de mise à jour de l'habilitation API Entreprise n°<%= @authorization_request.external_id %> est en cours de - traitement par notre service juridique. - -
- Vous devriez donc recevoir une réponse de notre part dans les prochains jours. -

-
- -

À bientôt 👋

-
- API Entreprise -

-
-
-
-<%= render partial: "shared/api_entreprise/mailers/footer" %> diff --git a/app/views/api_entreprise/documentation/index.html.erb b/app/views/api_entreprise/documentation/index.html.erb index 0f3ac6f3a..c7e9c5ced 100644 --- a/app/views/api_entreprise/documentation/index.html.erb +++ b/app/views/api_entreprise/documentation/index.html.erb @@ -1,5 +1,5 @@
-
+
<%= render 'menu' %>
diff --git a/app/views/api_entreprise/endpoints/index.html.erb b/app/views/api_entreprise/endpoints/index.html.erb index 26479f7db..bdb3545f0 100644 --- a/app/views/api_entreprise/endpoints/index.html.erb +++ b/app/views/api_entreprise/endpoints/index.html.erb @@ -1,4 +1,4 @@ -
data-algolia-search-catalogue-index-value="APIEntreprise_Endpoint" data-algolia-search-catalogue-attributes-to-highlight-value='["title", "description"]'> +
data-algolia-search-catalogue-index-value="APIEntreprise_Endpoint" data-algolia-search-catalogue-attributes-to-highlight-value='["title", "description"]'>