From 25672aabb00fee5d875cfb10cc40e0158a1b2b70 Mon Sep 17 00:00:00 2001 From: Christoph Haas Date: Tue, 25 Feb 2025 21:57:16 +0100 Subject: [PATCH] Update to Rails 7.2 --- Gemfile | 14 +- Gemfile.lock | 361 +++++++++--------- app/assets/builds/application.css | 1 + app/assets/config/manifest.js | 4 + app/assets/stylesheets/_settings.scss | 143 ++++--- app/assets/stylesheets/application.scss | 2 + app/assets/stylesheets/browserslist | 4 + app/controllers/packages_controller.rb | 4 +- app/controllers/welcome_controller.rb | 5 +- app/models/package.rb | 7 + app/models/screenshot.rb | 1 + app/views/layouts/application.html.erb___ | 19 + app/views/welcome/home.slim | 12 +- bin/sass | 17 - bin/sass-convert | 17 - bin/setup | 8 +- config/application.rb | 9 +- config/environments/development.rb | 25 +- config/environments/production.rb | 90 ++--- config/environments/test.rb | 35 +- config/initializers/assets.rb | 2 +- .../initializers/content_security_policy.rb | 4 +- .../initializers/filter_parameter_logging.rb | 8 +- .../new_framework_defaults_7_2.rb | 70 ++++ config/initializers/permissions_policy.rb | 20 +- config/puma.rb | 65 ++-- doc/README.Installation on Dokku.md | 212 ++++++++++ doc/README.Installation.md | 2 +- lib/deb_importer.rb | 37 +- public/406-unsupported-browser.html | 66 ++++ test/controllers/packages_controller_test.rb | 7 + 31 files changed, 836 insertions(+), 435 deletions(-) create mode 100644 app/assets/builds/application.css create mode 100644 app/assets/config/manifest.js create mode 100644 app/assets/stylesheets/browserslist create mode 100644 app/views/layouts/application.html.erb___ delete mode 100755 bin/sass delete mode 100755 bin/sass-convert create mode 100644 config/initializers/new_framework_defaults_7_2.rb create mode 100644 doc/README.Installation on Dokku.md create mode 100644 public/406-unsupported-browser.html diff --git a/Gemfile b/Gemfile index 97fabcd..42c94f5 100644 --- a/Gemfile +++ b/Gemfile @@ -21,14 +21,15 @@ gem 'image_processing' gem 'mini_magick' # Use Puma as the app server -gem 'puma', '~> 3.0' +gem 'puma', '~> 6.6.0' # Use SCSS for stylesheets -gem 'sass-rails', '~> 5.0' +#gem 'sass-rails', '~> 6.0.0' +gem 'dartsass-rails', '~> 0.5.1' # TODO: ruby sass is decprecated # Use Uglifier as compressor for JavaScript assets -gem 'uglifier', '>= 1.3.0' +gem 'uglifier', '>= 4.2.1' # See https://github.com/rails/execjs#readme for more supported runtimes # gem 'therubyracer', platforms: :ruby @@ -40,7 +41,7 @@ gem 'jquery-rails' gem 'turbolinks', '~> 5' # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder -gem 'jbuilder', '~> 2.12' +gem 'jbuilder', '~> 2.13.0' # Use Redis adapter to run Action Cable in production # gem 'redis', '~> 3.0' @@ -111,7 +112,8 @@ end # Zurb Foundation # https://github.com/zurb/foundation-rails -gem 'foundation-rails', '~> 6.6' +gem 'foundation-rails', '~> 6.9.0.0' +gem 'autoprefixer-rails' # Pagination gem 'will_paginate' @@ -137,7 +139,7 @@ gem 'font-awesome-rails' # gem "recaptcha", require: "recaptcha/rails" -gem 'sprockets' +gem 'sprockets-rails' # gem "activemodel-serializers-xml" diff --git a/Gemfile.lock b/Gemfile.lock index ca98737..20f02c7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,100 +1,100 @@ GEM remote: https://rubygems.org/ specs: - actioncable (7.1.3.4) - actionpack (= 7.1.3.4) - activesupport (= 7.1.3.4) + actioncable (7.2.2.1) + actionpack (= 7.2.2.1) + activesupport (= 7.2.2.1) 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.2.1) + actionpack (= 7.2.2.1) + activejob (= 7.2.2.1) + activerecord (= 7.2.2.1) + activestorage (= 7.2.2.1) + activesupport (= 7.2.2.1) + mail (>= 2.8.0) + actionmailer (7.2.2.1) + actionpack (= 7.2.2.1) + actionview (= 7.2.2.1) + activejob (= 7.2.2.1) + activesupport (= 7.2.2.1) + 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.2.1) + actionview (= 7.2.2.1) + activesupport (= 7.2.2.1) 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.2.1) + actionpack (= 7.2.2.1) + activerecord (= 7.2.2.1) + activestorage (= 7.2.2.1) + activesupport (= 7.2.2.1) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.1.3.4) - activesupport (= 7.1.3.4) + actionview (7.2.2.1) + activesupport (= 7.2.2.1) 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.2.1) + activesupport (= 7.2.2.1) 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.2.1) + activesupport (= 7.2.2.1) + activerecord (7.2.2.1) + activemodel (= 7.2.2.1) + activesupport (= 7.2.2.1) 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 (7.2.2.1) + actionpack (= 7.2.2.1) + activejob (= 7.2.2.1) + activerecord (= 7.2.2.1) + activesupport (= 7.2.2.1) marcel (~> 1.0) - activesupport (7.1.3.4) + activesupport (7.2.2.1) 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) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) addressable (2.8.7) public_suffix (>= 2.0.2, < 7.0) aes_key_wrap (1.1.0) ansi (1.5.0) attr_required (1.0.2) + autoprefixer-rails (10.4.19.0) + execjs (~> 2) babel-source (5.8.35) babel-transpiler (0.7.0) babel-source (>= 4.0, < 6) execjs (~> 2.0) 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) rouge (>= 1.0.0) - bigdecimal (3.1.8) + bigdecimal (3.1.9) bindata (2.5.0) binding_of_caller (1.0.1) debug_inspector (>= 1.2.0) - bootsnap (1.18.3) + bootsnap (1.18.4) msgpack (~> 1.2) builder (3.3.0) byebug (11.1.3) @@ -112,12 +112,15 @@ GEM xpath (~> 3.2) choice (0.2.0) coderay (1.1.3) - concurrent-ruby (1.3.3) - connection_pool (2.4.1) + concurrent-ruby (1.3.5) + connection_pool (2.5.0) content_disposition (1.0.0) crass (1.0.6) - date (3.3.4) - debug (1.9.2) + dartsass-rails (0.5.1) + railties (>= 6.0.0) + sass-embedded (~> 1.63) + date (3.4.1) + debug (1.10.0) irb (~> 1.10) reline (>= 0.3.8) debug_inspector (1.2.0) @@ -132,38 +135,44 @@ GEM drb (2.2.1) email_validator (2.2.4) activemodel - erubi (1.13.0) - execjs (2.9.1) - factory_bot (6.4.6) - activesupport (>= 5.0.0) - factory_bot_rails (6.4.3) - factory_bot (~> 6.4) + erubi (1.13.1) + execjs (2.10.0) + factory_bot (6.5.1) + activesupport (>= 6.1.0) + factory_bot_rails (6.4.4) + factory_bot (~> 6.5) railties (>= 5.0.0) - faraday (2.10.0) - faraday-net_http (>= 2.0, < 3.2) + faraday (2.12.2) + faraday-net_http (>= 2.0, < 3.5) + json logger faraday-follow_redirects (0.3.0) faraday (>= 1, < 3) - faraday-net_http (3.1.0) - net-http - fastimage (2.3.1) - ffi (1.17.0-x86_64-linux-gnu) - font-awesome-rails (4.7.0.8) - railties (>= 3.2, < 8.0) + faraday-net_http (3.4.0) + net-http (>= 0.5.0) + fastimage (2.4.0) + ffi (1.17.1-x86_64-linux-gnu) + font-awesome-rails (4.7.0.9) + railties (>= 3.2, < 9.0) formatador (1.1.0) - foundation-rails (6.6.2.0) + foundation-rails (6.9.0.0) railties (>= 3.1.0) - sass (>= 3.3.0) - sprockets-es6 (>= 0.9.0) + sassc + sprockets-es6 globalid (1.2.1) activesupport (>= 6.1) + google-protobuf (4.29.3-x86_64-linux) + bigdecimal + rake (>= 13) gravtastic (3.2.6) - guard (2.18.1) + guard (2.19.1) formatador (>= 0.2.4) listen (>= 2.7, < 4.0) + logger (~> 1.6) lumberjack (>= 1.0.12, < 2.0) nenv (~> 0.1) notiffany (~> 0.0) + ostruct (~> 0.6) pry (>= 0.13.0) shellany (~> 0.0) thor (>= 0.18.1) @@ -175,23 +184,25 @@ GEM guard (~> 2.11) guard-compat (~> 1.0) hashie (5.0.0) - i18n (1.14.5) + i18n (1.14.7) concurrent-ruby (~> 1.0) - image_processing (1.12.2) - mini_magick (>= 4.9.5, < 5) + image_processing (1.14.0) + mini_magick (>= 4.9.5, < 6) ruby-vips (>= 2.0.17, < 3) - io-console (0.7.2) - irb (1.14.0) + io-console (0.8.0) + irb (1.15.1) + pp (>= 0.6.0) rdoc (>= 4.0.0) reline (>= 0.4.2) - jbuilder (2.12.0) + jbuilder (2.13.0) actionview (>= 5.0.0) activesupport (>= 5.0.0) jquery-rails (4.6.0) rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) - json-jwt (1.16.6) + json (2.10.1) + json-jwt (1.16.7) activesupport (>= 4.2) aes_key_wrap base64 @@ -202,8 +213,8 @@ GEM listen (3.9.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - logger (1.6.0) - loofah (2.22.0) + logger (1.6.5) + loofah (2.24.0) crass (~> 1.0.2) nokogiri (>= 1.12.0) lumberjack (1.2.10) @@ -215,33 +226,34 @@ GEM marcel (1.0.4) matrix (0.4.2) method_source (1.1.0) - mini_magick (4.13.2) + mini_magick (5.1.2) + benchmark + logger mini_mime (1.1.5) - minitest (5.24.1) - minitest-rails (7.1.1) + minitest (5.25.4) + minitest-rails (7.2.0) minitest (~> 5.20) - railties (>= 7.1.0, < 8.0.0) + railties (>= 7.2.0, < 8.0.0) minitest-reporters (1.7.1) ansi builder minitest (>= 5.0) ruby-progressbar - msgpack (1.7.2) - mutex_m (0.2.0) + msgpack (1.8.0) nenv (0.3.0) - net-http (0.4.1) + net-http (0.6.0) uri - net-imap (0.4.14) + net-imap (0.5.6) date net-protocol net-pop (0.1.2) net-protocol net-protocol (0.2.2) timeout - net-smtp (0.5.0) + net-smtp (0.5.1) net-protocol - nio4r (2.7.3) - nokogiri (1.16.6-x86_64-linux) + nio4r (2.7.4) + nokogiri (1.18.2-x86_64-linux-gnu) racc (~> 1.4) notiffany (0.1.3) nenv (~> 0.1) @@ -256,7 +268,7 @@ GEM omniauth_openid_connect (0.8.0) omniauth (>= 1.9, < 3) openid_connect (~> 2.2) - openid_connect (2.3.0) + openid_connect (2.3.1) activemodel attr_required (>= 1.0.0) email_validator @@ -270,20 +282,26 @@ GEM validate_url webfinger (~> 2.0) orm_adapter (0.5.0) - pg (1.5.6) - pg_search (2.3.6) - activerecord (>= 5.2) - activesupport (>= 5.2) + ostruct (0.6.1) + pg (1.5.9) + pg_search (2.3.7) + activerecord (>= 6.1) + activesupport (>= 6.1) + pp (0.6.2) + prettyprint + prettyprint (0.2.0) prism (1.3.0) - pry (0.14.2) + pry (0.15.2) coderay (~> 1.1) method_source (~> 1.0) - psych (5.1.2) + psych (5.2.3) + date stringio - public_suffix (6.0.0) - puma (3.12.6) - racc (1.8.0) - rack (2.2.9) + public_suffix (6.0.1) + puma (6.6.0) + nio4r (~> 2.0) + racc (1.8.1) + rack (3.1.9) rack-oauth2 (2.2.1) activesupport attr_required @@ -291,30 +309,31 @@ GEM faraday-follow_redirects json-jwt (>= 1.11.0) rack (>= 2.1.0) - rack-protection (3.2.0) + rack-protection (4.1.1) base64 (>= 0.1.0) - rack (~> 2.2, >= 2.2.4) - rack-session (1.0.2) - rack (< 3) - rack-test (2.1.0) + logger (>= 1.6.0) + rack (>= 3.0.0, < 4) + rack-session (2.1.0) + base64 (>= 0.1.0) + rack (>= 3.0.0) + rack-test (2.2.0) rack (>= 1.3) - rackup (1.0.0) - rack (< 3) - webrick - 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) + rackup (2.2.1) + rack (>= 3) + rails (7.2.2.1) + actioncable (= 7.2.2.1) + actionmailbox (= 7.2.2.1) + actionmailer (= 7.2.2.1) + actionpack (= 7.2.2.1) + actiontext (= 7.2.2.1) + actionview (= 7.2.2.1) + activejob (= 7.2.2.1) + activemodel (= 7.2.2.1) + activerecord (= 7.2.2.1) + activestorage (= 7.2.2.1) + activesupport (= 7.2.2.1) bundler (>= 1.15.0) - railties (= 7.1.3.4) + railties (= 7.2.2.1) rails-dom-testing (2.2.0) activesupport (>= 5.0.0) minitest @@ -327,13 +346,13 @@ GEM rails-healthcheck (1.4.0) actionpack railties - rails-html-sanitizer (1.6.0) + rails-html-sanitizer (1.6.2) loofah (~> 2.21) - nokogiri (~> 1.14) - railties (7.1.3.4) - actionpack (= 7.1.3.4) - activesupport (= 7.1.3.4) - irb + 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) + railties (7.2.2.1) + actionpack (= 7.2.2.1) + activesupport (= 7.2.2.1) + irb (~> 1.13) rackup (>= 1.0.0) rake (>= 12.2) thor (~> 1.0, >= 1.2.2) @@ -344,43 +363,37 @@ GEM ffi (~> 1.0) rbs (3.8.1) logger - rdoc (6.7.0) + rdoc (6.12.0) psych (>= 4.0.0) - regexp_parser (2.9.2) - reline (0.5.9) + regexp_parser (2.10.0) + reline (0.6.0) io-console (~> 0.5) responders (3.1.1) actionpack (>= 5.2) railties (>= 5.2) - rexml (3.3.1) - strscan - rouge (4.3.0) + rexml (3.4.0) + rouge (4.5.1) ruby-graphviz (1.2.5) rexml - ruby-lsp (0.23.8) + ruby-lsp (0.23.10) language_server-protocol (~> 3.17.0) prism (>= 1.2, < 2.0) rbs (>= 3, < 4) sorbet-runtime (>= 0.5.10782) ruby-progressbar (1.13.0) - ruby-vips (2.2.1) + ruby-vips (2.2.3) ffi (~> 1.12) - rubyzip (2.3.2) + logger + rubyzip (2.4.1) rufo (0.18.0) - sass (3.7.4) - sass-listen (~> 4.0.0) - sass-listen (4.0.0) - rb-fsevent (~> 0.9, >= 0.9.4) - rb-inotify (~> 0.9, >= 0.9.7) - sass-rails (5.1.0) - railties (>= 5.2.0) - sass (~> 3.1) - sprockets (>= 2.8, < 4.0) - sprockets-rails (>= 2.0, < 4.0) - tilt (>= 1.1, < 3) + sass-embedded (1.83.4-x86_64-linux-gnu) + google-protobuf (~> 4.29) + sassc (2.4.0) + ffi (~> 1.9) sdoc (2.6.1) rdoc (>= 5.0) - selenium-webdriver (4.22.0) + securerandom (0.4.1) + selenium-webdriver (4.28.0) base64 (~> 0.2) logger (~> 1.4) rexml (~> 3.2, >= 3.2.5) @@ -393,46 +406,45 @@ GEM slim (5.2.1) temple (~> 0.10.0) tilt (>= 2.1.0) - slim-rails (3.6.3) + slim-rails (3.7.0) actionpack (>= 3.1) railties (>= 3.1) slim (>= 3.0, < 6.0, != 5.0.0) - sorbet-runtime (0.5.11798) + sorbet-runtime (0.5.11820) spring (2.1.1) spring-watcher-listen (2.0.1) listen (>= 2.7, < 4.0) spring (>= 1.2, < 3.0) - sprockets (3.7.3) - base64 + sprockets (4.2.1) concurrent-ruby (~> 1.0) - rack (> 1, < 3) + rack (>= 2.2.4, < 4) sprockets-es6 (0.9.2) babel-source (>= 5.8.11) babel-transpiler sprockets (>= 3.0.0) - sprockets-rails (3.5.1) + sprockets-rails (3.5.2) actionpack (>= 6.1) activesupport (>= 6.1) sprockets (>= 3.0.0) - stringio (3.1.1) - strscan (3.1.0) + stringio (3.1.2) swd (2.0.3) activesupport (>= 3) attr_required (>= 0.0.5) faraday (~> 2.0) faraday-follow_redirects temple (0.10.3) - thor (1.3.1) - tilt (2.4.0) - timeout (0.4.1) + thor (1.3.2) + tilt (2.6.0) + timeout (0.4.3) turbolinks (5.2.1) turbolinks-source (~> 5.2) turbolinks-source (5.2.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) - uglifier (4.2.0) + uglifier (4.2.1) execjs (>= 0.3.0, < 3) - uri (0.13.0) + uri (1.0.2) + useragent (0.16.11) validate_url (1.0.15) activemodel (>= 3.0.0) public_suffix @@ -442,9 +454,9 @@ GEM activesupport faraday (~> 2.0) faraday-follow_redirects - webrick (1.8.1) websocket (1.2.11) - websocket-driver (0.7.6) + websocket-driver (0.7.7) + base64 websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) will_paginate (4.0.1) @@ -452,12 +464,13 @@ GEM will_paginate (>= 3.0.3) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.6.16) + zeitwerk (2.7.1) PLATFORMS x86_64-linux DEPENDENCIES + autoprefixer-rails better_errors binding_of_caller bootsnap @@ -465,17 +478,18 @@ DEPENDENCIES bzip2-ffi cancancan capybara + dartsass-rails (~> 0.5.1) debug devise factory_bot_rails fastimage font-awesome-rails - foundation-rails (~> 6.6) + foundation-rails (~> 6.9.0.0) gravtastic guard-minitest guard-rails image_processing - jbuilder (~> 2.12) + jbuilder (~> 2.13.0) jquery-rails listen (~> 3.5) mini_magick @@ -487,22 +501,21 @@ DEPENDENCIES omniauth_openid_connect pg pg_search - puma (~> 3.0) + puma (~> 6.6.0) rails (~> 7.1) rails-erd rails-healthcheck ruby-lsp rufo - sass-rails (~> 5.0) sdoc selenium-webdriver shrine (~> 3.0) slim-rails spring spring-watcher-listen (~> 2.0.0) - sprockets + sprockets-rails turbolinks (~> 5) - uglifier (>= 1.3.0) + uglifier (>= 4.2.1) will_paginate will_paginate-foundation diff --git a/app/assets/builds/application.css b/app/assets/builds/application.css new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/app/assets/builds/application.css @@ -0,0 +1 @@ + diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js new file mode 100644 index 0000000..9e0e087 --- /dev/null +++ b/app/assets/config/manifest.js @@ -0,0 +1,4 @@ +//= link_tree ../images +//= link_directory ../javascripts .js +//= link_directory ../stylesheets .css +//= link application.js diff --git a/app/assets/stylesheets/_settings.scss b/app/assets/stylesheets/_settings.scss index 3b800ff..cba0260 100644 --- a/app/assets/stylesheets/_settings.scss +++ b/app/assets/stylesheets/_settings.scss @@ -58,8 +58,9 @@ // 53. Title Bar // 54. Tooltip // 55. Top Bar -// 56. Xy Grid +// 57. Xy Grid +@use "sass:color"; @import 'util/util'; // 1. Global @@ -69,22 +70,21 @@ $global-font-size: 100%; $global-width: rem-calc(1200); $global-lineheight: 1.5; $foundation-palette: ( - primary: #c70338, - secondary: #767676, - success: #3adb76, - warning: #ffae00, - alert: #cc4b37, + "primary": #1779ba, + "secondary": #767676, + "success": #3adb76, + "warning": #ffae00, + "alert": #cc4b37, ); $light-gray: #e6e6e6; $medium-gray: #cacaca; $dark-gray: #8a8a8a; $black: #0a0a0a; $white: #fefefe; -// $body-background: $white; -$body-background: #f2f2f2; +$body-background: $white; $body-font-color: $black; -$body-font-family: 'Droid Sans', sans-serif; -// $body-font-family: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif; +$body-font-family: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif; +$body-safe-padding: false; $body-antialiased: true; $global-margin: 1rem; $global-padding: 1rem; @@ -92,8 +92,7 @@ $global-position: 1rem; $global-weight-normal: normal; $global-weight-bold: bold; $global-radius: 0; -$global-menu-padding: 0.3rem 0.5rem; -// $global-menu-padding: 0.7rem 1rem; +$global-menu-padding: 0.7rem 1rem; $global-menu-nested-margin: 1rem; $global-text-direction: ltr; $global-flexbox: true; @@ -101,18 +100,27 @@ $global-prototype-breakpoints: false; $global-button-cursor: auto; $global-color-pick-contrast-tolerance: 0; $print-transparent-backgrounds: true; +$print-hrefs: true; @include add-foundation-colors; // 2. Breakpoints // -------------- +$-zf-size: null; $breakpoints: ( - small: 0, - medium: 640px, - large: 1024px, - xlarge: 1200px, - xxlarge: 1440px, + "small": 0, + "medium": 640px, + "large": 1024px, + "xlarge": 1200px, + "xxlarge": 1440px, +); +$breakpoints-hidpi: ( + "hidpi-1": 1, + "hidpi-1-5": 1.5, + "hidpi-2": 2, + "retina": 2, + "hidpi-3": 3 ); $print-breakpoint: large; $breakpoint-classes: (small medium large); @@ -143,19 +151,19 @@ $header-margin-bottom: 0.5rem; $header-styles: ( small: ( 'h1': ('font-size': 24), - 'h2': ('font-size': 16), - 'h3': ('font-size': 14), - 'h4': ('font-size': 13), - 'h5': ('font-size': 12), - 'h6': ('font-size': 11), + 'h2': ('font-size': 20), + 'h3': ('font-size': 19), + 'h4': ('font-size': 18), + 'h5': ('font-size': 17), + 'h6': ('font-size': 16), ), medium: ( - 'h1': ('font-size': 40), - 'h2': ('font-size': 32), - 'h3': ('font-size': 28), - 'h4': ('font-size': 26), - 'h5': ('font-size': 24), - 'h6': ('font-size': 22), + 'h1': ('font-size': 48), + 'h2': ('font-size': 40), + 'h3': ('font-size': 31), + 'h4': ('font-size': 25), + 'h5': ('font-size': 20), + 'h6': ('font-size': 16), ), ); $header-text-rendering: optimizeLegibility; @@ -164,12 +172,7 @@ $header-small-font-color: $medium-gray; $paragraph-lineheight: 1.6; $paragraph-margin-bottom: 1rem; $paragraph-text-rendering: optimizeLegibility; -$code-color: $black; -$code-font-family: $font-family-monospace; -$code-font-weight: $global-weight-normal; -$code-background: $light-gray; -$code-border: 1px solid $medium-gray; -$code-padding: rem-calc(2 5 1); +$enable-code-inline: true; $anchor-color: $primary-color; $anchor-color-hover: scale-color($anchor-color, $lightness: -14%); $anchor-text-decoration: none; @@ -189,9 +192,7 @@ $defnlist-term-margin-bottom: 0.3rem; $blockquote-color: $dark-gray; $blockquote-padding: rem-calc(9 20 0 19); $blockquote-border: 1px solid $medium-gray; -$cite-font-size: rem-calc(13); -$cite-color: $dark-gray; -$cite-pseudo-content: '\2014 \0020'; +$enable-cite-block: true; $keystroke-font: $font-family-monospace; $keystroke-color: $black; $keystroke-background: $light-gray; @@ -210,6 +211,17 @@ $subheader-font-weight: $global-weight-normal; $subheader-margin-top: 0.2rem; $subheader-margin-bottom: 0.5rem; $stat-font-size: 2.5rem; +$cite-color: $dark-gray; +$cite-font-size: rem-calc(13); +$cite-pseudo-content: '\2014 \0020'; +$code-color: $black; +$code-font-family: $font-family-monospace; +$code-font-weight: $global-weight-normal; +$code-background: $light-gray; +$code-border: 1px solid $medium-gray; +$code-padding: rem-calc(2 5 1); +$code-block-padding: 1rem; +$code-block-margin-bottom: 1.5rem; // 6. Abide // -------- @@ -227,6 +239,8 @@ $input-error-font-weight: $global-weight-bold; $accordion-background: $white; $accordion-plusminus: true; +$accordion-plus-content: '\002B'; +$accordion-minus-content: '\2013'; $accordion-title-font-size: rem-calc(12); $accordion-item-color: $primary-color; $accordion-item-background-hover: $light-gray; @@ -282,6 +296,7 @@ $breadcrumbs-item-separator-color: $medium-gray; // ---------- $button-font-family: inherit; +$button-font-weight: null; $button-padding: 0.85em 1em; $button-margin: 0 0 $global-margin 0; $button-fill: solid; @@ -289,8 +304,8 @@ $button-background: $primary-color; $button-background-hover: scale-color($button-background, $lightness: -15%); $button-color: $white; $button-color-alt: $black; -//$button-radius: $global-radius; -$button-radius: 0.5rem; +$button-radius: $global-radius; +$button-border: 1px solid transparent; $button-hollow-border-width: 1px; $button-sizes: ( tiny: 0.6rem, @@ -303,6 +318,7 @@ $button-opacity-disabled: 0.25; $button-background-hover-lightness: -20%; $button-hollow-hover-lightness: -50%; $button-transition: background-color 0.25s ease-out, color 0.25s ease-out; +$button-responsive-expanded: false; // 12. Button Group // ---------------- @@ -320,7 +336,11 @@ $callout-background: $white; $callout-background-fade: 85%; $callout-border: 1px solid rgba($black, 0.25); $callout-margin: 0 0 1rem 0; -$callout-padding: 1rem; +$callout-sizes: ( + small: 0.5rem, + default: 1rem, + large: 3rem, +); $callout-font-color: $body-font-color; $callout-font-color-alt: $body-background; $callout-radius: $global-radius; @@ -342,6 +362,8 @@ $card-margin-bottom: $global-margin; // ---------------- $closebutton-position: right top; +$closebutton-z-index: 10; +$closebutton-default-size: medium; $closebutton-offset-horizontal: ( small: 0.66rem, medium: 1rem, @@ -394,8 +416,8 @@ $dropdownmenu-arrow-color: $anchor-color; $dropdownmenu-arrow-size: 6px; $dropdownmenu-arrow-padding: 1.5rem; $dropdownmenu-min-width: 200px; -$dropdownmenu-background: $white; -$dropdownmenu-submenu-background: $dropdownmenu-background; +$dropdownmenu-background: null; +$dropdownmenu-submenu-background: $white; $dropdownmenu-padding: $global-menu-padding; $dropdownmenu-nested-margin: 0; $dropdownmenu-submenu-padding: $dropdownmenu-padding; @@ -442,7 +464,7 @@ $input-background-focus: $white; $input-background-disabled: $light-gray; $input-border: 1px solid $medium-gray; $input-border-focus: 1px solid $dark-gray; -$input-padding: $form-spacing / 2; +$input-padding: $form-spacing * 0.5; $input-shadow: inset 0 1px 2px rgba($black, 0.1); $input-shadow-focus: 0 0 5px $medium-gray; $input-cursor-disabled: not-allowed; @@ -477,9 +499,9 @@ $menu-nested-margin: $global-menu-nested-margin; $menu-items-padding: $global-menu-padding; $menu-simple-margin: 1rem; $menu-item-color-active: $white; +$menu-item-color-alt-active: $black; $menu-item-background-active: get-color(primary); $menu-icon-spacing: 0.25rem; -$menu-item-background-hover: $light-gray; $menu-state-back-compat: true; $menu-centered-back-compat: true; $menu-icons-back-compat: true; @@ -549,6 +571,8 @@ $pagination-ellipsis-color: $black; $pagination-mobile-items: false; $pagination-mobile-current-item: false; $pagination-arrows: true; +$pagination-arrow-previous: '\00AB'; +$pagination-arrow-next: '\00BB'; // 28. Progress Bar // ---------------- @@ -670,8 +694,7 @@ $prototype-separator-margin-top: $global-margin; // -------------------- $prototype-shadow-breakpoints: $global-prototype-breakpoints; -$prototype-box-shadow: 0 2px 5px 0 rgba(0,0,0,.16), - 0 2px 10px 0 rgba(0,0,0,.12); +$prototype-box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12); // 41. Prototype Sizing // -------------------- @@ -759,7 +782,9 @@ $slider-radius: $global-radius; // ---------- $switch-background: $medium-gray; +$switch-background-focus: scale-color($switch-background, $lightness: -10%); $switch-background-active: $primary-color; +$switch-background-active-focus: scale-color($switch-background-active, $lightness: -15%); $switch-height: 2rem; $switch-height-tiny: 1.5rem; $switch-height-small: 1.75rem; @@ -770,6 +795,8 @@ $switch-paddle-background: $white; $switch-paddle-offset: 0.25rem; $switch-paddle-radius: $global-radius; $switch-paddle-transition: all 0.25s ease-out; +$switch-opacity-disabled: 0.5; +$switch-cursor-disabled: not-allowed; // 50. Table // --------- @@ -779,15 +806,15 @@ $table-color-scale: 5%; $table-border: 1px solid smart-scale($table-background, $table-color-scale); $table-padding: rem-calc(8 10 10); $table-hover-scale: 2%; -$table-row-hover: darken($table-background, $table-hover-scale); -$table-row-stripe-hover: darken($table-background, $table-color-scale + $table-hover-scale); +$table-row-hover: color.adjust($table-background, $lightness: -$table-hover-scale); +$table-row-stripe-hover: color.adjust($table-background, $lightness: -($table-color-scale + $table-hover-scale)); $table-is-striped: true; $table-striped-background: smart-scale($table-background, $table-color-scale); $table-stripe: even; -$table-head-background: smart-scale($table-background, $table-color-scale / 2); -$table-head-row-hover: darken($table-head-background, $table-hover-scale); +$table-head-background: smart-scale($table-background, $table-color-scale * 0.5); +$table-head-row-hover: color.adjust($table-head-background, $lightness: -$table-hover-scale); $table-foot-background: smart-scale($table-background, $table-color-scale); -$table-foot-row-hover: darken($table-foot-background, $table-hover-scale); +$table-foot-row-hover: color.adjust($table-foot-background, $lightness: -$table-hover-scale); $table-head-font-color: $body-font-color; $table-foot-font-color: $body-font-color; $show-header-for-stacked: false; @@ -804,7 +831,6 @@ $tab-active-color: $primary-color; $tab-item-font-size: rem-calc(12); $tab-item-background-hover: $white; $tab-item-padding: 1.25rem 1.5rem; -$tab-expand-max: 6; $tab-content-background: $white; $tab-content-border: $light-gray; $tab-content-color: $body-font-color; @@ -813,7 +839,7 @@ $tab-content-padding: 1rem; // 52. Thumbnail // ------------- -$thumbnail-border: solid 4px $white; +$thumbnail-border: 4px solid $white; $thumbnail-margin-bottom: $global-margin; $thumbnail-shadow: 0 0 0 1px rgba($black, 0.2); $thumbnail-shadow-hover: 0 0 6px 1px rgba($primary-color, 0.5); @@ -849,23 +875,22 @@ $tooltip-radius: $global-radius; // 55. Top Bar // ----------- -$topbar-padding: 0; -// $topbar-background: $light-gray; -$topbar-background: #d8d8d8; +$topbar-padding: 0.5rem; +$topbar-background: $light-gray; $topbar-submenu-background: $topbar-background; $topbar-title-spacing: 0.5rem 1rem 0.5rem 0; $topbar-input-width: 200px; $topbar-unstack-breakpoint: medium; -// 56. Xy Grid +// 57. Xy Grid // ----------- $xy-grid: true; $grid-container: $global-width; $grid-columns: 12; $grid-margin-gutters: ( - small: 20px, - medium: 30px + "small": 20px, + "medium": 30px ); $grid-padding-gutters: $grid-margin-gutters; $grid-container-padding: $grid-padding-gutters; diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 2bcc98b..1b79845 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -9,6 +9,8 @@ * compiled file, but it's generally better to create a new file per style scope. * *= require_self +//= require foundation_and_overrides + *= require foundation_and_overrides *= require font-awesome *= require my_styles diff --git a/app/assets/stylesheets/browserslist b/app/assets/stylesheets/browserslist new file mode 100644 index 0000000..6019618 --- /dev/null +++ b/app/assets/stylesheets/browserslist @@ -0,0 +1,4 @@ +last 2 versions +ie >= 9 +Android >= 2.3 +ios >= 7 diff --git a/app/controllers/packages_controller.rb b/app/controllers/packages_controller.rb index add8d0a..c1a19ae 100644 --- a/app/controllers/packages_controller.rb +++ b/app/controllers/packages_controller.rb @@ -341,7 +341,7 @@ class PackagesController < ApplicationController # Return packages matching the criteria given by parameters def query_packages - packages = Package.order(visits: :desc) + packages = Package #.order(visits: :desc) # text search if params[:search].present? @@ -352,7 +352,7 @@ class PackagesController < ApplicationController case params[:show] when 'with' # Enrich the result with the screenshots readable by the current user (CanCanCan) - packages = packages.with_screenshots + packages = packages.with_public_screenshots logger.debug 'Limiting packages to those with screenshots' when 'without' packages = packages.without_screenshots diff --git a/app/controllers/welcome_controller.rb b/app/controllers/welcome_controller.rb index d2dca58..2935bb2 100644 --- a/app/controllers/welcome_controller.rb +++ b/app/controllers/welcome_controller.rb @@ -4,12 +4,13 @@ class WelcomeController < ApplicationController def home @newest_upload = Screenshot.where(approved: true).first - @most_popular_package = Package.with_screenshots.order(visits: :desc).first + #@most_popular_package = Package.with_screenshots.order(visits: :desc).first + @random_pick = Package.with_public_screenshots.order("RANDOM()").first @package_count = Package.count # Get up 100 screenshots where the packages have the most visits - query = Package.without_screenshots.order(visits: :desc) + query = Package.without_screenshots #.order(visits: :desc) count = query.count random_offset = rand( [100, count].min ) @most_wanted_package = query.offset(random_offset).first diff --git a/app/models/package.rb b/app/models/package.rb index d8775ba..f4c7169 100644 --- a/app/models/package.rb +++ b/app/models/package.rb @@ -51,6 +51,13 @@ class Package < ApplicationRecord where(id: subselect) end + # Return a query of all packages that have approved screenshots + def self.with_public_screenshots + # Query for all packages who's ID appears in a screenshot's "package_id" field + subselect = Screenshot.visible.approved.select(:package_id) + where(id: subselect) + end + # Return a list of packages that have screenshots to be moderated def self.need_moderation Package.joins(:screenshots).where('screenshots.approved=false').distinct(:name) diff --git a/app/models/screenshot.rb b/app/models/screenshot.rb index df71257..b8ee8da 100644 --- a/app/models/screenshot.rb +++ b/app/models/screenshot.rb @@ -8,6 +8,7 @@ class Screenshot < ApplicationRecord default_scope { order(approved: :asc, hidden: :asc, created_at: :desc) } scope :approved, -> { where(approved: true) } + scope :visible, -> { where(hidden: false) } # Shrine include ImageUploader::Attachment(:simage) # adds an `simage` virtual attribute diff --git a/app/views/layouts/application.html.erb___ b/app/views/layouts/application.html.erb___ new file mode 100644 index 0000000..cd60004 --- /dev/null +++ b/app/views/layouts/application.html.erb___ @@ -0,0 +1,19 @@ + + + + + + + <%= content_for?(:title) ? yield(:title) : "Untitled" %> + + <%= stylesheet_link_tag "application" %> + <%= javascript_include_tag "application", 'data-turbolinks-track' => true %> + <%= csrf_meta_tags %> + + + + + <%= yield %> + + + diff --git a/app/views/welcome/home.slim b/app/views/welcome/home.slim index 29cc942..83f8ab1 100644 --- a/app/views/welcome/home.slim +++ b/app/views/welcome/home.slim @@ -39,19 +39,19 @@ .small-12.medium-4.cell - h2.text-center Most popular + h2.text-center Random pick .pkgcard .image - - if @most_popular_package - a href=package_path(@most_popular_package.name) - = small_img(@most_popular_package.screenshots.first) + - if @random_pick + a href=package_path(@random_pick.name) + = small_img(@random_pick.screenshots.first) - else 'No uploaded screenshots yet. .text strong - =@most_popular_package.name + =@random_pick.name ' : - =@most_popular_package.description + =@random_pick.description .small-12.medium-4.cell h2.text-center Your help needed diff --git a/bin/sass b/bin/sass deleted file mode 100755 index ef9f699..0000000 --- a/bin/sass +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env ruby -# frozen_string_literal: true -# -# This file was generated by Bundler. -# -# The application 'sass' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require "pathname" -ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -require "rubygems" -require "bundler/setup" - -load Gem.bin_path("sass", "sass") diff --git a/bin/sass-convert b/bin/sass-convert deleted file mode 100755 index 13936f1..0000000 --- a/bin/sass-convert +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env ruby -# frozen_string_literal: true -# -# This file was generated by Bundler. -# -# The application 'sass-convert' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require "pathname" -ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -require "rubygems" -require "bundler/setup" - -load Gem.bin_path("sass", "sass-convert") diff --git a/bin/setup b/bin/setup index ec47b79..ce0ec18 100755 --- a/bin/setup +++ b/bin/setup @@ -1,11 +1,11 @@ #!/usr/bin/env ruby require "fileutils" -# path to your application root. APP_ROOT = File.expand_path("..", __dir__) +APP_NAME = "debshots" def system!(*args) - system(*args) || abort("\n== Command #{args} failed ==") + system(*args, exception: true) end FileUtils.chdir APP_ROOT do @@ -30,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/application.rb b/config/application.rb index 531b8e3..ee13544 100644 --- a/config/application.rb +++ b/config/application.rb @@ -1,6 +1,6 @@ -require_relative 'boot' +require_relative "boot" -require 'rails/all' +require "rails/all" # Require the gems listed in Gemfile, including any gems # you've limited to :test, :development, or :production. @@ -11,7 +11,10 @@ module Debshots # Initialize configuration defaults for originally generated Rails version. config.load_defaults 7.1 - #config.active_support.cache_format_version = 7.1 + # Please, add to the `ignore` list any other `lib` subdirectories that do + # not contain `.rb` files, or that should not be reloaded or eager loaded. + # Common ones are `templates`, `generators`, or `middleware`, for example. + config.autoload_lib(ignore: %w[assets tasks]) # Configuration for the application, engines, and railties goes here. # diff --git a/config/environments/development.rb b/config/environments/development.rb index 0013462..3beb0d0 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -6,7 +6,7 @@ Rails.application.configure do # In the development environment your application's code is reloaded any time # it changes. This slows down response time but is perfect for development # since you don't have to restart the web server when you make code changes. - config.cache_classes = false + config.enable_reloading = true # Do not eager load code on boot. config.eager_load = false @@ -14,16 +14,17 @@ Rails.application.configure do # Show full error reports. config.consider_all_requests_local = true + # 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 @@ -43,10 +44,13 @@ Rails.application.configure do config.action_mailer.default_url_options = { host: "screenshots.debian.net", protocol: 'https' - } + # 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: "localhost", port: 3000 } + # Print deprecation notices to the Rails logger. config.active_support.deprecation = :log @@ -62,10 +66,8 @@ Rails.application.configure do # Highlight code that triggered database queries in logs. config.active_record.verbose_query_logs = true - # Debug mode disables concatenation and preprocessing of assets. - # This option may cause significant delays in view rendering with a large - # number of complex assets. - config.assets.debug = true + # Highlight code that enqueued background job in logs. + config.active_job.verbose_enqueue_logs = true # Suppress logger output for asset requests. config.assets.quiet = true @@ -100,4 +102,7 @@ Rails.application.configure do # Uncomment if you wish to allow Action Cable access from any origin. # config.action_cable.disable_request_forgery_protection = true + + # Raise error when a before_action's only/except options reference missing actions. + config.action_controller.raise_on_missing_callback_actions = true end diff --git a/config/environments/production.rb b/config/environments/production.rb index 6c9d48a..fd2d0e5 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -1,13 +1,10 @@ require "active_support/core_ext/integer/time" Rails.application.configure do - # Prepare the ingress controller used to receive mail - # config.action_mailbox.ingress = :relay - # Settings specified here will take precedence over those in config/application.rb. # Code is not reloaded between requests. - config.cache_classes = true + config.enable_reloading = false # Eager load code on boot. This eager loads most of Rails and # your application in memory, allowing both threaded web servers @@ -16,55 +13,69 @@ Rails.application.configure do config.eager_load = true # Full error reports are disabled and caching is turned on. - config.consider_all_requests_local = false + config.consider_all_requests_local = false config.action_controller.perform_caching = true - # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] - # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). + # Ensures that a master key has been made available in ENV["RAILS_MASTER_KEY"], config/master.key, or an environment + # key such as config/credentials/production.key. This key is used to decrypt credentials (and other encrypted files). # config.require_master_key = true - # Disable serving static files from the `/public` folder by default since - # Apache or NGINX already handles this. - config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? + # Disable serving static files from `public/`, relying on NGINX/Apache to do so instead. + # config.public_file_server.enabled = false # Compress CSS using a preprocessor. # config.assets.css_compressor = :sass - # Do not fallback to assets pipeline if a precompiled asset is missed. + # Do not fall back to assets pipeline if a precompiled asset is missed. config.assets.compile = false # Enable serving of images, stylesheets, and JavaScripts from an asset server. - # config.asset_host = 'http://assets.example.com' + # config.asset_host = "http://assets.example.com" # Specifies the header that your server uses for sending files. - # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache - # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX + # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache + # config.action_dispatch.x_sendfile_header = "X-Accel-Redirect" # for NGINX # Store uploaded files on the local file system (see config/storage.yml for options). config.active_storage.service = :local # Mount Action Cable outside main process or domain. # config.action_cable.mount_path = nil - # config.action_cable.url = 'wss://example.com/cable' - # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ] + # config.action_cable.url = "wss://example.com/cable" + # config.action_cable.allowed_request_origins = [ "http://example.com", /http:\/\/example.*/ ] + + # Assume all access to the app is happening through a SSL-terminating reverse proxy. + # Can be used together with config.force_ssl for Strict-Transport-Security and secure cookies. + # config.assume_ssl = true # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. - # config.force_ssl = true + config.force_ssl = true - # Include generic and useful information about system operation, but avoid logging too much - # information to avoid inadvertent exposure of personally identifiable information (PII). - config.log_level = :info + # Skip http-to-https redirect for the default health check endpoint. + # config.ssl_options = { redirect: { exclude: ->(request) { request.path == "/up" } } } + + # Log to STDOUT by default + 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 ] + # "info" includes generic and useful information about system operation, but avoids logging too much + # information to avoid inadvertent exposure of personally identifiable information (PII). If you + # want to log everything, set the level to "debug". + config.log_level = ENV.fetch("RAILS_LOG_LEVEL", "info") + # Use a different cache store in production. # config.cache_store = :mem_cache_store # Use a real queuing backend for Active Job (and separate queues per environment). - # config.active_job.queue_adapter = :resque - # config.active_job.queue_name_prefix = "debshots_#{Rails.env}" + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "debshots_production" + # Disable caching for Action Mailer templates even if Action Controller + # caching is enabled. config.action_mailer.perform_caching = false config.action_mailer.smtp_settings = { @@ -86,32 +97,12 @@ Rails.application.configure do # the I18n.default_locale when a translation cannot be found). config.i18n.fallbacks = true - # Send deprecation notices to registered listeners. - config.active_support.deprecation = :notify - - # Log disallowed deprecations. - config.active_support.disallowed_deprecation = :log - - # Tell Active Support which deprecation messages to disallow. - config.active_support.disallowed_deprecation_warnings = [] - - # Use default logging formatter so that PID and timestamp are not suppressed. - config.log_formatter = ::Logger::Formatter.new - - # Use a different logger for distributed setups. - # require 'syslog/logger' - # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') - - if ENV["RAILS_LOG_TO_STDOUT"].present? - logger = ActiveSupport::Logger.new(STDOUT) - logger.formatter = config.log_formatter - config.logger = ActiveSupport::TaggedLogging.new(logger) - end + # Don't log any deprecations. + config.active_support.report_deprecations = false # Do not dump schema after migrations. config.active_record.dump_schema_after_migration = false - config.package_sources = [ { description: 'Debian Unstable (Sid)', type: 'apt', url: 'http://ftp.de.debian.org/debian/dists/sid', architectures: ['i386' ,'amd64'] @@ -129,7 +120,16 @@ Rails.application.configure do # Any action dealing with authentication should redirect to HTTPS # Disabled because it will redirect incorrectly behind a proxy. # config.to_prepare { Devise::SessionsController.force_ssl } - + # Only use :id for inspections in production. # Needed (at least) for devise.rb to determine the oauth2 callback URL config.base_url = ENV['DEBSHOTS_BASE_URL'] || 'http://localhost:3000' + config.active_record.attributes_for_inspect = [ :id ] + + # Enable DNS rebinding protection and other `Host` header attacks. + # config.hosts = [ + # "example.com", # Allow requests from example.com + # /.*\.example\.com/ # Allow requests from subdomains like `www.example.com` + # ] + # Skip DNS rebinding protection for the default health check endpoint. + # config.host_authorization = { exclude: ->(request) { request.path == "/up" } } end diff --git a/config/environments/test.rb b/config/environments/test.rb index 2f2ee06..9b22182 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -8,27 +8,25 @@ require "active_support/core_ext/integer/time" Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. - config.cache_classes = false - config.action_view.cache_template_loading = true + # While tests run files are not watched, reloading is not necessary. + config.enable_reloading = false - # Do not eager load code on boot. This avoids loading your whole application - # just for the purpose of running a single test. If you are using a tool that - # preloads Rails for running tests, you may have to set it to true. - config.eager_load = false + # Eager loading loads your entire application. When running a single test locally, + # this is usually not necessary, and can slow down your test suite. However, it's + # recommended that you enable it in continuous integration systems to ensure eager + # loading is working properly before deploying your code. + config.eager_load = ENV["CI"].present? # 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 + config.consider_all_requests_local = true config.action_controller.perform_caching = false config.cache_store = :null_store - # Raise exceptions instead of rendering exception templates. - config.action_dispatch.show_exceptions = false + # Render exception templates for rescuable exceptions and raise for other exceptions. + config.action_dispatch.show_exceptions = :rescuable # Disable request forgery protection in test environment. config.action_controller.allow_forgery_protection = false @@ -36,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. @@ -43,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 @@ -73,10 +77,5 @@ Rails.application.configure do # Raises error for missing translations # config.action_view.raise_on_missing_translations = true - # Needed (at least) for devise.rb to determine the oauth2 callback URL config.base_url = ENV['DEBSHOTS_BASE_URL'] || 'http://localhost:3000' end - -# Set base URL to be used in links in mails -# https://github.com/rails/rails/issues/29992 -Rails.application.default_url_options = { host: 'localhost', port: 3000 } diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb index 2eeef96..bd5bcd2 100644 --- a/config/initializers/assets.rb +++ b/config/initializers/assets.rb @@ -9,4 +9,4 @@ Rails.application.config.assets.version = "1.0" # Precompile additional assets. # application.js, application.css, and all non-JS/CSS in the app/assets # folder are already added. -# Rails.application.config.assets.precompile += %w( admin.js admin.css ) +# Rails.application.config.assets.precompile += %w[ admin.js admin.css ] diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb index 54f47cf..b3076b3 100644 --- a/config/initializers/content_security_policy.rb +++ b/config/initializers/content_security_policy.rb @@ -16,9 +16,9 @@ # # policy.report_uri "/csp-violation-report-endpoint" # end # -# # Generate session nonces for permitted importmap and inline scripts +# # Generate session nonces for permitted importmap, inline scripts, and inline styles. # config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s } -# config.content_security_policy_nonce_directives = %w(script-src) +# config.content_security_policy_nonce_directives = %w(script-src style-src) # # # Report violations without enforcing the policy. # # config.content_security_policy_report_only = true diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb index adc6568..c010b83 100644 --- a/config/initializers/filter_parameter_logging.rb +++ b/config/initializers/filter_parameter_logging.rb @@ -1,8 +1,8 @@ # Be sure to restart your server when you modify this file. -# Configure parameters to be filtered from the log file. Use this to limit dissemination of -# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported -# notations and behaviors. +# Configure parameters to be partially matched (e.g. passw matches password) and filtered from the log file. +# Use this to limit dissemination of sensitive information. +# See the ActiveSupport::ParameterFilter documentation for supported notations and behaviors. Rails.application.config.filter_parameters += [ - :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn + :passw, :email, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn ] 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..b549c4a --- /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/initializers/permissions_policy.rb b/config/initializers/permissions_policy.rb index 00f64d7..7db3b95 100644 --- a/config/initializers/permissions_policy.rb +++ b/config/initializers/permissions_policy.rb @@ -1,11 +1,13 @@ +# Be sure to restart your server when you modify this file. + # Define an application-wide HTTP permissions policy. For further -# information see https://developers.google.com/web/updates/2018/06/feature-policy -# -# Rails.application.config.permissions_policy do |f| -# f.camera :none -# f.gyroscope :none -# f.microphone :none -# f.usb :none -# f.fullscreen :self -# f.payment :self, "https://secure.example.com" +# information see: https://developers.google.com/web/updates/2018/06/feature-policy + +# Rails.application.config.permissions_policy do |policy| +# policy.camera :none +# policy.gyroscope :none +# policy.microphone :none +# policy.usb :none +# policy.fullscreen :self +# policy.payment :self, "https://secure.example.com" # end diff --git a/config/puma.rb b/config/puma.rb index d9b3e83..03c166f 100644 --- a/config/puma.rb +++ b/config/puma.rb @@ -1,43 +1,34 @@ -# 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 +# This configuration file will be evaluated by Puma. The top-level methods that +# 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. -# Specifies the `worker_timeout` threshold that Puma will use to wait before -# terminating a worker in development environments. +# Puma starts a configurable number of processes (workers) and each process +# serves each request in a thread from an internal thread pool. # -worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" +# 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 } +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" } - -# Specifies the number of `workers` to boot in clustered mode. -# Workers are forked web server processes. If using threads and workers together -# the concurrency of the application would be max `threads` * `workers`. -# Workers do not work on JRuby or Windows (both of which do not support -# processes). -# -# workers ENV.fetch("WEB_CONCURRENCY") { 2 } - -# Use the `preload_app!` method when specifying a `workers` number. -# This directive tells Puma to first boot the application and load code -# before forking the application. This takes advantage of Copy On Write -# process behavior so workers use less memory. -# -# preload_app! - -# Allow puma to be restarted by `rails restart` command. +# Allow puma to be restarted by `bin/rails restart` command. plugin :tmp_restart + +# Specify the PID file. Defaults to tmp/pids/server.pid in development. +# In other environments, only set the PID file if requested. +pidfile ENV["PIDFILE"] if ENV["PIDFILE"] diff --git a/doc/README.Installation on Dokku.md b/doc/README.Installation on Dokku.md new file mode 100644 index 0000000..ddf1976 --- /dev/null +++ b/doc/README.Installation on Dokku.md @@ -0,0 +1,212 @@ +# Installing debshots on Dokku + +## What is Dokku? + +[Dokku](https://dokku.com/) is an open-source software that helps deploy +web applications. Once installed and set up you essentially do a _git push_ and +Dokku will do its magic. It works similar to Heroku (a paid service) and +even uses Heroku's _buildpacks_ for that purpose. It can handle common +web frameworks like Ruby-on-Rails. It has been used for +screenshots.debian.net in production for several years. + +Some of the features that make it a good choice: + +- healthchecks (will refuse to deploy if your new version is failing) +- seamless deployment (no downtime while switching to the new version) +- provides persistent volumes (where screenshots are stored) +- provides a PostgreSQL database and tells the application how to access it + through an automatic environment variable +- handles Let's Encrypt certificates automatically +- deploying a new application version is done simply by _git push_ + +## Install Dokku + +Grab a (virtual) server with at least 3 GB of RAM and 20 GB of SSD space. +The application is currently run on a Hetzner server in Germany that costs +less than 5€ per month. + +Follow the installation instructions on https://dokku.com/ + +Install the _Let's Encrypt_ plugin: + + dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git + +Set the email address as a contact for Let's Encrypt: + + dokku letsencrypt:set screenshots-beta.debian.net email haas@debian.org + +Create a new blank Dokku application: + + dokku apps:create screenshots-beta.debian.net + +Create a new blank PostgreSQL database and link it to the application: + + dokku postgres:create screenshots_beta + dokku postgres:link screenshots_beta screenshots-beta.debian.net + +Create a directory that will hold the screenshots' files: + + mkdir -p /srv/www/screenshots-beta.debian.net/shrine + +Mount it into the application's path: + + dokku storage:mount screenshots-beta.debian.net /srv/www/screenshots-beta.debian.net/shrine:/app/public/shrine + +By default the Nginx (that Dokku provides) will only allow uploads up to 1 MB. +You may want to increase that limit: + + dokku nginx:set screenshots-beta.debian.net client-max-body-size 10m + dokku proxy:build-config screenshots-beta.debian.net + +If you want to add a message that gets printed on all pages you can set +an environment variable for that purpose: + + dokku config:set screenshots-beta.debian.net DEBSHOTS\_ALERT\_MESSAGE='This is a staging site. Uploads will not persist. Testing only.' + + + +dokku config:set --no-restart screenshots-beta.debian.net SALSA_OAUTH_SECRET='c4c137fcbbcb5d9c6ff98a76bbf45bceee77ebe13645198359a0fa38cd8fb1d0' +dokku config:set --no-restart screenshots-beta.debian.net SALSA_OAUTH_KEY='644440cd5595b3b7aea6e959ab1488e7026c2b5cf24faea8f9af5ce914377d52' + + + + + + + + + + + + + + + + + + + + + + + + +Make sure that you set the environment variables as described in README.SSO.md before +you start the Rails application. Otherwise most single sign-on providers cannot work. +You also need to get the https://salsa.debian.org/debsso-team/debsso/raw/master/update-debsso-ca +script and run it in /etc/nginx to update the certficate and CRL used by the Debian +single-sign-on provider. + +The production configuration uses Nginx that decrypts HTTPS and either serves static +assets (images, Javascript, CSS) itself or requests for dynamic content to the +Rails application. You will need a SSL certificate for Nginx. Just get one from +LetsEncrypt using the *certbot* tool. + +Finally create an admin user for moderation: + +Start a Rails console: + + rails c -e production + +Create a new user record: + + user = User.create(realname: 'Christoph Haas', password: 'foobartest', email: 'email@christoph-haas.de') + user.save! + +## Cron jobs + +Parse Nginx access logs to count the number of visits of each package: + + RAILS_ENV=production bundle exec rake debshots:accesslog2visits[/var/log/nginx/cache-access.log.1] + +As a cron job: + + 41 9 * * * cd $HOME/debshots ; RAILS_ENV=production /home/debshots/.rbenv/shims/bundle exec rake debshots:accesslog2visits[/var/log/nginx/cache-access.log.1] + +Get the latest information on packages from the Debian repositories. + + bundle exec rails debshots:update_from_deb_repos RAILS_ENV=production + bundle exec rails debshots:update_longdescription_from_deb_repos RAILS_ENV=production + +# Authentication + +This web application tries to avoid to create yet another directory +of user accounts. So it leverages other common web sites like StackExchange, +Debian SSO (using browser/client certificates) or GitHub as single-sign-on +services. It is still possible to create local user accounts for administrators +but registration is disabled. + +Anonymous uploads are possible but they have to be moderated by an administrator. + +# Authorization (not yet implemented) + +A user can have one of these access levels. + +## Anonymous + +Without authentication all user actions are moderated. Such users can upload +screenshots or report existing/published screenshots as inappropriate. However +a user with level 'admin' will have to approve that action. + +## Authenticated by single-sign-login (SSO) + +Users can use different authentication services to login - like Github or +StackExchange. Such users internally get an account with a random password +created but they will keep logging in via SSO. + +The first upload will have to be moderated. Subsequent uploads will be +approved automatically. + +## Authenticated by Debian signle-sign-login (SSO) + +If a user authenticates using a Debian SSO client certificate they will be +able to upload screenshots without moderation. +(Anohter idea was to restrict them to uploading only screenshots for the +packages they maintain. But that may be reliable and is not implemented at +this time.) + +## Administrator + +Such a user has an internal user account. The database record has the +'admin' field set to 1. Admins can freely upload, moderate and delete +screenshots. They can also read the log files. + +# Nginx during development + +During development it is advised to run Nginx to proxy ports 3000 (HTTP) +and 3001 (HTTPS) to the rails application. + + cd nginx + nginx -c `pwd`/nginx.conf + +The SSL certitificate is just a self-signed certificate with the +common name "localhost". It was generated using: + + openssl req -x509 -newkey 4096 -nodes -keyout localhost.key -out localhost.crt -days 3650 + +Run "rails s" in another window. That will use the built-in Ruby 'Puma' +application server that can also be used in production. It requires less +configuration than Phusion Passenger but may be slower in regard to +performance and multi-threading / multi-core support. + +If you get "400 Bad Request / The SSL certificate error" in the browser then +please check the error log (/tmp/error*). Once cause is that the CRL of +the Debian SSO has expired and needs to be updated. + +# Tidy up the screenshot data: + +bundle exec rake debshots:remove_broken_screenshots + +bundle exec rake debshots:remove_duplicate_images + +# Frequent update of Debian SSO certificate + +Run /etc/nginx/update-sso-ca regularly to update the CA certificate and the CRL. +The CRL (certificate revocation list) is only valid for three days. So make sure +you have a daily cron job for the updates. Do not forget to restart Nginx afterwards. + +Otherwise you will end up with this error message: + + 400 Bad Request + The SSL certificate error + nginx diff --git a/doc/README.Installation.md b/doc/README.Installation.md index 6c6e279..dfc8ce9 100644 --- a/doc/README.Installation.md +++ b/doc/README.Installation.md @@ -43,7 +43,7 @@ Start a Rails console: Create a new user record: - user = User.create(realname: 'Christoph Haas', password: 'foobartest', email: 'email@christoph-haas.de') + user = User.create(realname: 'Christoph Haas', password: 'foobartest', email: 'email@christoph-haas.de', provider: 'local') user.save! ## Cron jobs diff --git a/lib/deb_importer.rb b/lib/deb_importer.rb index 06b355b..071db04 100644 --- a/lib/deb_importer.rb +++ b/lib/deb_importer.rb @@ -14,13 +14,12 @@ require 'pp' # Next it loads the Packages lists (prefers bz2, falls back to # .gz or even the uncompressed version). module DebImporter - # Defines a Debian release class Release attr_reader :architectures, :components, :description, :codename, :origin, :version, :files # Load and parse a Release file of an APT repository - def initialize(dist_url) # rubocop:disable Metrics/MethodLength + def initialize(dist_url) @dist_url = dist_url release_url = "#{dist_url}/Release" Rails.logger.debug "Loading Release file from #{release_url}" @@ -42,11 +41,9 @@ module DebImporter def i18n(component, language) url = "#{@dist_url}/#{component}/i18n/Translation-#{language}" file = find_and_open_compressed_url(url) - if file - return get_paragraphs(file) - else - return [] - end + return get_paragraphs(file) if file + + [] end # Look for the file or URL in various compressed formats @@ -66,14 +63,14 @@ module DebImporter file2 = nil # Decompress file depending on its filename suffix - case suffix - when '.bz2' - file2 = Bzip2::FFI::Reader.read(file) - when '.gz' - file2 = Zlib::GzipReader.new(file) - else # plain text - file2 = file - end + file2 = case suffix + when '.bz2' + Bzip2::FFI::Reader.read(file) + when '.gz' + Zlib::GzipReader.new(file) + else # plain text + file + end Rails.logger.debug "File containing translations is: #{url}" # Return an enumerator that iterates over lines of the file @@ -112,7 +109,7 @@ module DebImporter when /^(\S+?):$/ # "Key:" (start of multi-line entry without value in line) fields[name.to_sym] = value unless value.empty? name = $1 - value = "" + value = '' when /^\s(.+)/ # " Indented multi-line value" # Add a newline for multi-line entries ("Key: Value\n Foo\n Bar") value += "\n" unless value.empty? @@ -138,7 +135,7 @@ module DebImporter gathered_lines = [] # collects all lines belonging to a field data.each_line do |line| - #Rails.logger.debug("___" + line) + # Rails.logger.debug("___" + line) if line.chomp.empty? # empty line found that seperates paragraphs if gathered_lines.any? # any lines gathered so far? # Rails.logger.debug('>>>>>>>>>>>>>>>>>>>>>> Gathered lines:') @@ -156,7 +153,7 @@ module DebImporter enum.yield get_fields(gathered_lines) if gathered_lines.any? end end - + # Represents the version of a Debian package class Version attr_reader :epoch, :upstream, :revision, :version_string @@ -165,10 +162,10 @@ module DebImporter @version_string = version_string # Split into "[epoch:]upstream[-revision]" # See: https://www.debian.org/doc/debian-policy/ch-controlfields.html#version - unless /^((?\d+)\:)?(?.+?)(\-(?.+))?$/ =~ version_string + unless /^((?\d+):)?(?.+?)(-(?.+))?$/ =~ version_string raise ArgumentError, "Cannot parse version string: #{version_string}" end - + @epoch = epoch || '0' @upstream = upstream @revision = revision if revision diff --git a/public/406-unsupported-browser.html b/public/406-unsupported-browser.html new file mode 100644 index 0000000..7cf1e16 --- /dev/null +++ b/public/406-unsupported-browser.html @@ -0,0 +1,66 @@ + + + + Your browser is not supported (406) + + + + + + +
+
+

Your browser is not supported.

+

Please upgrade your browser to continue.

+
+
+ + diff --git a/test/controllers/packages_controller_test.rb b/test/controllers/packages_controller_test.rb index 873097a..9a9d9d5 100644 --- a/test/controllers/packages_controller_test.rb +++ b/test/controllers/packages_controller_test.rb @@ -8,6 +8,13 @@ class PackagesControllerTest < ActionController::TestCase end test "should get list view with_screenshots and find Firefox" do + # package = Package.create!(name: 'firefox', description: 'A web browser.') + # Screenshot.create!(package: package, approved: true, hidden: false) + + # get :list, params: { show: 'with' } + # assert_response :success + # assert_select 'div', 'A web browser.' + get :list, params: { show: 'with' } assert_response :success assert_select 'div', 'A program to browse web sites.'