diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index 32997e0..1cea344 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -2,5 +2,8 @@ version: '3.8' services: # Update this to the name of the service you want to work with in your docker-compose.yml file app: + environment: + EDITOR: code + SHELL: fish command: /bin/sh -c "while sleep 1000; do :; done" diff --git a/.dockerignore b/.dockerignore index 066cd7a..36170e5 100644 --- a/.dockerignore +++ b/.dockerignore @@ -39,4 +39,5 @@ /Dockerfile /docker-compose.yml -/.forgejo/ \ No newline at end of file +/.forgejo/ +/core* diff --git a/.forgejo/workflows/ci_cd.yml b/.forgejo/workflows/ci_cd.yml index 0f17daa..b43fc55 100644 --- a/.forgejo/workflows/ci_cd.yml +++ b/.forgejo/workflows/ci_cd.yml @@ -66,7 +66,7 @@ jobs: path: repository key: ${{ runner.os }}-repository-${{ github.sha }} restore-keys: | - ${{ runner.os }}-repository- + ${{ runner.os }}-repository - name: Checkout repository uses: actions/checkout@v4 with: diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index f33a02c..0000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,12 +0,0 @@ -# To get started with Dependabot version updates, you'll need to specify which -# package ecosystems to update and where the package manifests are located. -# Please see the documentation for more information: -# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates -# https://containers.dev/guide/dependabot - -version: 2 -updates: - - package-ecosystem: "devcontainers" - directory: "/" - schedule: - interval: weekly diff --git a/.rubocop.yml b/.rubocop.yml index 25b6323..466c8dd 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,3 +1,6 @@ +inherit_gem: + rubocop-rails-omakase: rubocop.yml + require: - rubocop-capybara - rubocop-rails diff --git a/.vscode/launch.json b/.vscode/launch.json index dda0271..a2f99f9 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,18 +10,5 @@ "request": "attach", "preLaunchTask": "dev" }, - { - "type": "ruby_lsp", - "name": "Debug script", - "request": "launch", - "program": "ruby ${file}" - }, - { - "type": "ruby_lsp", - "name": "Debug test", - "request": "launch", - "program": "ruby -Itest ${relativeFile}" - }, - ] } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 2b3522d..1f77ccb 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -2,10 +2,21 @@ "version": "2.0.0", "tasks": [ { - "type": "shell", + "type": "process", + "presentation": { + "echo": true, + "reveal": "silent", + "focus": false, + "panel": "dedicated", + "showReuseMessage": true, + "clear": false, + "revealProblems": "always", + "group": "dev", + "close": true + }, "command": "dev", "label": "dev", - "isBackground": true + "isBackground": true, } ] } \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 9f587ba..949012b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -47,7 +47,7 @@ RUN \ echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \ apt-get update -yqq && \ apt-get install -yqq --no-install-recommends \ - sqlite3 nodejs npm sassc yarn libvips fish ranger pandoc && \ + sqlite3 nodejs npm sassc yarn libvips fish ranger pandoc libjemalloc2 && \ apt-get clean && \ npm install tabby-agent && \ rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \ @@ -55,26 +55,23 @@ RUN \ gem update --system && \ bundle config set app_config ${GEM_HOME} +ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 + USER ${NAME} -FROM development AS builder +RUN mkdir -p ~/.config/fish && echo "set fish_greeting" >> ~/.config/fish/config.fish +RUN \ + echo >> ~/.config/fish/config.fish &&\ + echo "function fish_prompt" >> ~/.config/fish/config.fish &&\ + echo " set -l last_status \$status" >> ~/.config/fish/config.fish &&\ + echo " set -l stat" >> ~/.config/fish/config.fish &&\ + echo " if test \$last_status -ne 0" >> ~/.config/fish/config.fish &&\ + echo " set stat (set_color red)\"[\$last_status]\"(set_color normal)" >> ~/.config/fish/config.fish &&\ + echo " end" >> ~/.config/fish/config.fish &&\ + echo " string join '' -- (set_color green) (prompt_pwd) (set_color normal) \$stat ' 🐳 '" >> ~/.config/fish/config.fish && \ + echo "end" >> ~/.config/fish/config.fish -USER root - -COPY Gemfile Gemfile.lock package.json yarn.lock ./ - -RUN bundle install && yarn install - -FROM builder AS assets - -COPY . . - -COPY --from=builder /app/.bundle /app/.bundle -COPY --from=builder /app/node_modules /app/node_modules - -RUN RAILS_ENV=production SECRET_KEY_BASE_DUMMY=1 rails assets:precompile - -FROM ruby:${RUBY_VERSION}-slim AS production +FROM ruby:${RUBY_VERSION}-alpine AS builder ARG NAME ARG UID @@ -84,50 +81,111 @@ ARG INSTALL_DIR WORKDIR ${INSTALL_DIR} +ENV GEM_HOME=${INSTALL_DIR}/.bundle + ENV \ LANG=C.UTF-8 \ INSTALL_DIR=${INSTALL_DIR} \ - RAILS_ENV=production \ + RAILS_ENV=development \ TZ=Europe/Zurich \ - PATH=${INSTALL_DIR}/bin:$GEM_HOME/bin:$GEM_HOME/gems/bin:$PATH + PATH=${INSTALL_DIR}/bin:$GEM_HOME/bin:$GEM_HOME/gems/bin:$PATH \ + EDITOR=vim -ENV GEM_HOME=${INSTALL_DIR}/.bundle - -RUN \ - ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \ - echo $TZ > /etc/timezone && \ - addgroup --gid ${GID} ${NAME} && \ - adduser \ - --gecos GECOS \ - --home /home/${NAME} \ - --uid ${UID} \ - --gid ${GID} \ - --disabled-password \ - --disabled-login \ - --shell /bin/bash \ - ${NAME} && \ - apt-get update -yqq && \ - apt-get install -yqq --no-install-recommends \ - sqlite3 libvips pandoc && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* && \ +RUN apk add --update --no-cache \ + binutils-gold \ + build-base \ + curl \ + file \ + g++ \ + gcc \ + git \ + less \ + libstdc++ \ + libffi-dev \ + libc-dev \ + linux-headers \ + libxml2-dev \ + libxslt-dev \ + libgcrypt-dev \ + make \ + netcat-openbsd \ + nodejs \ + openssl \ + pkgconfig \ + tzdata \ + yarn \ + sqlite \ + vips-dev \ + npm \ + sassc \ + jemalloc \ + pandoc-cli \ + sqlite-libs \ + build-base && \ truncate -s 0 /var/log/*log && \ gem update --system && \ bundle config set app_config ${GEM_HOME} -EXPOSE 3000 +ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.2 -ENTRYPOINT [ "bin/entrypoint" ] +USER ${NAME} + +USER root + +COPY Gemfile Gemfile.lock package.json yarn.lock ./ + +RUN bundle config without test development && bundle install && yarn install + +FROM builder AS assets COPY . . -COPY --from=builder /app/.bundle /app/.bundle -COPY --from=assets /app/public/assets /app/public/assets +COPY --from=builder ${INSTALL_DIR}/.bundle ${INSTALL_DIR}/.bundle +COPY --from=builder ${INSTALL_DIR}/node_modules ${INSTALL_DIR}/node_modules -RUN chown -R app:app /app/tmp /app/log /app/storage -RUN date +"%Y-%m-%d %H:%M:%S %Z" >> .build_version +RUN RAILS_ENV=production SECRET_KEY_BASE_DUMMY=1 rails assets:precompile + +FROM ruby:${RUBY_VERSION}-alpine AS production + +ARG INSTALL_DIR +ARG NAME + +WORKDIR ${INSTALL_DIR} + +ENV GEM_HOME=${INSTALL_DIR}/.bundle + +ENV \ + RAILS_ENV=production \ + PATH=${INSTALL_DIR}/bin:$GEM_HOME/bin:$GEM_HOME/gems/bin:$PATH \ + TZ=Europe/Zurich + +RUN \ + adduser ${NAME} --disabled-password --shell /bin/ash && \ + apk add --update --no-cache \ + tzdata \ + sqlite \ + vips-dev \ + jemalloc && \ + gem update --system && \ + bundle config set app_config ${GEM_HOME} && \ + bundle config set without development test && \ + apk add patchelf && \ + patchelf --add-needed libjemalloc.so.2 /usr/local/bin/ruby && \ + apk del patchelf && \ + truncate -s 0 /var/log/*log + +EXPOSE 3000 + +COPY . . + +COPY --from=builder ${INSTALL_DIR}/.bundle ${INSTALL_DIR}/.bundle +COPY --from=assets ${INSTALL_DIR}/public/assets ${INSTALL_DIR}/public/assets + +RUN chown -R ${NAME}:${NAME} ${INSTALL_DIR}/tmp ${INSTALL_DIR}/log ${INSTALL_DIR}/storage && \ + date +"%Y-%m-%d %H:%M:%S %Z" >> .build_version + +USER ${NAME} + +ENTRYPOINT [ "bin/entrypoint" ] -USER app -# Using variables in command list is not possible: -# https://stackoverflow.com/questions/40454470/how-can-i-use-a-variable-inside-a-dockerfile-cmd CMD [ "rails", "server", "--binding", "0.0.0.0", "--no-daemon", "--port" , "3000" ] diff --git a/Gemfile b/Gemfile index 95e2e4e..fd56b94 100644 --- a/Gemfile +++ b/Gemfile @@ -1,35 +1,36 @@ # frozen_string_literal: true -source 'https://rubygems.org' +source "https://rubygems.org" -ruby '3.3.4' +ruby "3.3.4" # Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main" -gem 'rails', '~> 7.1.3', '>= 7.1.3.4' +gem "rails", "~> 7.2" # The original asset pipeline for Rails [https://github.com/rails/sprockets-rails] -gem 'sprockets-rails' +gem "sprockets-rails" # Use sqlite3 as the database for Active Record -gem 'sqlite3', '~> 1.4' +# gem "sqlite3", "~> 1.4" +gem "sqlite3", ">= 2.0" # Use the Puma web server [https://github.com/puma/puma] -gem 'puma', '>= 5.0' +gem "puma", ">= 5.0" # Bundle and transpile JavaScript [https://github.com/rails/jsbundling-rails] -gem 'jsbundling-rails' +gem "jsbundling-rails" # Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev] -gem 'turbo-rails' +gem "turbo-rails" # Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev] -gem 'stimulus-rails' +gem "stimulus-rails" # Bundle and process CSS [https://github.com/rails/cssbundling-rails] -gem 'cssbundling-rails' +gem "cssbundling-rails" # Build JSON APIs with ease [https://github.com/rails/jbuilder] -gem 'jbuilder' +gem "jbuilder" # Use Redis adapter to run Action Cable in production # gem "redis", ">= 4.0.1" @@ -41,45 +42,50 @@ gem 'jbuilder' # gem "bcrypt", "~> 3.1.7" # Windows does not include zoneinfo files, so bundle the tzinfo-data gem -gem 'tzinfo-data', platforms: %i[windows jruby] +gem "tzinfo-data", platforms: %i[windows jruby] # Reduces boot times through caching; required in config/boot.rb -gem 'bootsnap', require: false +gem "bootsnap", require: false # Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images] -gem 'bootstrap_form' -gem 'caxlsx' -gem 'caxlsx_rails' -gem 'image_processing', '~> 1.2' -gem 'pagy', '~> 9.0' -gem 'pandoc-ruby' -gem 'prawn-markup' -gem 'prawn-rails' -gem 'sablon' +gem "bootstrap_form" +gem "caxlsx" +gem "caxlsx_rails" +gem "image_processing", "~> 1.2" +gem "openxml-docx" +gem "pagy", "~> 9.0" +gem "pandoc-ruby" +gem "prawn-markup" +gem "prawn-rails" +gem "sablon" +gem "activerecord-enhancedsqlite3-adapter" +gem "slim" group :development, :test do # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem - gem 'debug', platforms: %i[mri windows] + gem "debug", platforms: %i[mri windows] end group :development do # Use console on exceptions pages [https://github.com/rails/web-console] - gem 'web-console' + gem "web-console" # Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler] # gem "rack-mini-profiler" # Speed up commands on slow machines / big apps [https://github.com/rails/spring] # gem "spring" - gem 'rubocop' - gem 'rubocop-capybara' - gem 'rubocop-rails' - gem 'ruby-lsp' - gem 'ruby-lsp-rails' + gem "brakeman" + gem "rubocop" + gem "rubocop-capybara" + gem "rubocop-rails" + gem "rubocop-rails-omakase", require: false + gem "ruby-lsp" + gem "ruby-lsp-rails" end group :test do # Use system testing [https://guides.rubyonrails.org/testing.html#system-testing] - gem 'capybara' - gem 'selenium-webdriver' + gem "capybara" + gem "selenium-webdriver" end diff --git a/Gemfile.lock b/Gemfile.lock index ee0de82..975d209 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,80 +1,79 @@ GEM remote: https://rubygems.org/ specs: - actioncable (7.1.3.4) - actionpack (= 7.1.3.4) - activesupport (= 7.1.3.4) + actioncable (7.2.0) + actionpack (= 7.2.0) + activesupport (= 7.2.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 (7.2.0) + actionpack (= 7.2.0) + activejob (= 7.2.0) + activerecord (= 7.2.0) + activestorage (= 7.2.0) + activesupport (= 7.2.0) + mail (>= 2.8.0) + actionmailer (7.2.0) + actionpack (= 7.2.0) + actionview (= 7.2.0) + activejob (= 7.2.0) + activesupport (= 7.2.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 (7.2.0) + actionview (= 7.2.0) + activesupport (= 7.2.0) nokogiri (>= 1.8.5) racc - rack (>= 2.2.4) + rack (>= 2.2.4, < 3.2) 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 (7.2.0) + actionpack (= 7.2.0) + activerecord (= 7.2.0) + activestorage (= 7.2.0) + activesupport (= 7.2.0) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.1.3.4) - activesupport (= 7.1.3.4) + actionview (7.2.0) + activesupport (= 7.2.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 (7.2.0) + activesupport (= 7.2.0) globalid (>= 0.3.6) - activemodel (7.1.3.4) - activesupport (= 7.1.3.4) - activerecord (7.1.3.4) - activemodel (= 7.1.3.4) - activesupport (= 7.1.3.4) + activemodel (7.2.0) + activesupport (= 7.2.0) + activerecord (7.2.0) + activemodel (= 7.2.0) + activesupport (= 7.2.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) + activerecord-enhancedsqlite3-adapter (0.8.0) + activerecord (>= 7.1) + sqlite3 (>= 1.6) + activestorage (7.2.0) + actionpack (= 7.2.0) + activejob (= 7.2.0) + activerecord (= 7.2.0) + activesupport (= 7.2.0) marcel (~> 1.0) - activesupport (7.1.3.4) + activesupport (7.2.0) base64 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) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) addressable (2.8.7) public_suffix (>= 2.0.2, < 7.0) ast (2.4.2) @@ -86,6 +85,8 @@ GEM bootstrap_form (5.4.0) actionpack (>= 6.1) activemodel (>= 6.1) + brakeman (6.1.2) + racc builder (3.3.0) capybara (3.40.0) addressable @@ -155,7 +156,6 @@ GEM mini_mime (1.1.5) minitest (5.24.1) msgpack (1.7.2) - mutex_m (0.2.0) net-imap (0.4.14) date net-protocol @@ -178,6 +178,19 @@ GEM racc (~> 1.4) nokogiri (1.16.6-x86_64-linux) racc (~> 1.4) + openxml-docx (0.11.5) + nokogiri + openxml-drawingml + openxml-package (>= 0.2.2) + ox (~> 2.9) + openxml-drawingml (0.3.1) + nokogiri + openxml-package (~> 0.3.2) + openxml-package (0.3.4) + nokogiri + ox + rubyzip + ox (2.14.18) pagy (9.0.2) pandoc-ruby (2.1.10) parallel (1.25.1) @@ -214,20 +227,20 @@ GEM rackup (2.1.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 (7.2.0) + actioncable (= 7.2.0) + actionmailbox (= 7.2.0) + actionmailer (= 7.2.0) + actionpack (= 7.2.0) + actiontext (= 7.2.0) + actionview (= 7.2.0) + activejob (= 7.2.0) + activemodel (= 7.2.0) + activerecord (= 7.2.0) + activestorage (= 7.2.0) + activesupport (= 7.2.0) bundler (>= 1.15.0) - railties (= 7.1.3.4) + railties (= 7.2.0) rails-dom-testing (2.2.0) activesupport (>= 5.0.0) minitest @@ -235,10 +248,10 @@ GEM rails-html-sanitizer (1.6.0) loofah (~> 2.21) nokogiri (~> 1.14) - railties (7.1.3.4) - actionpack (= 7.1.3.4) - activesupport (= 7.1.3.4) - irb + railties (7.2.0) + actionpack (= 7.2.0) + activesupport (= 7.2.0) + irb (~> 1.13) rackup (>= 1.0.0) rake (>= 12.2) thor (~> 1.0, >= 1.2.2) @@ -252,7 +265,7 @@ GEM regexp_parser (2.9.2) reline (0.5.9) io-console (~> 0.5) - rexml (3.3.1) + rexml (3.3.2) strscan rubocop (1.65.0) json (~> 2.3) @@ -269,11 +282,22 @@ GEM parser (>= 3.3.1.0) rubocop-capybara (2.21.0) rubocop (~> 1.41) + rubocop-minitest (0.35.1) + rubocop (>= 1.61, < 2.0) + rubocop-ast (>= 1.31.1, < 2.0) + rubocop-performance (1.21.1) + rubocop (>= 1.48.1, < 2.0) + rubocop-ast (>= 1.31.1, < 2.0) rubocop-rails (2.25.1) activesupport (>= 4.2.0) rack (>= 1.1) rubocop (>= 1.33.0, < 2.0) rubocop-ast (>= 1.31.1, < 2.0) + rubocop-rails-omakase (1.0.0) + rubocop + rubocop-minitest + rubocop-performance + rubocop-rails ruby-lsp (0.17.7) language_server-protocol (~> 3.17.0) prism (>= 0.29.0, < 0.31) @@ -288,12 +312,16 @@ GEM sablon (0.4.1) nokogiri (>= 1.8.5) rubyzip (>= 1.3.0) - selenium-webdriver (4.22.0) + securerandom (0.3.1) + selenium-webdriver (4.23.0) base64 (~> 0.2) logger (~> 1.4) rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) websocket (~> 1.0) + slim (5.2.1) + temple (~> 0.10.0) + tilt (>= 2.1.0) sorbet-runtime (0.5.11481) sprockets (4.2.1) concurrent-ruby (~> 1.0) @@ -302,17 +330,19 @@ GEM actionpack (>= 6.1) activesupport (>= 6.1) sprockets (>= 3.0.0) - sqlite3 (1.7.3-aarch64-linux) - sqlite3 (1.7.3-arm-linux) - sqlite3 (1.7.3-arm64-darwin) - sqlite3 (1.7.3-x86-linux) - sqlite3 (1.7.3-x86_64-darwin) - sqlite3 (1.7.3-x86_64-linux) + sqlite3 (2.0.3-aarch64-linux-gnu) + sqlite3 (2.0.3-arm-linux-gnu) + sqlite3 (2.0.3-arm64-darwin) + sqlite3 (2.0.3-x86-linux-gnu) + sqlite3 (2.0.3-x86_64-darwin) + sqlite3 (2.0.3-x86_64-linux-gnu) stimulus-rails (1.3.3) railties (>= 6.0.0) stringio (3.1.1) strscan (3.1.0) + temple (0.10.3) thor (1.3.1) + tilt (2.4.0) timeout (0.4.1) ttfunk (1.8.0) bigdecimal (~> 3.1) @@ -323,6 +353,7 @@ GEM tzinfo (2.0.6) concurrent-ruby (~> 1.0) unicode-display_width (2.5.0) + useragent (0.16.10) web-console (4.2.1) actionview (>= 6.0.0) activemodel (>= 6.0.0) @@ -346,8 +377,10 @@ PLATFORMS x86_64-linux DEPENDENCIES + activerecord-enhancedsqlite3-adapter bootsnap bootstrap_form + brakeman capybara caxlsx caxlsx_rails @@ -356,21 +389,24 @@ DEPENDENCIES image_processing (~> 1.2) jbuilder jsbundling-rails + openxml-docx pagy (~> 9.0) pandoc-ruby prawn-markup prawn-rails puma (>= 5.0) - rails (~> 7.1.3, >= 7.1.3.4) + rails (~> 7.2) rubocop rubocop-capybara rubocop-rails + rubocop-rails-omakase ruby-lsp ruby-lsp-rails sablon selenium-webdriver + slim sprockets-rails - sqlite3 (~> 1.4) + sqlite3 (>= 2.0) stimulus-rails turbo-rails tzinfo-data diff --git a/app/assets/stylesheets/application.bootstrap.scss b/app/assets/stylesheets/application.bootstrap.scss index 2983d77..727a354 100644 --- a/app/assets/stylesheets/application.bootstrap.scss +++ b/app/assets/stylesheets/application.bootstrap.scss @@ -115,6 +115,4 @@ $enable-rounded: false; overflow-y: auto; } */ - - @import "./layout"; \ No newline at end of file diff --git a/app/controllers/admin/backups_controller.rb b/app/controllers/admin/backups_controller.rb index 65dcf87..6b501e0 100644 --- a/app/controllers/admin/backups_controller.rb +++ b/app/controllers/admin/backups_controller.rb @@ -1,8 +1,10 @@ +# frozen_string_literal: true + module Admin class BackupsController < ApplicationController # GET /admin/backups/1 def show - send_file Backup.db_xlsx, filename: 'backup.xlsx', disposition: :attachment + send_file Backup.db_xlsx, filename: "backup.xlsx", disposition: :attachment end end end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index de00ee8..e99f4ce 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -3,20 +3,24 @@ class ApplicationController < ActionController::Base include Pagy::Backend + # allow_browser versions: :modern + before_action :initialize_navbar private def initialize_navbar - @nav_path = controller_name + return unless request.get? + @navbar_items = [ - { label: 'Dashboard', icon: :speedometer2, path: :root }, - { label: Report.model_name.human(count: 2), icon: :'journal-text', path: :reports }, - { label: Checklist.model_name.human(count: 2), icon: :'list-check', path: :checklists }, - { label: Check.model_name.human(count: 2), icon: :check2, path: :checks }, - { label: Link.model_name.human(count: 2), icon: :link, path: :links }, - { label: LinkCategory.model_name.human(count: 2), icon: :"folder", path: :link_categories } + { label: "Dashboard", icon: :speedometer2, path: :root }, + { label: Report.model_name.human(count: 2), icon: :'journal-text', path: :reports }, + { label: Checklist.model_name.human(count: 2), icon: :'list-check', path: :checklists }, + { label: Check.model_name.human(count: 2), icon: :check2, path: :checks }, + { label: Link.model_name.human(count: 2), icon: :link, path: :links }, + { label: LinkCategory.model_name.human(count: 2), icon: :folder, path: :link_categories } ] - @search_url = nil # root_url + @nav_path = controller_name + @search_url = nil end end diff --git a/app/controllers/benchmarking_controller.rb b/app/controllers/benchmarking_controller.rb new file mode 100644 index 0000000..353fc55 --- /dev/null +++ b/app/controllers/benchmarking_controller.rb @@ -0,0 +1,213 @@ +class BenchmarkingController < ApplicationController + protect_from_forgery with: :null_session + before_action :set_user_update_last_seen_at + + # POST /benchmarking/read_heavy + def read_heavy + act_and_respond( + link_create: 0.1, + link_destroy: 0.1, + link_show: 0.4, + links_index: 0.4, + ) + end + + # POST /benchmarking/write_heavy + def write_heavy + act_and_respond( + link_create: 0.4, + link_destroy: 0.4, + link_show: 0.1, + links_index: 0.1, + ) + end + + # POST /benchmarking/balanced + def balanced + act_and_respond( + link_create: 0.25, + link_destroy: 0.25, + link_show: 0.25, + links_index: 0.25, + ) + end + + def link_create + link = LinkCategory.create!(name: "Benchmark #{request.uuid}", description_html: "
#{format(request:)}")
+ redirect_to link
+ end
+
+ def link_destroy
+ link = LinkCategory.where("id >= ?", rand(LinkCategory.minimum(:id)..LinkCategory.maximum(:id))).limit(1).first
+ link.destroy!
+ redirect_to links_path
+ end
+
+ def link_show
+ @link_category = LinkCategory.where("id >= ?", rand(LinkCategory.minimum(:id)..LinkCategory.maximum(:id))).limit(1).first
+ render "link_categories/show", status: :ok
+ end
+
+ def links_index
+ @link_categories = LinkCategory.where("id >= ?", rand(LinkCategory.minimum(:id)..LinkCategory.maximum(:id))).limit(100)
+ render "link_categories/index", status: :ok
+ end
+
+ private
+
+ def set_user_update_last_seen_at
+ # @user = User.where("id >= ?", rand(User.minimum(:id)..User.maximum(:id))).limit(1).first
+ # @user.update!(last_seen_at: Time.now)
+ end
+
+ def act_and_respond(actions_with_weighted_distribution)
+ action = actions_with_weighted_distribution.max_by { |_, weight| rand ** (1.0 / weight) }.first
+
+ send(action)
+ end
+
+ def format(request:)
+ request.headers.to_h.slice(
+ "GATEWAY_INTERFACE",
+ "HTTP_ACCEPT",
+ "HTTP_HOST",
+ "HTTP_USER_AGENT",
+ "HTTP_VERSION",
+ "ORIGINAL_FULLPATH",
+ "ORIGINAL_SCRIPT_NAME",
+ "PATH_INFO",
+ "QUERY_STRING",
+ "REMOTE_ADDR",
+ "REQUEST_METHOD",
+ "REQUEST_PATH",
+ "REQUEST_URI",
+ "SCRIPT_NAME",
+ "SERVER_NAME",
+ "SERVER_PORT",
+ "SERVER_PROTOCOL",
+ "SERVER_SOFTWARE",
+ "action_dispatch.request_id",
+ "puma.request_body_wait",
+ ).map { _1.join(": ") }.join("\n")
+ end
+end
+
+# class BenchmarkingController < ApplicationController
+# skip_before_action :verify_authenticity_token
+# skip_before_action :ensure_user_authenticated!
+# before_action :set_user_update_last_seen_at
+
+# # POST /benchmarking/read_heavy
+# def read_heavy
+# act_and_respond(
+# link_create: 0.10,
+# comment_create: 0.10,
+# post_destroy: 0.02,
+# comment_destroy: 0.03,
+# post_show: 0.25,
+# posts_index: 0.25,
+# user_show: 0.25,
+# )
+# end
+
+# # POST /benchmarking/write_heavy
+# def write_heavy
+# act_and_respond(
+# link_create: 0.25,
+# comment_create: 0.25,
+# post_destroy: 0.05,
+# comment_destroy: 0.20,
+# post_show: 0.05,
+# posts_index: 0.15,
+# user_show: 0.05,
+# )
+# end
+
+# # POST /benchmarking/balanced
+# def balanced
+# act_and_respond(
+# link_create: 0.17,
+# comment_create: 0.17,
+# post_destroy: 0.05,
+# comment_destroy: 0.11,
+# post_show: 0.17,
+# posts_index: 0.17,
+# user_show: 0.16,
+# )
+# end
+
+# def link_create
+# post = Post.create!(user: @user, title: "Post #{request.uuid}", description: format(request:))
+# redirect_to post
+# end
+
+# def comment_create
+# post = Post.where("id >= ?", rand(Post.minimum(:id)..Post.maximum(:id))).limit(1).first
+# comment = Comment.create!(user: @user, post: post, body: "Comment #{request.uuid}")
+# redirect_to comment.post
+# end
+
+# def post_destroy
+# post = Post.where("id >= ?", rand(Post.minimum(:id)..Post.maximum(:id))).limit(1).first
+# post.destroy!
+# redirect_to posts_path
+# end
+
+# def comment_destroy
+# comment = Comment.where("id >= ?", rand(Comment.minimum(:id)..Comment.maximum(:id))).limit(1).first
+# comment.destroy!
+# redirect_to comment.post
+# end
+
+# def post_show
+# @post = Post.where("id >= ?", rand(Post.minimum(:id)..Post.maximum(:id))).limit(1).first
+# render "posts/show", status: :ok
+# end
+
+# def posts_index
+# @posts = Post.where("id >= ?", rand(Post.minimum(:id)..Post.maximum(:id))).limit(100)
+# render "posts/index", status: :ok
+# end
+
+# def user_show
+# render "users/show", status: :ok
+# end
+
+# private
+
+# def set_user_update_last_seen_at
+# @user = User.where("id >= ?", rand(User.minimum(:id)..User.maximum(:id))).limit(1).first
+# @user.update!(last_seen_at: Time.now)
+# end
+
+# def act_and_respond(actions_with_weighted_distribution)
+# action = actions_with_weighted_distribution.max_by { |_, weight| rand ** (1.0 / weight) }.first
+
+# send(action)
+# end
+
+# def format(request:)
+# request.headers.to_h.slice(
+# "GATEWAY_INTERFACE",
+# "HTTP_ACCEPT",
+# "HTTP_HOST",
+# "HTTP_USER_AGENT",
+# "HTTP_VERSION",
+# "ORIGINAL_FULLPATH",
+# "ORIGINAL_SCRIPT_NAME",
+# "PATH_INFO",
+# "QUERY_STRING",
+# "REMOTE_ADDR",
+# "REQUEST_METHOD",
+# "REQUEST_PATH",
+# "REQUEST_URI",
+# "SCRIPT_NAME",
+# "SERVER_NAME",
+# "SERVER_PORT",
+# "SERVER_PROTOCOL",
+# "SERVER_SOFTWARE",
+# "action_dispatch.request_id",
+# "puma.request_body_wait",
+# ).map { _1.join(": ") }.join("\n")
+# end
+# end
diff --git a/app/controllers/checklist_entries_controller.rb b/app/controllers/checklist_entries_controller.rb
index c0f7de4..10ac787 100644
--- a/app/controllers/checklist_entries_controller.rb
+++ b/app/controllers/checklist_entries_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class ChecklistEntriesController < ApplicationController
before_action :set_checklist_entry, only: %i[show edit update destroy]
@@ -7,8 +9,7 @@ class ChecklistEntriesController < ApplicationController
end
# GET /checklist_entries/1
- def show
- end
+ def show; end
# GET /checklist_entries/new
def new
@@ -16,15 +17,14 @@ class ChecklistEntriesController < ApplicationController
end
# GET /checklist_entries/1/edit
- def edit
- end
+ def edit; end
# POST /checklist_entries
def create
@checklist_entry = ChecklistEntry.new(checklist_entry_params)
if @checklist_entry.save
- redirect_to @checklist_entry.checklist, notice: 'Checklist entry was successfully created.'
+ redirect_to @checklist_entry.checklist, notice: "Checklist entry was successfully created."
else
render :new, status: :unprocessable_entity
end
@@ -33,7 +33,7 @@ class ChecklistEntriesController < ApplicationController
# PATCH/PUT /checklist_entries/1
def update
if @checklist_entry.update(checklist_entry_params)
- redirect_to @checklist_entry.checklist, notice: 'Checklist entry was successfully updated.',
+ redirect_to @checklist_entry.checklist, notice: "Checklist entry was successfully updated.",
status: :see_other
else
render :edit, status: :unprocessable_entity
@@ -45,7 +45,7 @@ class ChecklistEntriesController < ApplicationController
@checklist_entry.destroy!
respond_to do |format|
format.html do
- redirect_to checklist_entries_url, notice: 'Checklist entry was successfully destroyed.', status: :see_other
+ redirect_to checklist_entries_url, notice: "Checklist entry was successfully destroyed.", status: :see_other
end
format.turbo_stream
end
diff --git a/app/controllers/checklists_controller.rb b/app/controllers/checklists_controller.rb
index 02a20b8..89f1973 100644
--- a/app/controllers/checklists_controller.rb
+++ b/app/controllers/checklists_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class ChecklistsController < ApplicationController
before_action :set_checklist, only: %i[show edit update destroy]
@@ -7,8 +9,7 @@ class ChecklistsController < ApplicationController
end
# GET /checklists/1
- def show
- end
+ def show; end
# GET /checklists/new
def new
@@ -16,15 +17,14 @@ class ChecklistsController < ApplicationController
end
# GET /checklists/1/edit
- def edit
- end
+ def edit; end
# POST /checklists
def create
@checklist = Checklist.new(checklist_params)
if @checklist.save
- redirect_to @checklist, notice: 'Checklist was successfully created.'
+ redirect_to @checklist, notice: "Checklist was successfully created."
else
render :new, status: :unprocessable_entity
end
@@ -33,7 +33,7 @@ class ChecklistsController < ApplicationController
# PATCH/PUT /checklists/1
def update
if @checklist.update(checklist_params)
- redirect_to @checklist, notice: 'Checklist was successfully updated.', status: :see_other
+ redirect_to @checklist, notice: "Checklist was successfully updated.", status: :see_other
else
render :edit, status: :unprocessable_entity
end
@@ -42,7 +42,7 @@ class ChecklistsController < ApplicationController
# DELETE /checklists/1
def destroy
@checklist.destroy!
- redirect_to checklists_url, notice: 'Checklist was successfully destroyed.', status: :see_other
+ redirect_to checklists_url, notice: "Checklist was successfully destroyed.", status: :see_other
end
private
diff --git a/app/controllers/checks_controller.rb b/app/controllers/checks_controller.rb
index 90c7a88..4b8669a 100644
--- a/app/controllers/checks_controller.rb
+++ b/app/controllers/checks_controller.rb
@@ -1,14 +1,19 @@
+# frozen_string_literal: true
+
class ChecksController < ApplicationController
before_action :set_check, only: %i[show edit update destroy]
# GET /checks or /checks.json
def index
- @pagy, @checks = pagy(Check.search(filter_params[:s]))
+ @pagy, @checks = if filter_params[:s]
+ pagy(Check.search(filter_params[:s]).order(:conformity_level))
+ else
+ pagy(Check.all.order(:conformity_level))
+ end
end
# GET /checks/1 or /checks/1.json
- def show
- end
+ def show; end
# GET /checks/new
def new
@@ -16,8 +21,7 @@ class ChecksController < ApplicationController
end
# GET /checks/1/edit
- def edit
- end
+ def edit; end
# POST /checks or /checks.json
def create
@@ -27,11 +31,11 @@ class ChecksController < ApplicationController
if @check.save
format.html do
redirect_to check_url(@check),
- notice: t('scaffold.model_created_successfully', model: @check.model_name.human)
+ notice: t("scaffold.model_created_successfully", model: @check.model_name.human)
end
format.json { render :show, status: :created, location: @check }
else
- flash[:alert] = t('there_were_errors', count: @check.errors.size)
+ flash[:alert] = t("there_were_errors", count: @check.errors.size)
format.html { render :new, status: :unprocessable_entity }
format.json { render json: @check.errors, status: :unprocessable_entity }
end
@@ -44,7 +48,7 @@ class ChecksController < ApplicationController
if @check.update(check_params)
format.html do
redirect_to check_url(@check),
- notice: t('scaffold.model_updated_successfully', model: @check.model_name.human)
+ notice: t("scaffold.model_updated_successfully", model: @check.model_name.human)
end
format.json { render :show, status: :ok, location: @check }
else
@@ -60,7 +64,7 @@ class ChecksController < ApplicationController
respond_to do |format|
format.html do
- redirect_to checks_url, notice: t('scaffold.model_destroyed_successfully', model: @check.model_name.human)
+ redirect_to checks_url, notice: t("scaffold.model_destroyed_successfully", model: @check.model_name.human)
end
format.json { head :no_content }
end
@@ -79,6 +83,43 @@ class ChecksController < ApplicationController
# Only allow a list of trusted parameters through.
def check_params
- params.require(:check).permit(:position, :name, :success_criterion, :success_criterion_html, :level)
+ params.require(:check).permit(:principle_id,
+ :number,
+ :name_de,
+ :name_en,
+ :standard_id,
+ :visual,
+ :auditory,
+ :physical,
+ :cognitive,
+ :applicable_to_app,
+ :applicable_to_web,
+ :external_number,
+ :conformity_level,
+ :conformity_notice_de,
+ :conformity_notice_en,
+ :priority,
+ :quick_criterion_de,
+ :quick_criterion_en,
+ :quick_fail_de,
+ :quick_fail_en,
+ :quick_fix_de,
+ :quick_fix_en,
+ :criterion_de,
+ :criterion_en,
+ :criterion_details_de,
+ :criterion_details_en,
+ :example_de,
+ :example_en,
+ :exemption_details_de,
+ :exemption_details_en,
+ :standard_text_de,
+ :standard_text_en,
+ :test_instructions,
+ :powerpoint_text_de,
+ :powerpoint_text_en,
+ :comment,
+ link_ids: [],
+ standard_ids: [])
end
end
diff --git a/app/controllers/elements_controller.rb b/app/controllers/elements_controller.rb
index 261e359..4824ec5 100644
--- a/app/controllers/elements_controller.rb
+++ b/app/controllers/elements_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class ElementsController < ApplicationController
before_action :set_element, only: %i[show edit update destroy]
@@ -7,8 +9,7 @@ class ElementsController < ApplicationController
end
# GET /elements/1
- def show
- end
+ def show; end
# GET /elements/new
def new
@@ -16,8 +17,7 @@ class ElementsController < ApplicationController
end
# GET /elements/1/edit
- def edit
- end
+ def edit; end
# POST /elements
def create
@@ -28,11 +28,11 @@ class ElementsController < ApplicationController
if @element.save
checklist.checks.each do |check|
- @element.success_criteria.create!(title: check.name, description_html: check.success_criterion_html,
+ @element.success_criteria.create!(title: check.t_name, description_html: check.t_criterion,
level: check.level)
end
respond_to do |format|
- format.html { redirect_to @element.report, notice: 'Element was successfully created.' }
+ format.html { redirect_to @element.report, notice: "Element was successfully created." }
format.turbo_stream
end
else
@@ -43,7 +43,7 @@ class ElementsController < ApplicationController
# PATCH/PUT /elements/1
def update
if @element.update(element_params)
- redirect_to @element, notice: 'Element was successfully updated.', status: :see_other
+ redirect_to @element, notice: "Element was successfully updated.", status: :see_other
else
render :edit, status: :unprocessable_entity
end
@@ -52,7 +52,7 @@ class ElementsController < ApplicationController
# DELETE /elements/1
def destroy
@element.destroy!
- redirect_to elements_url, notice: 'Element was successfully destroyed.', status: :see_other
+ redirect_to elements_url, notice: "Element was successfully destroyed.", status: :see_other
end
private
diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb
index 13ff6f6..9ccfc38 100644
--- a/app/controllers/home_controller.rb
+++ b/app/controllers/home_controller.rb
@@ -1,5 +1,6 @@
# frozen_string_literal: true
class HomeController < ApplicationController
- def show; end
+ def show
+ end
end
diff --git a/app/controllers/link_categories_controller.rb b/app/controllers/link_categories_controller.rb
index 7014f9c..cbccdf0 100644
--- a/app/controllers/link_categories_controller.rb
+++ b/app/controllers/link_categories_controller.rb
@@ -1,5 +1,7 @@
+# frozen_string_literal: true
+
class LinkCategoriesController < ApplicationController
- before_action :set_link_category, only: %i[ show edit update destroy ]
+ before_action :set_link_category, only: %i[show edit update destroy]
# GET /link_categories
def index
@@ -7,8 +9,7 @@ class LinkCategoriesController < ApplicationController
end
# GET /link_categories/1
- def show
- end
+ def show; end
# GET /link_categories/new
def new
@@ -16,8 +17,7 @@ class LinkCategoriesController < ApplicationController
end
# GET /link_categories/1/edit
- def edit
- end
+ def edit; end
# POST /link_categories
def create
@@ -46,13 +46,14 @@ class LinkCategoriesController < ApplicationController
end
private
- # Use callbacks to share common setup or constraints between actions.
- def set_link_category
- @link_category = LinkCategory.find(params[:id])
- end
- # Only allow a list of trusted parameters through.
- def link_category_params
- params.require(:link_category).permit(:name, :description, :rich_text)
- end
+ # Use callbacks to share common setup or constraints between actions.
+ def set_link_category
+ @link_category = LinkCategory.find(params[:id])
+ end
+
+ # Only allow a list of trusted parameters through.
+ def link_category_params
+ params.require(:link_category).permit(:name, :description, :rich_text)
+ end
end
diff --git a/app/controllers/links_controller.rb b/app/controllers/links_controller.rb
index 810716f..20f1c7d 100644
--- a/app/controllers/links_controller.rb
+++ b/app/controllers/links_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class LinksController < ApplicationController
before_action :set_link, only: %i[show edit update destroy]
@@ -7,8 +9,7 @@ class LinksController < ApplicationController
end
# GET /links/1
- def show
- end
+ def show; end
# GET /links/new
def new
@@ -16,15 +17,14 @@ class LinksController < ApplicationController
end
# GET /links/1/edit
- def edit
- end
+ def edit; end
# POST /links
def create
@link = Link.new(link_params)
if @link.save
- redirect_to @link, notice: 'Link was successfully created.'
+ redirect_to @link, notice: "Link was successfully created."
else
render :new, status: :unprocessable_entity
end
@@ -33,7 +33,7 @@ class LinksController < ApplicationController
# PATCH/PUT /links/1
def update
if @link.update(link_params)
- redirect_to @link, notice: 'Link was successfully updated.', status: :see_other
+ redirect_to @link, notice: "Link was successfully updated.", status: :see_other
else
render :edit, status: :unprocessable_entity
end
@@ -42,7 +42,7 @@ class LinksController < ApplicationController
# DELETE /links/1
def destroy
@link.destroy!
- redirect_to links_url, notice: 'Link was successfully destroyed.', status: :see_other
+ redirect_to links_url, notice: "Link was successfully destroyed.", status: :see_other
end
private
diff --git a/app/controllers/reports_controller.rb b/app/controllers/reports_controller.rb
index dfe6847..1ada068 100644
--- a/app/controllers/reports_controller.rb
+++ b/app/controllers/reports_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class ReportsController < ApplicationController
before_action :set_report, only: %i[show edit update destroy work]
@@ -12,26 +14,56 @@ class ReportsController < ApplicationController
format.html
format.pdf
format.xlsx do
- response.headers['Content-Disposition'] = %(attachment; filename="#{filename(@report, extension: 'xlsx')}")
+ response.headers["Content-Disposition"] = %(attachment; filename="#{filename(@report, extension: 'xlsx')}")
render
end
format.xml do
- response.headers['Content-Disposition'] = %(attachment; filename="#{filename(@report, extension: 'html')}")
- render formats: [:odt], layout: false
+ response.headers["Content-Disposition"] = %(attachment; filename="#{filename(@report, extension: 'html')}")
+ render formats: [ :odt ], layout: false
end
format.rtf do
- html = render_to_string(template: 'reports/show', formats: [:odt],
+ html = render_to_string(template: "reports/show", formats: [ :odt ],
layout: false)
rtf = "{\\rtf1\n#{PandocRuby.html(html).to_rtf}}"
- send_data rtf, filename: filename(@report, extension: 'rtf')
+ send_data rtf, filename: filename(@report, extension: "rtf")
end
format.odt do
html = render_to_string(layout: false)
odt = PandocRuby.html(html).to_odt
- send_data odt, filename: filename(@report, extension: 'odt')
+ send_data odt, filename: filename(@report, extension: "odt")
end
format.docx do
- template = Sablon.template(Rails.root.join('lib/templates/docx/report.docx'))
+ send_file(Docx::Document.new.generate do |document|
+ document.heading1(@report.name)
+ document.paragraph(@report.comment_html)
+ # document.heading1("slfkj")
+ # document.paragraph("sldkfj")
+ @report.elements.each do |element|
+ document.heading2(element.title)
+ element.success_criteria.each do |sc|
+ document.heading3(sc.title)
+ document.paragraph(sc.description_html)
+ end
+ end
+ end, filename: filename(@report, extension: "docx"),
+ type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document")
+
+ return
+
+ text = OpenXml::Docx::Elements::Text.new(@report.name)
+ run = OpenXml::Docx::Elements::Run.new
+ run.bold = true
+ run << text
+ paragraph = OpenXml::Docx::Elements::Paragraph.new
+ paragraph << run
+
+ document = OpenXml::Docx::Package.new
+ document.document << paragraph
+ document.save(Rails.root.join("tmp", "output.docx"))
+ send_file Rails.root.join("tmp", "output.docx")
+ return
+
+ template = Sablon.template(Rails.root.join("lib/templates/docx/report.docx"))
context = {
person: OpenStruct.new(first_name: @report.name),
skills: [],
@@ -40,10 +72,10 @@ class ReportsController < ApplicationController
referees: []
}
- template.render_to_file(Rails.root.join('tmp/output.docx'), context)
- send_file Rails.root.join('tmp/output.docx'),
- filename: filename(@report, extension: 'docx'),
- type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
+ template.render_to_file(Rails.root.join("tmp/output.docx"), context)
+ send_file Rails.root.join("tmp/output.docx"),
+ filename: filename(@report, extension: "docx"),
+ type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
end
end
end
@@ -54,15 +86,14 @@ class ReportsController < ApplicationController
end
# GET /reports/1/edit
- def edit
- end
+ def edit; end
# POST /reports
def create
@report = Report.new(report_params)
if @report.save
- redirect_to @report, notice: 'Report was successfully created.'
+ redirect_to @report, notice: "Report was successfully created."
else
render :new, status: :unprocessable_entity
end
@@ -71,7 +102,7 @@ class ReportsController < ApplicationController
# PATCH/PUT /reports/1
def update
if @report.update(report_params)
- redirect_to @report, notice: 'Report was successfully updated.', status: :see_other
+ redirect_to @report, notice: "Report was successfully updated.", status: :see_other
else
render :edit, status: :unprocessable_entity
end
@@ -80,7 +111,7 @@ class ReportsController < ApplicationController
# DELETE /reports/1
def destroy
@report.destroy!
- redirect_to reports_url, notice: 'Report was successfully destroyed.', status: :see_other
+ redirect_to reports_url, notice: "Report was successfully destroyed.", status: :see_other
end
def work
@@ -99,7 +130,7 @@ class ReportsController < ApplicationController
params.require(:report).permit(:name, :comment_html)
end
- def filename(report, extension: 'html')
+ def filename(report, extension: "html")
"#{report.name}-#{Time.current.strftime('%Y%m%d%H%M')}.#{extension}"
end
end
diff --git a/app/controllers/success_criteria_controller.rb b/app/controllers/success_criteria_controller.rb
index a7fcf2a..7784d09 100644
--- a/app/controllers/success_criteria_controller.rb
+++ b/app/controllers/success_criteria_controller.rb
@@ -1,3 +1,5 @@
+# frozen_string_literal: true
+
class SuccessCriteriaController < ApplicationController
before_action :set_success_criterion, only: %i[show edit update destroy]
@@ -7,8 +9,7 @@ class SuccessCriteriaController < ApplicationController
end
# GET /success_criteria/1
- def show
- end
+ def show; end
# GET /success_criteria/new
def new
@@ -16,15 +17,14 @@ class SuccessCriteriaController < ApplicationController
end
# GET /success_criteria/1/edit
- def edit
- end
+ def edit; end
# POST /success_criteria
def create
@success_criterion = SuccessCriterion.new(success_criterion_params)
if @success_criterion.save
- redirect_to @success_criterion, notice: 'Erfolgskriterium was successfully created.'
+ redirect_to @success_criterion, notice: "Erfolgskriterium was successfully created."
else
render :new, status: :unprocessable_entity
end
@@ -33,7 +33,7 @@ class SuccessCriteriaController < ApplicationController
# PATCH/PUT /success_criteria/1
def update
if @success_criterion.update(success_criterion_params)
- redirect_to @success_criterion, notice: 'Erfolgskriterium was successfully updated.', status: :see_other
+ redirect_to @success_criterion, notice: "Erfolgskriterium was successfully updated.", status: :see_other
else
render :edit, status: :unprocessable_entity
end
@@ -44,7 +44,7 @@ class SuccessCriteriaController < ApplicationController
@success_criterion.destroy!
respond_to do |format|
format.html do
- redirect_to success_criteria_url, notice: 'Erfolgskriterium was successfully destroyed.', status: :see_other
+ redirect_to success_criteria_url, notice: "Erfolgskriterium was successfully destroyed.", status: :see_other
end
format.turbo_stream
end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index ebb9bc8..70edee3 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -4,4 +4,16 @@ module ApplicationHelper
include Pagy::Frontend
delegate :filter_params, to: :controller
+
+ def multilang_form_field(form, attribute, as: :text_field)
+ col_width = as == :rich_text_area ? 12 : 12 / I18n.available_locales.count
+ tag.div(class: "row") do
+ fields = I18n.available_locales.map { _1.to_s.split("-").first }.map do |lang|
+ tag.div(class: "col-lg-#{col_width}") do
+ form.send(as, "#{attribute}_#{lang}")
+ end
+ end
+ safe_join(fields)
+ end
+ end
end
diff --git a/app/helpers/checklist_entries_helper.rb b/app/helpers/checklist_entries_helper.rb
index 09d2b52..e18ebce 100644
--- a/app/helpers/checklist_entries_helper.rb
+++ b/app/helpers/checklist_entries_helper.rb
@@ -1,2 +1,4 @@
+# frozen_string_literal: true
+
module ChecklistEntriesHelper
end
diff --git a/app/helpers/checklists_helper.rb b/app/helpers/checklists_helper.rb
index 4652a79..b1da425 100644
--- a/app/helpers/checklists_helper.rb
+++ b/app/helpers/checklists_helper.rb
@@ -1,2 +1,4 @@
+# frozen_string_literal: true
+
module ChecklistsHelper
end
diff --git a/app/helpers/checks_helper.rb b/app/helpers/checks_helper.rb
index ec8edd7..2515a9f 100644
--- a/app/helpers/checks_helper.rb
+++ b/app/helpers/checks_helper.rb
@@ -1,2 +1,4 @@
+# frozen_string_literal: true
+
module ChecksHelper
end
diff --git a/app/helpers/elements_helper.rb b/app/helpers/elements_helper.rb
index fed28ea..d7f10ce 100644
--- a/app/helpers/elements_helper.rb
+++ b/app/helpers/elements_helper.rb
@@ -1,2 +1,4 @@
+# frozen_string_literal: true
+
module ElementsHelper
end
diff --git a/app/helpers/link_categories_helper.rb b/app/helpers/link_categories_helper.rb
index c60b20f..d38d401 100644
--- a/app/helpers/link_categories_helper.rb
+++ b/app/helpers/link_categories_helper.rb
@@ -1,2 +1,4 @@
+# frozen_string_literal: true
+
module LinkCategoriesHelper
end
diff --git a/app/helpers/links_helper.rb b/app/helpers/links_helper.rb
index f6bc988..038f107 100644
--- a/app/helpers/links_helper.rb
+++ b/app/helpers/links_helper.rb
@@ -1,2 +1,4 @@
+# frozen_string_literal: true
+
module LinksHelper
end
diff --git a/app/helpers/pdf_helper.rb b/app/helpers/pdf_helper.rb
index 825b788..4f72ab3 100644
--- a/app/helpers/pdf_helper.rb
+++ b/app/helpers/pdf_helper.rb
@@ -1,17 +1,19 @@
+# frozen_string_literal: true
+
module PdfHelper
def prepare_rich_text(rich_text)
return rich_text
- { del: 'strikethrough' }.each do |tag, replacement|
+ { del: "strikethrough" }.each do |tag, replacement|
rich_text = rich_text.to_s.gsub("<#{tag}", "<#{replacement}")
rich_text = rich_text.to_s.gsub("#{tag}>", "#{replacement}>")
end
%w[div p del blockquote pre code].each do |tag|
- rich_text = rich_text.to_s.gsub(%r{<#{tag}.*?>|#{tag}>}, '')
+ rich_text = rich_text.to_s.gsub(%r{<#{tag}.*?>|#{tag}>}, "")
end
- rich_text.gsub!(/- <%= Check.human_attribute_name(:position) %>: - <%= check.position %> -
- -- <%= Check.human_attribute_name(:name) %>: - <%= check.name %> -
- -- <%= Check.human_attribute_name(:success_criterion_html) %>: - <%= check.success_criterion_html %> -
- -- <%= Check.human_attribute_name(:level) %>: - <%= check.level %> -
- -| <%= Check.human_attribute_name(:id) %> | -<%= Check.human_attribute_name(:level) %> | +<%= Check.human_attribute_name(:number) %> | <%= Check.human_attribute_name(:name) %> | -<%= Check.human_attribute_name(:success_criterion_html) %> | +<%= Check.human_attribute_name(:standards) %> | +<%= t("checks.target_disabilities") %> | +<%= t("checks.applicability") %> | +<%= Check.human_attribute_name(:external_number) %> | +<%= Check.human_attribute_name(:conformity_level) %> | |
|---|---|---|---|---|---|---|---|---|---|---|
| <%= check.id %> | -<%= check.level %> | -<%= link_to(check.name, url_for(check)) %> | -<%= link_to(truncate(strip_tags(check.success_criterion_html.to_s)), url_for(check)) %> | +<%= check.number %> | +<%= check.t_name %> | +<%= check.standards.map(&:t_name).join(", ") %> | +<%= check.display_target_disabilities %> | +<%= check.t_name %> | +<%= check.t_name %> | +<%= link_to(check.t_name, url_for(check)) %> | <%= link_to(link_category.name, url_for(link_category)) %> | -<%= link_to(link_category.description, url_for(link_category)) %> | +<%= link_to(truncate(link_category.description.to_plain_text), url_for(link_category)) %> | <% end %> diff --git a/app/views/link_categories/index.json.jbuilder b/app/views/link_categories/index.json.jbuilder index b68de09..5c313a1 100644 --- a/app/views/link_categories/index.json.jbuilder +++ b/app/views/link_categories/index.json.jbuilder @@ -1 +1,3 @@ +# frozen_string_literal: true + json.array! @link_categories, partial: "link_categories/link_category", as: :link_category diff --git a/app/views/link_categories/show.json.jbuilder b/app/views/link_categories/show.json.jbuilder index ec040cb..0076302 100644 --- a/app/views/link_categories/show.json.jbuilder +++ b/app/views/link_categories/show.json.jbuilder @@ -1 +1,3 @@ +# frozen_string_literal: true + json.partial! "link_categories/link_category", link_category: @link_category diff --git a/app/views/links/_link.json.jbuilder b/app/views/links/_link.json.jbuilder index 8857558..cc270f2 100644 --- a/app/views/links/_link.json.jbuilder +++ b/app/views/links/_link.json.jbuilder @@ -1,3 +1,6 @@ -json.extract! link, :id, :url, :text, :description, :last_check_at, :fail_count, :link_category_id, :created_at, :updated_at +# frozen_string_literal: true + +json.extract! link, :id, :url, :text, :description, :last_check_at, :fail_count, :link_category_id, :created_at, + :updated_at json.url link_url(link, format: :json) json.description link.description.to_s diff --git a/app/views/links/index.json.jbuilder b/app/views/links/index.json.jbuilder index 7b13bad..1367af9 100644 --- a/app/views/links/index.json.jbuilder +++ b/app/views/links/index.json.jbuilder @@ -1 +1,3 @@ +# frozen_string_literal: true + json.array! @links, partial: "links/link", as: :link diff --git a/app/views/links/show.json.jbuilder b/app/views/links/show.json.jbuilder index 79e4f78..6a9c888 100644 --- a/app/views/links/show.json.jbuilder +++ b/app/views/links/show.json.jbuilder @@ -1 +1,3 @@ +# frozen_string_literal: true + json.partial! "links/link", link: @link diff --git a/app/views/reports/_report.json.jbuilder b/app/views/reports/_report.json.jbuilder index 5012ee9..3c8f009 100644 --- a/app/views/reports/_report.json.jbuilder +++ b/app/views/reports/_report.json.jbuilder @@ -1,2 +1,4 @@ +# frozen_string_literal: true + json.extract! report, :id, :name, :comment_html, :created_at, :updated_at json.url report_url(report, format: :json) diff --git a/app/views/reports/index.json.jbuilder b/app/views/reports/index.json.jbuilder index 31811f6..5da3e58 100644 --- a/app/views/reports/index.json.jbuilder +++ b/app/views/reports/index.json.jbuilder @@ -1 +1,3 @@ +# frozen_string_literal: true + json.array! @reports, partial: "reports/report", as: :report diff --git a/app/views/reports/show.json.jbuilder b/app/views/reports/show.json.jbuilder index b5a5508..5ff9f54 100644 --- a/app/views/reports/show.json.jbuilder +++ b/app/views/reports/show.json.jbuilder @@ -1 +1,3 @@ +# frozen_string_literal: true + json.partial! "reports/report", report: @report diff --git a/app/views/reports/show.xlsx.axlsx b/app/views/reports/show.xlsx.axlsx index 92d2d08..1087d58 100644 --- a/app/views/reports/show.xlsx.axlsx +++ b/app/views/reports/show.xlsx.axlsx @@ -1,3 +1,5 @@ +# frozen_string_literal: true + wb = xlsx_package.workbook wb.add_worksheet(name: "Erfolgskriterien") do |sheet| sheet.add_row SuccessCriterion.column_names @@ -7,4 +9,4 @@ wb.add_worksheet(name: "Erfolgskriterien") do |sheet| sheet.add_row sc.attributes.values end end -end \ No newline at end of file +end diff --git a/app/views/success_criteria/_success_criterion.json.jbuilder b/app/views/success_criteria/_success_criterion.json.jbuilder index 81d1a20..672caae 100644 --- a/app/views/success_criteria/_success_criterion.json.jbuilder +++ b/app/views/success_criteria/_success_criterion.json.jbuilder @@ -1,3 +1,5 @@ +# frozen_string_literal: true + json.extract! success_criterion, :id, :element_id, :title, :description_html, :level, :result, :comment_html, :created_at, :updated_at json.url success_criterion_url(success_criterion, format: :json) diff --git a/app/views/success_criteria/index.json.jbuilder b/app/views/success_criteria/index.json.jbuilder index 8ee481b..96dcdc7 100644 --- a/app/views/success_criteria/index.json.jbuilder +++ b/app/views/success_criteria/index.json.jbuilder @@ -1 +1,3 @@ +# frozen_string_literal: true + json.array! @success_criteria, partial: "success_criteria/success_criterion", as: :success_criterion diff --git a/app/views/success_criteria/show.json.jbuilder b/app/views/success_criteria/show.json.jbuilder index 5df804d..463c139 100644 --- a/app/views/success_criteria/show.json.jbuilder +++ b/app/views/success_criteria/show.json.jbuilder @@ -1 +1,3 @@ +# frozen_string_literal: true + json.partial! "success_criteria/success_criterion", success_criterion: @success_criterion diff --git a/bin/brakeman b/bin/brakeman new file mode 100755 index 0000000..ae3a448 --- /dev/null +++ b/bin/brakeman @@ -0,0 +1,9 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require 'rubygems' +require 'bundler/setup' + +ARGV.unshift('--ensure-latest') + +load Gem.bin_path('brakeman', 'brakeman') diff --git a/bin/entrypoint b/bin/entrypoint index 2f2c947..54e4d9b 100755 --- a/bin/entrypoint +++ b/bin/entrypoint @@ -1,20 +1,23 @@ -#!/bin/bash +#!/bin/ash + set -e -echo "1: ${1}" -echo "2: ${2}" if [ -f tmp/pids/server.pid ]; then rm tmp/pids/server.pid fi # Make the if statement match any invocation of the "rails server" command if [[ "${1}" == *rails ]] && ([ "${2}" == "server" ] || [ "${2}" == "s" ]); then + echo "+ preparing database..." + ./bin/rails db:prepare + echo "- preparing database done." - if [ ! -f /app/no_migrate ] && [ ! -v NO_MIGRATE ]; then - echo "+ preparing database..." - ./bin/rails db:prepare - echo "- preparing database done." + if [ -n "$ASSETS_PATH" ]; then + echo "+ copying assets..." + cp -nr public/* $ASSETS_PATH + echo "- copying assets done." fi + fi # Execute the given or default command: diff --git a/bin/rubocop b/bin/rubocop new file mode 100755 index 0000000..f45b065 --- /dev/null +++ b/bin/rubocop @@ -0,0 +1,10 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require 'rubygems' +require 'bundler/setup' + +# explicit rubocop config increases performance slightly while avoiding config confusion. +ARGV.unshift('--config', File.expand_path('../.rubocop.yml', __dir__)) + +load Gem.bin_path('rubocop', 'rubocop') diff --git a/bin/setup b/bin/setup index d38bf9f..c823853 100755 --- a/bin/setup +++ b/bin/setup @@ -1,8 +1,8 @@ #!/usr/bin/env ruby require "fileutils" -# path to your application root. APP_ROOT = File.expand_path("..", __dir__) +APP_NAME = "a11yist" def system!(*args) system(*args, exception: true) @@ -17,9 +17,6 @@ FileUtils.chdir APP_ROOT do system! "gem install bundler --conservative" system("bundle check") || system!("bundle install") - # Install JavaScript dependencies - system("yarn check --check-files") || system!("yarn install") - # puts "\n== Copying sample files ==" # unless File.exist?("config/database.yml") # FileUtils.cp "config/database.yml.sample", "config/database.yml" @@ -33,4 +30,8 @@ FileUtils.chdir APP_ROOT do puts "\n== Restarting application server ==" system! "bin/rails restart" + + # puts "\n== Configuring puma-dev ==" + # system "ln -nfs #{APP_ROOT} ~/.puma-dev/#{APP_NAME}" + # system "curl -Is https://#{APP_NAME}.test/up | head -n 1" end diff --git a/config/boot.rb b/config/boot.rb index b9e460c..988a5dd 100644 --- a/config/boot.rb +++ b/config/boot.rb @@ -1,4 +1,4 @@ -ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) -require 'bundler/setup' # Set up gems listed in the Gemfile. -require 'bootsnap/setup' # Speed up boot time by caching expensive operations. +require "bundler/setup" # Set up gems listed in the Gemfile. +require "bootsnap/setup" # Speed up boot time by caching expensive operations. diff --git a/config/database.yml b/config/database.yml index 796466b..56d378d 100644 --- a/config/database.yml +++ b/config/database.yml @@ -8,6 +8,7 @@ default: &default adapter: sqlite3 pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> timeout: 5000 + default_transaction_mode: IMMEDIATE development: <<: *default diff --git a/config/environments/development.rb b/config/environments/development.rb index a72b7d7..c6145f2 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/integer/time' +require "active_support/core_ext/integer/time" Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. @@ -14,19 +14,17 @@ Rails.application.configure do # Show full error reports. config.consider_all_requests_local = true - # Enable server timing + # Enable server timing. config.server_timing = true # Enable/disable caching. By default caching is disabled. # Run rails dev:cache to toggle caching. - if Rails.root.join('tmp/caching-dev.txt').exist? + if Rails.root.join("tmp/caching-dev.txt").exist? config.action_controller.perform_caching = true config.action_controller.enable_fragment_cache_logging = true config.cache_store = :memory_store - config.public_file_server.headers = { - 'Cache-Control' => "public, max-age=#{2.days.to_i}" - } + config.public_file_server.headers = { "Cache-Control" => "public, max-age=#{2.days.to_i}" } else config.action_controller.perform_caching = false @@ -39,8 +37,12 @@ Rails.application.configure do # Don't care if the mailer can't send. config.action_mailer.raise_delivery_errors = false + # Disable caching for Action Mailer templates even if Action Controller + # caching is enabled. config.action_mailer.perform_caching = false + config.action_mailer.default_url_options = { host: "a11yist.localhost" } + # Print deprecation notices to the Rails logger. config.active_support.deprecation = :log @@ -66,13 +68,16 @@ Rails.application.configure do # config.i18n.raise_on_missing_translations = true # Annotate rendered view with file names. - # config.action_view.annotate_rendered_view_with_filenames = true + config.action_view.annotate_rendered_view_with_filenames = true # Uncomment if you wish to allow Action Cable access from any origin. # config.action_cable.disable_request_forgery_protection = true - # Raise error when a before_action's only/except options reference missing actions + # Raise error when a before_action's only/except options reference missing actions. config.action_controller.raise_on_missing_callback_actions = true - config.web_console.permissions = ['192.168.0.0/16', '10.10.0.0/16'] + # Apply autocorrection by RuboCop to files generated by `bin/rails generate`. + # config.generators.apply_rubocop_autocorrect_after_generate! + # + config.web_console.allowed_ips = ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "127.0.0.0/8"] end diff --git a/config/environments/production.rb b/config/environments/production.rb index 569a1d8..b20131b 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/integer/time' +require "active_support/core_ext/integer/time" Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. @@ -21,7 +21,7 @@ Rails.application.configure do # config.require_master_key = true # Disable serving static files from `public/`, relying on NGINX/Apache to do so instead. - # config.public_file_server.enabled = false + config.public_file_server.enabled = ENV.fetch("ASSETS_PATH") { nil }.nil? # Compress CSS using a preprocessor. # config.assets.css_compressor = :sass @@ -49,20 +49,25 @@ Rails.application.configure do # config.assume_ssl = true # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. - config.force_ssl = true + config.force_ssl = false + + # Skip http-to-https redirect for the default health check endpoint. + # config.ssl_options = { redirect: { exclude: ->(request) { request.path == "/up" } } } + + config.logger = ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new("log/#{Rails.env}.log")) # Log to STDOUT by default - config.logger = ActiveSupport::Logger.new(STDOUT) - .tap { |logger| logger.formatter = ::Logger::Formatter.new } - .then { |logger| ActiveSupport::TaggedLogging.new(logger) } + # config.logger = ActiveSupport::Logger.new(STDOUT) + # .tap { |logger| logger.formatter = ::Logger::Formatter.new } + # .then { |logger| ActiveSupport::TaggedLogging.new(logger) } # Prepend all log lines with the following tags. - config.log_tags = [:request_id] + config.log_tags = [ :request_id, :remote_ip ] # "info" includes generic and useful information about system operation, but avoids logging too much # information to avoid inadvertent exposure of personally identifiable information (PII). If you # want to log everything, set the level to "debug". - config.log_level = ENV.fetch('RAILS_LOG_LEVEL', 'info') + config.log_level = ENV.fetch("RAILS_LOG_LEVEL", "info") # Use a different cache store in production. # config.cache_store = :mem_cache_store @@ -71,6 +76,8 @@ Rails.application.configure do # config.active_job.queue_adapter = :resque # config.active_job.queue_name_prefix = "a11yist_production" + # Disable caching for Action Mailer templates even if Action Controller + # caching is enabled. config.action_mailer.perform_caching = false # Ignore bad email addresses and do not raise email delivery errors. @@ -92,8 +99,6 @@ Rails.application.configure do # "example.com", # Allow requests from example.com # /.*\.example\.com/ # Allow requests from subdomains like `www.example.com` # ] - config.hosts = ENV.fetch('APP_HOSTS', '').split(',') # Skip DNS rebinding protection for the default health check endpoint. # config.host_authorization = { exclude: ->(request) { request.path == "/up" } } - config.active_record.sqlite3_production_warning=false end diff --git a/config/environments/test.rb b/config/environments/test.rb index bb76f63..0c616a1 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -1,4 +1,4 @@ -require 'active_support/core_ext/integer/time' +require "active_support/core_ext/integer/time" # The test environment is used exclusively to run your application's # test suite. You never need to work with it otherwise. Remember that @@ -15,13 +15,10 @@ Rails.application.configure do # this is usually not necessary, and can slow down your test suite. However, it's # recommended that you enable it in continuous integration systems to ensure eager # loading is working properly before deploying your code. - config.eager_load = ENV['CI'].present? + config.eager_load = ENV["CI"].present? # Configure public file server for tests with Cache-Control for performance. - config.public_file_server.enabled = true - config.public_file_server.headers = { - 'Cache-Control' => "public, max-age=#{1.hour.to_i}" - } + config.public_file_server.headers = { "Cache-Control" => "public, max-age=#{1.hour.to_i}" } # Show full error reports and disable caching. config.consider_all_requests_local = true @@ -37,6 +34,8 @@ Rails.application.configure do # Store uploaded files on the local file system in a temporary directory. config.active_storage.service = :test + # Disable caching for Action Mailer templates even if Action Controller + # caching is enabled. config.action_mailer.perform_caching = false # Tell Action Mailer not to deliver emails to the real world. @@ -44,6 +43,10 @@ Rails.application.configure do # ActionMailer::Base.deliveries array. config.action_mailer.delivery_method = :test + # Unlike controllers, the mailer instance doesn't have any context about the + # incoming request so you'll need to provide the :host parameter yourself. + config.action_mailer.default_url_options = { host: "www.example.com" } + # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr @@ -59,6 +62,6 @@ Rails.application.configure do # Annotate rendered view with file names. # config.action_view.annotate_rendered_view_with_filenames = true - # Raise error when a before_action's only/except options reference missing actions + # Raise error when a before_action's only/except options reference missing actions. config.action_controller.raise_on_missing_callback_actions = true end diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb index 262e862..c010b83 100644 --- a/config/initializers/filter_parameter_logging.rb +++ b/config/initializers/filter_parameter_logging.rb @@ -3,6 +3,6 @@ # Configure parameters to be partially matched (e.g. passw matches password) and filtered from the log file. # Use this to limit dissemination of sensitive information. # See the ActiveSupport::ParameterFilter documentation for supported notations and behaviors. -Rails.application.config.filter_parameters += %i[ - passw secret token _key crypt salt certificate otp ssn +Rails.application.config.filter_parameters += [ + :passw, :email, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn ] diff --git a/config/initializers/locale.rb b/config/initializers/locale.rb index 850ffb8..1b127cd 100644 --- a/config/initializers/locale.rb +++ b/config/initializers/locale.rb @@ -3,7 +3,7 @@ # I18n.load_path += Dir[Rails.root.join('lib', 'locale', '*.{rb,yml}')] # Permitted locales available for the application -I18n.available_locales = [:"de-CH"] +I18n.available_locales = [:"de-CH", :en] # Set default locale to something other than :en I18n.default_locale = :"de-CH" \ No newline at end of file diff --git a/config/initializers/new_framework_defaults_7_2.rb b/config/initializers/new_framework_defaults_7_2.rb new file mode 100644 index 0000000..53b5626 --- /dev/null +++ b/config/initializers/new_framework_defaults_7_2.rb @@ -0,0 +1,70 @@ +# Be sure to restart your server when you modify this file. +# +# This file eases your Rails 7.2 framework defaults upgrade. +# +# Uncomment each configuration one by one to switch to the new default. +# Once your application is ready to run with all new defaults, you can remove +# this file and set the `config.load_defaults` to `7.2`. +# +# Read the Guide for Upgrading Ruby on Rails for more info on each option. +# https://guides.rubyonrails.org/upgrading_ruby_on_rails.html + +### +# Controls whether Active Job's `#perform_later` and similar methods automatically defer +# the job queuing to after the current Active Record transaction is committed. +# +# Example: +# Topic.transaction do +# topic = Topic.create(...) +# NewTopicNotificationJob.perform_later(topic) +# end +# +# In this example, if the configuration is set to `:never`, the job will +# be enqueued immediately, even though the `Topic` hasn't been committed yet. +# Because of this, if the job is picked up almost immediately, or if the +# transaction doesn't succeed for some reason, the job will fail to find this +# topic in the database. +# +# If `enqueue_after_transaction_commit` is set to `:default`, the queue adapter +# will define the behaviour. +# +# Note: Active Job backends can disable this feature. This is generally done by +# backends that use the same database as Active Record as a queue, hence they +# don't need this feature. +#++ +# Rails.application.config.active_job.enqueue_after_transaction_commit = :default + +### +# Adds image/webp to the list of content types Active Storage considers as an image +# Prevents automatic conversion to a fallback PNG, and assumes clients support WebP, as they support gif, jpeg, and png. +# This is possible due to broad browser support for WebP, but older browsers and email clients may still not support +# WebP. Requires imagemagick/libvips built with WebP support. +#++ +Rails.application.config.active_storage.web_image_content_types = %w[image/png image/jpeg image/gif image/webp] + +### +# Enable validation of migration timestamps. When set, an ActiveRecord::InvalidMigrationTimestampError +# will be raised if the timestamp prefix for a migration is more than a day ahead of the timestamp +# associated with the current time. This is done to prevent forward-dating of migration files, which can +# impact migration generation and other migration commands. +# +# Applications with existing timestamped migrations that do not adhere to the +# expected format can disable validation by setting this config to `false`. +#++ +# Rails.application.config.active_record.validate_migration_timestamps = true + +### +# Controls whether the PostgresqlAdapter should decode dates automatically with manual queries. +# +# Example: +# ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.select_value("select '2024-01-01'::date") #=> Date +# +# This query used to return a `String`. +#++ +# Rails.application.config.active_record.postgresql_adapter_decode_dates = true + +### +# Enables YJIT as of Ruby 3.3, to bring sizeable performance improvements. If you are +# deploying to a memory constrained environment you may want to set this to `false`. +#++ +Rails.application.config.yjit = true diff --git a/config/locales/activerecord.yml b/config/locales/activerecord.yml index bf3043f..894aeb0 100644 --- a/config/locales/activerecord.yml +++ b/config/locales/activerecord.yml @@ -12,9 +12,39 @@ de-CH: results/not_applicable: Nicht anwendbar check: id: ID - level: Stufe + number: Nummer + external_number: WCAG Nummer + conformity_level: Konformitätsstufe position: Position - success_criterion_html: Erfolgskriterium + conformity_notice_de: Konformitätserklärung (de) + conformity_notice_en: Konformitätserklärung (eng) + standard_ids: Standards + name_de: Name (de) + name_en: Name (eng) + principle_id: Prinzip + priority: Priorität + quick_criterion_de: Quick Kriterium (de) + quick_criterion_en: Quick Kriterium (eng) + quick_fix_de: Quick Fix (de) + quick_fix_en: Quick Fix (eng) + quick_fail_de: Quick Fail (de) + quick_fail_en: Quick Fail (eng) + criterion_de: Kriterium/Grundlage (de) + criterion_en: Kriterium/Grundlage (eng) + criterion_details_de: Verstehen (de) + criterion_details_en: Verstehen (eng) + example_de: Beispiel (de) + example_en: Beispiel (eng) + exemption_details_de: Ausnahme (de) + exemption_details_en: Ausnahme (eng) + standard_text_de: WCAG-Text (de) + standard_text_en: WCAG-Text (eng) + test_instructions: Testanleitung + powerpoint_text_de: Powerpoint Text (de) + powerpoint_text_en: Powerpoint Text (eng) + comment: Kommentar + target_disability: Zugänglichkeit + applicability: Anwendbarkeit checklist: id: ID name: Überschrift @@ -65,3 +95,6 @@ de-CH: element: one: Element other: Elemente + principle: + one: Prinzip + other: Prinzipien diff --git a/config/locales/i11yist.yml b/config/locales/i11yist.yml index fc35e1c..a83f572 100644 --- a/config/locales/i11yist.yml +++ b/config/locales/i11yist.yml @@ -44,4 +44,17 @@ de-CH: link_show: "%{model} anzeigen" link_edit: "%{model} bearbeiten" link_destroy: "%{model} löschen" - link_index: "%{model} Liste" \ No newline at end of file + link_index: "%{model} Liste" + disability: + visual: visuell + auditory: auditiv + physical: motorisch + cognitive: kognitiv + applicability: + applicable_to_app: app + applicable_to_web: web + priority: + highest: "Sehr hoch" + high: "Hoch" + medium: "Mittel" + low: "Niedrig" \ No newline at end of file diff --git a/config/puma.rb b/config/puma.rb index 3b8d4f8..60e1b9c 100644 --- a/config/puma.rb +++ b/config/puma.rb @@ -2,34 +2,32 @@ # are invoked here are part of Puma's configuration DSL. For more information # about methods provided by the DSL, see https://puma.io/puma/Puma/DSL.html. -# Puma can serve each request in a thread from an internal thread pool. -# The `threads` method setting takes two numbers: a minimum and maximum. -# Any libraries that use thread pools should be configured to match -# the maximum value specified for Puma. Default is set to 5 threads for minimum -# and maximum; this matches the default thread size of Active Record. -max_threads_count = ENV.fetch('RAILS_MAX_THREADS') { 5 } -min_threads_count = ENV.fetch('RAILS_MIN_THREADS') { max_threads_count } -threads min_threads_count, max_threads_count - -# Specifies that the worker count should equal the number of processors in production. -if ENV['RAILS_ENV'] == 'production' - require 'concurrent-ruby' - worker_count = Integer(ENV.fetch('WEB_CONCURRENCY') { Concurrent.physical_processor_count }) - workers worker_count if worker_count > 1 -end - -# Specifies the `worker_timeout` threshold that Puma will use to wait before -# terminating a worker in development environments. -worker_timeout 3600 if ENV.fetch('RAILS_ENV', 'development') == 'development' +# Puma starts a configurable number of processes (workers) and each process +# serves each request in a thread from an internal thread pool. +# +# The ideal number of threads per worker depends both on how much time the +# application spends waiting for IO operations and on how much you wish to +# to prioritize throughput over latency. +# +# As a rule of thumb, increasing the number of threads will increase how much +# traffic a given process can handle (throughput), but due to CRuby's +# Global VM Lock (GVL) it has diminishing returns and will degrade the +# response time (latency) of the application. +# +# The default is set to 3 threads as it's deemed a decent compromise between +# throughput and latency for the average Rails application. +# +# Any libraries that use a connection pool or another resource pool should +# be configured to provide at least as many connections as the number of +# threads. This includes Active Record's `pool` parameter in `database.yml`. +threads_count = ENV.fetch("RAILS_MAX_THREADS", 3) +threads threads_count, threads_count # Specifies the `port` that Puma will listen on to receive requests; default is 3000. -port ENV.fetch('PORT') { 3000 } - -# Specifies the `environment` that Puma will run in. -environment ENV.fetch('RAILS_ENV') { 'development' } - -# Specifies the `pidfile` that Puma will use. -pidfile ENV.fetch('PIDFILE') { 'tmp/pids/server.pid' } +port ENV.fetch("PORT", 3000) # Allow puma to be restarted by `bin/rails restart` command. plugin :tmp_restart + +# Only use a pidfile when requested +pidfile ENV["PIDFILE"] if ENV["PIDFILE"] diff --git a/config/routes.rb b/config/routes.rb index 4e10e3b..3f34a94 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -18,6 +18,21 @@ Rails.application.routes.draw do # Can be used by load balancers and uptime monitors to verify that the app is live. get 'up' => 'rails/health#show', as: :rails_health_check + if Rails.env.development? + namespace :benchmarking do + post "read_heavy" + post "write_heavy" + post "balanced" + post "link_create" + post "comment_create" + post "link_destroy" + post "comment_destroy" + post "link_show" + post "links_index" + post "user_show" + end + end + # Defines the root path route ("/") root 'home#show' end diff --git a/db/migrate/20240810081701_create_standards.rb b/db/migrate/20240810081701_create_standards.rb new file mode 100644 index 0000000..b1210c0 --- /dev/null +++ b/db/migrate/20240810081701_create_standards.rb @@ -0,0 +1,13 @@ +class CreateStandards < ActiveRecord::Migration[7.2] + def change + create_table :standards do |t| + t.string :name_de + t.string :name_en + t.string :version + t.string :url_de + t.string :url_en + + t.timestamps + end + end +end diff --git a/db/migrate/20240810185205_add_service_name_to_active_storage_blobs.active_storage.rb b/db/migrate/20240810185205_add_service_name_to_active_storage_blobs.active_storage.rb new file mode 100644 index 0000000..a15c6ce --- /dev/null +++ b/db/migrate/20240810185205_add_service_name_to_active_storage_blobs.active_storage.rb @@ -0,0 +1,22 @@ +# This migration comes from active_storage (originally 20190112182829) +class AddServiceNameToActiveStorageBlobs < ActiveRecord::Migration[6.0] + def up + return unless table_exists?(:active_storage_blobs) + + unless column_exists?(:active_storage_blobs, :service_name) + add_column :active_storage_blobs, :service_name, :string + + if configured_service = ActiveStorage::Blob.service.name + ActiveStorage::Blob.unscoped.update_all(service_name: configured_service) + end + + change_column :active_storage_blobs, :service_name, :string, null: false + end + end + + def down + return unless table_exists?(:active_storage_blobs) + + remove_column :active_storage_blobs, :service_name + end +end diff --git a/db/migrate/20240810185206_create_active_storage_variant_records.active_storage.rb b/db/migrate/20240810185206_create_active_storage_variant_records.active_storage.rb new file mode 100644 index 0000000..94ac83a --- /dev/null +++ b/db/migrate/20240810185206_create_active_storage_variant_records.active_storage.rb @@ -0,0 +1,27 @@ +# This migration comes from active_storage (originally 20191206030411) +class CreateActiveStorageVariantRecords < ActiveRecord::Migration[6.0] + def change + return unless table_exists?(:active_storage_blobs) + + # Use Active Record's configured type for primary key + create_table :active_storage_variant_records, id: primary_key_type, if_not_exists: true do |t| + t.belongs_to :blob, null: false, index: false, type: blobs_primary_key_type + t.string :variation_digest, null: false + + t.index %i[ blob_id variation_digest ], name: "index_active_storage_variant_records_uniqueness", unique: true + t.foreign_key :active_storage_blobs, column: :blob_id + end + end + + private + def primary_key_type + config = Rails.configuration.generators + config.options[config.orm][:primary_key_type] || :primary_key + end + + def blobs_primary_key_type + pkey_name = connection.primary_key(:active_storage_blobs) + pkey_column = connection.columns(:active_storage_blobs).find { |c| c.name == pkey_name } + pkey_column.bigint? ? :bigint : pkey_column.type + end +end diff --git a/db/migrate/20240810185207_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb b/db/migrate/20240810185207_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb new file mode 100644 index 0000000..93c8b85 --- /dev/null +++ b/db/migrate/20240810185207_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb @@ -0,0 +1,8 @@ +# This migration comes from active_storage (originally 20211119233751) +class RemoveNotNullOnActiveStorageBlobsChecksum < ActiveRecord::Migration[6.0] + def change + return unless table_exists?(:active_storage_blobs) + + change_column_null(:active_storage_blobs, :checksum, true) + end +end diff --git a/db/migrate/20240819170606_create_principles.rb b/db/migrate/20240819170606_create_principles.rb new file mode 100644 index 0000000..04d2017 --- /dev/null +++ b/db/migrate/20240819170606_create_principles.rb @@ -0,0 +1,10 @@ +class CreatePrinciples < ActiveRecord::Migration[7.2] + def change + create_table :principles do |t| + t.string :name_de + t.string :name_en + + t.timestamps + end + end +end diff --git a/db/migrate/20240820164827_finalize_check_fields.rb b/db/migrate/20240820164827_finalize_check_fields.rb new file mode 100644 index 0000000..ceb0e27 --- /dev/null +++ b/db/migrate/20240820164827_finalize_check_fields.rb @@ -0,0 +1,26 @@ +class FinalizeCheckFields < ActiveRecord::Migration[7.2] + def change + add_column :checks, :number, :integer + add_index :checks, :number, unique: true + + add_column :checks, :name_de, :string + add_column :checks, :name_en, :string + + add_column :checks, :visual, :boolean, null: false, default: false + add_column :checks, :auditory, :boolean, null: false, default: false + add_column :checks, :physical, :boolean, null: false, default: false + add_column :checks, :cognitive, :boolean, null: false, default: false + + add_column :checks, :applicable_to_web, :boolean, null: false, default: false + add_column :checks, :applicable_to_app, :boolean, null: false, default: false + + add_reference :checks, :principle, foreign_key: true + + add_column :checks, :external_number, :string, null: true + add_column :checks, :conformity_level, :integer, null: false, default: 0 + add_column :checks, :priority, :integer, null: false, default: 0 + + add_column :checks, :manual_test, :boolean, null: false, default: true + add_column :checks, :test_url, :string, null: true + end +end diff --git a/db/migrate/20240830083327_add_checks_standards_join_table.rb b/db/migrate/20240830083327_add_checks_standards_join_table.rb new file mode 100644 index 0000000..c8548e4 --- /dev/null +++ b/db/migrate/20240830083327_add_checks_standards_join_table.rb @@ -0,0 +1,5 @@ +class AddChecksStandardsJoinTable < ActiveRecord::Migration[7.2] + def change + create_join_table :checks, :standards + end +end diff --git a/db/migrate/20240830134641_add_checks_links_join_table.rb b/db/migrate/20240830134641_add_checks_links_join_table.rb new file mode 100644 index 0000000..a62aa4d --- /dev/null +++ b/db/migrate/20240830134641_add_checks_links_join_table.rb @@ -0,0 +1,5 @@ +class AddChecksLinksJoinTable < ActiveRecord::Migration[7.2] + def change + create_join_table :checks, :links + end +end diff --git a/db/schema.rb b/db/schema.rb index 98809d5..7b21686 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_07_25_173433) do +ActiveRecord::Schema[7.2].define(version: 2024_08_30_134641) do create_table "action_text_rich_texts", force: :cascade do |t| t.string "name", null: false t.text "body" @@ -73,6 +73,36 @@ ActiveRecord::Schema[7.1].define(version: 2024_07_25_173433) do t.integer "level" t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.boolean "applicability_web", default: false, null: false + t.boolean "applicability_app", default: false, null: false + t.string "exernal_number" + t.integer "number" + t.string "name_de" + t.string "name_en" + t.boolean "visual", default: false, null: false + t.boolean "auditory", default: false, null: false + t.boolean "physical", default: false, null: false + t.boolean "cognitive", default: false, null: false + t.boolean "applicable_to_web", default: false, null: false + t.boolean "applicable_to_app", default: false, null: false + t.integer "principle_id" + t.string "external_number" + t.integer "conformity_level", default: 0, null: false + t.integer "priority", default: 0, null: false + t.boolean "manual_test", default: true, null: false + t.string "test_url" + t.index ["number"], name: "index_checks_on_number", unique: true + t.index ["principle_id"], name: "index_checks_on_principle_id" + end + + create_table "checks_links", id: false, force: :cascade do |t| + t.integer "check_id", null: false + t.integer "link_id", null: false + end + + create_table "checks_standards", id: false, force: :cascade do |t| + t.integer "check_id", null: false + t.integer "standard_id", null: false end create_table "elements", force: :cascade do |t| @@ -102,12 +132,29 @@ ActiveRecord::Schema[7.1].define(version: 2024_07_25_173433) do t.index ["link_category_id"], name: "index_links_on_link_category_id" end + create_table "principles", force: :cascade do |t| + t.string "name_de" + t.string "name_en" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "reports", force: :cascade do |t| t.string "name" t.datetime "created_at", null: false t.datetime "updated_at", null: false end + create_table "standards", force: :cascade do |t| + t.string "name_de" + t.string "name_en" + t.string "version" + t.string "url_de" + t.string "url_en" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "success_criteria", force: :cascade do |t| t.integer "element_id", null: false t.string "title" @@ -122,6 +169,7 @@ ActiveRecord::Schema[7.1].define(version: 2024_07_25_173433) do add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id" add_foreign_key "checklist_entries", "checklists" add_foreign_key "checklist_entries", "checks" + add_foreign_key "checks", "principles" add_foreign_key "elements", "reports" add_foreign_key "links", "link_categories" add_foreign_key "success_criteria", "elements" diff --git a/db/seeds.rb b/db/seeds.rb index 4fbd6ed..38c0424 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -1,9 +1,21 @@ -# This file should ensure the existence of records required to run the application in every environment (production, -# development, test). The code here should be idempotent so that it can be executed at any point in every environment. -# The data can then be loaded with the bin/rails db:seed command (or created alongside the database with db:setup). -# -# Example: -# -# ["Action", "Comedy", "Drama", "Horror"].each do |genre_name| -# MovieGenre.find_or_create_by!(name: genre_name) -# end +# Seed Standards +Standard.create!(name_de: "WCAG", + name_en: "WCAG", + version: "2.1", + url_de: "https://outline-rocks.github.io/wcag/translations/WCAG21-de/", + url_en: "https://www.w3.org/TR/WCAG21/") +Standard.create!(name_de: "eCH-0059", + name_en: "eCH-0059", + version: "3.0", + url_de: "https://www.ech.ch/de/ech/ech-0059/3.0", + url_en: "https://www.ech.ch/de/ech/ech-0059/3.0") +Standard.create!(name_de: "EN 301 549", + name_en: "EN 301 549", + version: "V3", + url_de: "https://www.etsi.org/deliver/etsi_en/301500_301599/301549/03.02.01_60/en_301549v030201p.pdf", + url_en: "https://www.etsi.org/deliver/etsi_en/301500_301599/301549/03.02.01_60/en_301549v030201p.pdf") + +Principle.create!(name_de: "Wahrnehmbar", name_en: "Perceivable") +Principle.create!(name_de: "Bedienbar", name_en: "Operable") +Principle.create!(name_de: "Verständlich", name_en: "Understandable") +Principle.create!(name_de: "Robust", name_en: "Robust") \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 877ee78..769d603 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,7 +14,7 @@ services: - ./:/app:cached - ${PWD}:${PWD} - ${HOME}/.tabby-client:/home/app/.tabby-client - working_dir: ${PWD} + - ${SSH_AUTH_SOCK}:/ssh-agent environment: RAILS_ENV: development LOG_LEVEL: debug diff --git a/lib/tasks/import.rake b/lib/tasks/import.rake index 44f95cf..3e14078 100644 --- a/lib/tasks/import.rake +++ b/lib/tasks/import.rake @@ -1,7 +1,9 @@ +# frozen_string_literal: true + namespace :import do - desc 'Import WCAG2.1 in german' + desc "Import WCAG2.1 in german" task wcag21de: :environment do - URL = 'https://outline-rocks.github.io/wcag/translations/WCAG21-de/' + URL = "https://outline-rocks.github.io/wcag/translations/WCAG21-de/" doc = Nokogiri::HTML5(URI.open(URL)) @@ -10,19 +12,19 @@ namespace :import do # standard.description = doc.css('#abstract p').map(&:to_s).join # standard.save! - doc.css('section.principle').each do |principle_node| - _principle_id = principle_node.attributes['id'].value - _principle_title = principle_node.css('h2').first.content + doc.css("section.principle").each do |principle_node| + _principle_id = principle_node.attributes["id"].value + _principle_title = principle_node.css("h2").first.content # principle = standard.principles.find_or_create_by(code: principle_id) # principle.name = principle_title.scan(/\d+\. (.*)/).first.last # principle.number = principle_title.scan(/(\d+)\..*/).first.last # principle.save! - principle_node.css('section').each do |guideline_node| - next unless guideline_node.css('h3').first + principle_node.css("section").each do |guideline_node| + next unless guideline_node.css("h3").first - guideline_title = guideline_node.css('h3').first.content - guideline_text = guideline_node.css('p').first + guideline_title = guideline_node.css("h3").first.content + guideline_text = guideline_node.css("p").first _guideline_number = guideline_title.scan(/Richtlinie \d+\.(\d+).*/).first.last # guideline = principle.guidelines.find_or_create_by(number: guideline_number) @@ -31,9 +33,9 @@ namespace :import do # guideline.save! - guideline_node.css('section').each do |sc| - sc_title = sc.css('h4').first.content.scan(/Erfolgskriterium \d+\.\d+\.\d+(.*)/).first.last - sc_level = sc.css('p').first.content.scan(/\(Stufe (A+)\)/).first.last + guideline_node.css("section").each do |sc| + sc_title = sc.css("h4").first.content.scan(/Erfolgskriterium \d+\.\d+\.\d+(.*)/).first.last + sc_level = sc.css("p").first.content.scan(/\(Stufe (A+)\)/).first.last # sc_hints = sc.css('div p').map { ReverseMarkdown.convert(_1.to_s) } # _sc_number = sc_title.scan(/Erfolgskriterium \d+\.\d+\.(\d+).*/).first.last @@ -41,7 +43,7 @@ namespace :import do success_criterion = Check.find_or_create_by(name: sc_title) success_criterion.name = sc_title text = "