diff --git a/.rubocop.yml b/.rubocop.yml index f4552f1afeefdff139cdb6657851f89b9132ca86..5e6705c20c0780b84a9ee94fa59cf0560d0488ac 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -10,6 +10,7 @@ AllCops: - 'db/**/*' - 'scripts/**/*' - 'bin/**/*' + - 'lib/namespaced_env_cache.rb' NewCops: enable SuggestExtensions: false diff --git a/Gemfile b/Gemfile index 0c180e87c0beca3e64a61fdc022deb68f68c2627..9917ae2379d8d91346b5061be2ba83d10aed7158 100644 --- a/Gemfile +++ b/Gemfile @@ -2,37 +2,39 @@ source 'https://rubygems.org' ruby '2.7.6' # Essential gems: servers, adapters, Rails + Rails requirements -gem 'coffee-rails', '~> 4.2.2' -gem 'counter_culture', '~> 2.0' -gem 'fastimage', '~> 2.1' +gem 'coffee-rails', '~> 5.0.0' +gem 'counter_culture', '~> 3.2' +gem 'fastimage', '~> 2.2' gem 'image_processing', '~> 1.12' -gem 'jquery-rails', '~> 4.3.5' -gem 'mysql2', '~> 0.5.3' -gem 'puma', '~> 4.3.12' -gem 'rails', '~> 5.2' -gem 'rails-html-sanitizer', '~> 1.3' -gem 'redis', '~> 4.1' -gem 'rotp', '~> 6.0' -gem 'sass-rails', '~> 5.0' -gem 'tzinfo-data', '~> 1.2019.3' -gem 'uglifier', '>= 1.3.0' +gem 'jquery-rails', '~> 4.5.0' +gem 'mysql2', '~> 0.5.4' +gem 'puma', '~> 5.6' +gem 'rails', '~> 7.0.0' +gem 'rails-html-sanitizer', '~> 1.4' +gem 'redis', '~> 5.0' +gem 'rotp', '~> 6.2' +gem 'sass-rails', '~> 6.0' +gem 'sprockets', '~> 4.1' +gem 'sprockets-rails', '~> 3.4', require: 'sprockets/railtie' +gem 'terser', '~> 1.1' +gem 'tzinfo-data', '~> 1.2022.3' # Sign in -gem 'devise', '~> 4.7' +gem 'devise', '~> 4.8' gem 'omniauth', '~> 1.9' # Markdown support in both directions. gem 'commonmarker', '~> 0.23' -gem 'reverse_markdown', '~> 2.0' +gem 'reverse_markdown', '~> 2.1' # Charting stuff. -gem 'chartkick', '~> 3.4' -gem 'groupdate', '~> 4.3' +gem 'chartkick', '~> 4.2' +gem 'groupdate', '~> 6.1' # View stuff. -gem 'diffy', '~> 3.3' -gem 'jbuilder', '~> 2.10' -gem 'rqrcode', '~> 1.1' +gem 'diffy', '~> 3.4' +gem 'jbuilder', '~> 2.11' +gem 'rqrcode', '~> 2.1' gem 'will_paginate', '~> 3.3' gem 'will_paginate-bootstrap', '~> 1.0' @@ -44,36 +46,36 @@ gem 'aws-ses-v4', require: 'aws/ses' gem 'whenever', '~> 1.0', require: false # Debugging, linting, testing. -gem 'awesome_print', '~> 1.8' +gem 'awesome_print', '~> 1.9' gem 'coveralls', '~> 0.8', require: false gem 'rubocop', '~> 1' -gem 'rubocop-rails', '~> 2.9' +gem 'rubocop-rails', '~> 2.15' # MiniProfiler support, including stack traces & memory dumps, plus flamegraphs. gem 'flamegraph', '~> 0.9' -gem 'memory_profiler', '~> 0.9' -gem 'rack-mini-profiler', '~> 2.0' +gem 'memory_profiler', '~> 1.0' +gem 'rack-mini-profiler', '~> 3.0' gem 'stackprof', '~> 0.2' # Ruby 2.7 compatibility: thwait and e2mmap are no longer bundled with Ruby, but # import needs thwait and ActiveSupport needs e2mmap. gem 'e2mmap', '~> 0.1' -gem 'thwait', '~> 0.1' +gem 'thwait', '~> 0.2' # Stuff for imports -gem 'ruby-progressbar', '~> 1.10' +gem 'ruby-progressbar', '~> 1.11' # Image generation gem 'rmagick' # Payments. Kinda important, y'know. -gem 'stripe', '~> 5.28' +gem 'stripe', '~> 5.55' # EeeMAILS! gem 'premailer-rails', '~> 1.11' group :test do - gem 'minitest', '~> 5.10.3' + gem 'minitest', '~> 5.16.0' gem 'minitest-ci', '~> 3.4.0' gem 'rails-controller-testing', '~> 1.0' gem 'term-ansicolor', '~> 1.7' @@ -84,7 +86,8 @@ group :development, :test do end group :development do - gem 'letter_opener_web', '~> 1.0' - gem 'spring', '~> 2.1' - gem 'web-console', '~> 3.7' + gem 'letter_opener_web', '~> 2.0' + gem 'listen', '~> 3.7' + gem 'spring', '~> 4.0' + gem 'web-console', '~> 4.2' end diff --git a/Gemfile.lock b/Gemfile.lock index f65efe5d4b583d2ef46042a967c531229288e7d7..74778fee98e1af4a6152f3d3e8ee6c0c00bba7b6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,90 +1,114 @@ GEM remote: https://rubygems.org/ specs: - actioncable (5.2.6) - actionpack (= 5.2.6) + actioncable (7.0.3.1) + actionpack (= 7.0.3.1) + activesupport (= 7.0.3.1) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailer (5.2.6) - actionpack (= 5.2.6) - actionview (= 5.2.6) - activejob (= 5.2.6) + actionmailbox (7.0.3.1) + actionpack (= 7.0.3.1) + activejob (= 7.0.3.1) + activerecord (= 7.0.3.1) + activestorage (= 7.0.3.1) + activesupport (= 7.0.3.1) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.3.1) + actionpack (= 7.0.3.1) + actionview (= 7.0.3.1) + activejob (= 7.0.3.1) + activesupport (= 7.0.3.1) mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp rails-dom-testing (~> 2.0) - actionpack (5.2.6) - actionview (= 5.2.6) - activesupport (= 5.2.6) - rack (~> 2.0, >= 2.0.8) + actionpack (7.0.3.1) + actionview (= 7.0.3.1) + activesupport (= 7.0.3.1) + rack (~> 2.0, >= 2.2.0) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.2.6) - activesupport (= 5.2.6) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.3.1) + actionpack (= 7.0.3.1) + activerecord (= 7.0.3.1) + activestorage (= 7.0.3.1) + activesupport (= 7.0.3.1) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.3.1) + activesupport (= 7.0.3.1) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.0.3) - activejob (5.2.6) - activesupport (= 5.2.6) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.3.1) + activesupport (= 7.0.3.1) globalid (>= 0.3.6) - activemodel (5.2.6) - activesupport (= 5.2.6) - activerecord (5.2.6) - activemodel (= 5.2.6) - activesupport (= 5.2.6) - arel (>= 9.0) - activestorage (5.2.6) - actionpack (= 5.2.6) - activerecord (= 5.2.6) - marcel (~> 1.0.0) - activesupport (5.2.6) + activemodel (7.0.3.1) + activesupport (= 7.0.3.1) + activerecord (7.0.3.1) + activemodel (= 7.0.3.1) + activesupport (= 7.0.3.1) + activestorage (7.0.3.1) + actionpack (= 7.0.3.1) + activejob (= 7.0.3.1) + activerecord (= 7.0.3.1) + activesupport (= 7.0.3.1) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.3.1) concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) - minitest (~> 5.1) - tzinfo (~> 1.1) - addressable (2.8.0) - public_suffix (>= 2.0.2, < 5.0) - arel (9.0.0) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + addressable (2.8.1) + public_suffix (>= 2.0.2, < 6.0) ast (2.4.2) awesome_print (1.9.2) - aws-eventstream (1.1.1) - aws-partitions (1.465.0) - aws-sdk-core (3.114.1) + aws-eventstream (1.2.0) + aws-partitions (1.626.0) + aws-sdk-core (3.140.0) aws-eventstream (~> 1, >= 1.0.2) - aws-partitions (~> 1, >= 1.239.0) + aws-partitions (~> 1, >= 1.525.0) aws-sigv4 (~> 1.1) - jmespath (~> 1.0) - aws-sdk-kms (1.43.0) - aws-sdk-core (~> 3, >= 3.112.0) + jmespath (~> 1, >= 1.6.1) + aws-sdk-kms (1.58.0) + aws-sdk-core (~> 3, >= 3.127.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.96.0) - aws-sdk-core (~> 3, >= 3.112.0) + aws-sdk-s3 (1.114.0) + aws-sdk-core (~> 3, >= 3.127.0) aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.1) + aws-sigv4 (~> 1.4) aws-ses-v4 (0.8.1) builder mail (> 2.2.5) mime-types xml-simple - aws-sigv4 (1.2.3) + aws-sigv4 (1.5.1) aws-eventstream (~> 1, >= 1.0.2) - bcrypt (3.1.16) + bcrypt (3.1.18) bindex (0.8.1) builder (3.2.4) byebug (11.1.3) - chartkick (3.4.2) + chartkick (4.2.1) chronic (0.10.2) chunky_png (1.4.0) - coffee-rails (4.2.2) + coffee-rails (5.0.0) coffee-script (>= 2.2.0) - railties (>= 4.0.0) + railties (>= 5.2.0) coffee-script (2.4.1) coffee-script-source execjs coffee-script-source (1.12.2) - commonmarker (0.23.4) - concurrent-ruby (1.1.9) - counter_culture (2.8.0) + commonmarker (0.23.5) + concurrent-ruby (1.1.10) + connection_pool (2.2.5) + counter_culture (3.2.1) activerecord (>= 4.2) activesupport (>= 4.2) coveralls (0.8.23) @@ -94,109 +118,126 @@ GEM thor (>= 0.19.4, < 2.0) tins (~> 1.6) crass (1.0.6) - css_parser (1.9.0) + css_parser (1.11.0) addressable - devise (4.8.0) + devise (4.8.1) bcrypt (~> 3.0) orm_adapter (~> 0.1) railties (>= 4.1.0) responders warden (~> 1.2.3) - diffy (3.4.0) + diffy (3.4.2) + digest (3.1.0) docile (1.4.0) e2mmap (0.1.0) - erubi (1.10.0) + erubi (1.11.0) execjs (2.8.1) - fastimage (2.2.4) + fastimage (2.2.6) ffi (1.15.5) flamegraph (0.9.5) - globalid (0.4.2) - activesupport (>= 4.2.0) - groupdate (4.3.0) - activesupport (>= 5) - hashie (4.1.0) + globalid (1.0.0) + activesupport (>= 5.0) + groupdate (6.1.0) + activesupport (>= 5.2) + hashie (5.0.0) htmlentities (4.3.4) - i18n (1.10.0) + i18n (1.12.0) concurrent-ruby (~> 1.0) image_processing (1.12.2) mini_magick (>= 4.9.5, < 5) ruby-vips (>= 2.0.17, < 3) - jbuilder (2.11.2) + jbuilder (2.11.5) + actionview (>= 5.0.0) activesupport (>= 5.0.0) jmespath (1.6.1) - jquery-rails (4.3.5) + jquery-rails (4.5.0) rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) - json (2.5.1) + json (2.6.2) launchy (2.5.0) addressable (~> 2.7) - letter_opener (1.7.0) - launchy (~> 2.2) - letter_opener_web (1.4.1) - actionmailer (>= 3.2) - letter_opener (~> 1.0) - railties (>= 3.2) - loofah (2.12.0) + letter_opener (1.8.1) + launchy (>= 2.2, < 3) + letter_opener_web (2.0.0) + actionmailer (>= 5.2) + letter_opener (~> 1.7) + railties (>= 5.2) + rexml + listen (3.7.1) + rb-fsevent (~> 0.10, >= 0.10.3) + rb-inotify (~> 0.9, >= 0.9.10) + loofah (2.18.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) mini_mime (>= 0.1.1) - marcel (1.0.1) - memory_profiler (0.9.14) + marcel (1.0.2) + memory_profiler (1.0.0) method_source (1.0.0) - mime-types (3.3.1) + mime-types (3.4.1) mime-types-data (~> 3.2015) - mime-types-data (3.2021.0901) + mime-types-data (3.2022.0105) mini_magick (4.11.0) - mini_mime (1.1.0) - mini_portile2 (2.8.0) - minitest (5.10.3) + mini_mime (1.1.2) + minitest (5.16.3) minitest-ci (3.4.0) minitest (>= 5.0.6) - mysql2 (0.5.3) + mysql2 (0.5.4) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout nio4r (2.5.8) - nokogiri (1.13.3) - mini_portile2 (~> 2.8.0) - racc (~> 1.4) - nokogiri (1.13.3-x86_64-linux) + nokogiri (1.13.8-x86_64-linux) racc (~> 1.4) - omniauth (1.9.1) + omniauth (1.9.2) hashie (>= 3.4.6) rack (>= 1.6.2, < 3) orm_adapter (0.5.0) - parallel (1.20.1) - parser (3.0.1.1) + parallel (1.22.1) + parser (3.1.2.1) ast (~> 2.4.1) - premailer (1.15.0) + premailer (1.16.0) addressable css_parser (>= 1.6.0) htmlentities (>= 4.0.0) premailer-rails (1.11.1) actionmailer (>= 3) premailer (~> 1.7, >= 1.7.9) - public_suffix (4.0.6) - puma (4.3.12) + public_suffix (5.0.0) + puma (5.6.5) nio4r (~> 2.0) racc (1.6.0) - rack (2.2.3.1) - rack-mini-profiler (2.3.2) + rack (2.2.4) + rack-mini-profiler (3.0.0) rack (>= 1.2.0) - rack-test (1.1.0) - rack (>= 1.0, < 3) - rails (5.2.6) - actioncable (= 5.2.6) - actionmailer (= 5.2.6) - actionpack (= 5.2.6) - actionview (= 5.2.6) - activejob (= 5.2.6) - activemodel (= 5.2.6) - activerecord (= 5.2.6) - activestorage (= 5.2.6) - activesupport (= 5.2.6) - bundler (>= 1.3.0) - railties (= 5.2.6) - sprockets-rails (>= 2.0.0) + rack-test (2.0.2) + rack (>= 1.3) + rails (7.0.3.1) + actioncable (= 7.0.3.1) + actionmailbox (= 7.0.3.1) + actionmailer (= 7.0.3.1) + actionpack (= 7.0.3.1) + actiontext (= 7.0.3.1) + actionview (= 7.0.3.1) + activejob (= 7.0.3.1) + activemodel (= 7.0.3.1) + activerecord (= 7.0.3.1) + activestorage (= 7.0.3.1) + activesupport (= 7.0.3.1) + bundler (>= 1.15.0) + railties (= 7.0.3.1) rails-controller-testing (1.0.5) actionpack (>= 5.0.1.rc1) actionview (>= 5.0.1.rc1) @@ -204,164 +245,173 @@ GEM rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) - rails-html-sanitizer (1.4.2) + rails-html-sanitizer (1.4.3) loofah (~> 2.3) - railties (5.2.6) - actionpack (= 5.2.6) - activesupport (= 5.2.6) + railties (7.0.3.1) + actionpack (= 7.0.3.1) + activesupport (= 7.0.3.1) method_source - rake (>= 0.8.7) - thor (>= 0.19.0, < 2.0) - rainbow (3.0.0) + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rainbow (3.1.1) rake (13.0.6) - rb-fsevent (0.11.0) + rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) - redis (4.2.5) - regexp_parser (2.1.1) + redis (5.0.2) + redis-client (~> 0.7) + redis-client (0.7.1) + connection_pool + regexp_parser (2.5.0) responders (3.0.1) actionpack (>= 5.0) railties (>= 5.0) - reverse_markdown (2.0.0) + reverse_markdown (2.1.1) nokogiri rexml (3.2.5) - rmagick (4.2.2) + rmagick (4.2.6) rotp (6.2.0) - rqrcode (1.2.0) + rqrcode (2.1.2) chunky_png (~> 1.0) - rqrcode_core (~> 0.2) - rqrcode_core (0.2.0) - rubocop (1.16.0) + rqrcode_core (~> 1.0) + rqrcode_core (1.2.0) + rubocop (1.36.0) + json (~> 2.3) parallel (~> 1.10) - parser (>= 3.0.0.0) + parser (>= 3.1.2.1) rainbow (>= 2.2.2, < 4.0) regexp_parser (>= 1.8, < 3.0) - rexml - rubocop-ast (>= 1.7.0, < 2.0) + rexml (>= 3.2.5, < 4.0) + rubocop-ast (>= 1.20.1, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 1.4.0, < 3.0) - rubocop-ast (1.7.0) - parser (>= 3.0.1.1) - rubocop-rails (2.10.1) + rubocop-ast (1.21.0) + parser (>= 3.1.1.0) + rubocop-rails (2.15.2) activesupport (>= 4.2.0) rack (>= 1.1) rubocop (>= 1.7.0, < 2.0) ruby-progressbar (1.11.0) ruby-vips (2.1.4) ffi (~> 1.12) - 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-rails (6.0.0) + sassc-rails (~> 2.1, >= 2.1.1) + sassc (2.4.0) + ffi (~> 1.9) + sassc-rails (2.1.2) + railties (>= 4.0.0) + sassc (>= 2.0) + sprockets (> 3.0) + sprockets-rails + tilt simplecov (0.16.1) docile (~> 1.1) json (>= 1.8, < 3) simplecov-html (~> 0.10.0) simplecov-html (0.10.2) - spring (2.1.1) - sprockets (3.7.2) + spring (4.0.0) + sprockets (4.1.1) concurrent-ruby (~> 1.0) rack (> 1, < 3) - sprockets-rails (3.2.2) - actionpack (>= 4.0) - activesupport (>= 4.0) + sprockets-rails (3.4.2) + actionpack (>= 5.2) + activesupport (>= 5.2) sprockets (>= 3.0.0) - stackprof (0.2.17) - stripe (5.34.0) + stackprof (0.2.21) + stripe (5.55.0) + strscan (3.0.4) sync (0.5.0) term-ansicolor (1.7.1) tins (~> 1.0) - thor (1.1.0) - thread_safe (0.3.6) + terser (1.1.12) + execjs (>= 0.3.0, < 3) + thor (1.2.1) thwait (0.2.0) e2mmap - tilt (2.0.10) - tins (1.29.1) + tilt (2.0.11) + timeout (0.3.0) + tins (1.31.1) sync - tzinfo (1.2.9) - thread_safe (~> 0.1) - tzinfo-data (1.2019.3) + tzinfo (2.0.5) + concurrent-ruby (~> 1.0) + tzinfo-data (1.2022.3) tzinfo (>= 1.0.0) - uglifier (4.2.0) - execjs (>= 0.3.0, < 3) - unicode-display_width (2.0.0) + unicode-display_width (2.2.0) warden (1.2.9) rack (>= 2.0.9) - web-console (3.7.0) - actionview (>= 5.0) - activemodel (>= 5.0) + web-console (4.2.0) + actionview (>= 6.0.0) + activemodel (>= 6.0.0) bindex (>= 0.4.0) - railties (>= 5.0) - websocket-driver (0.7.4) + railties (>= 6.0.0) + websocket-driver (0.7.5) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) whenever (1.0.0) chronic (>= 0.6.3) - will_paginate (3.3.0) + will_paginate (3.3.1) will_paginate-bootstrap (1.0.2) will_paginate (>= 3.0.3) xml-simple (1.1.9) rexml + zeitwerk (2.6.0) PLATFORMS ruby x86_64-linux DEPENDENCIES - awesome_print (~> 1.8) + awesome_print (~> 1.9) aws-sdk-s3 (~> 1.61) aws-ses-v4 byebug (~> 11.1) - chartkick (~> 3.4) - coffee-rails (~> 4.2.2) + chartkick (~> 4.2) + coffee-rails (~> 5.0.0) commonmarker (~> 0.23) - counter_culture (~> 2.0) + counter_culture (~> 3.2) coveralls (~> 0.8) - devise (~> 4.7) - diffy (~> 3.3) + devise (~> 4.8) + diffy (~> 3.4) e2mmap (~> 0.1) - fastimage (~> 2.1) + fastimage (~> 2.2) flamegraph (~> 0.9) - groupdate (~> 4.3) + groupdate (~> 6.1) image_processing (~> 1.12) - jbuilder (~> 2.10) - jquery-rails (~> 4.3.5) - letter_opener_web (~> 1.0) - memory_profiler (~> 0.9) - minitest (~> 5.10.3) + jbuilder (~> 2.11) + jquery-rails (~> 4.5.0) + letter_opener_web (~> 2.0) + listen (~> 3.7) + memory_profiler (~> 1.0) + minitest (~> 5.16.0) minitest-ci (~> 3.4.0) - mysql2 (~> 0.5.3) + mysql2 (~> 0.5.4) omniauth (~> 1.9) premailer-rails (~> 1.11) - puma (~> 4.3.12) - rack-mini-profiler (~> 2.0) - rails (~> 5.2) + puma (~> 5.6) + rack-mini-profiler (~> 3.0) + rails (~> 7.0.0) rails-controller-testing (~> 1.0) - rails-html-sanitizer (~> 1.3) - redis (~> 4.1) - reverse_markdown (~> 2.0) + rails-html-sanitizer (~> 1.4) + redis (~> 5.0) + reverse_markdown (~> 2.1) rmagick - rotp (~> 6.0) - rqrcode (~> 1.1) + rotp (~> 6.2) + rqrcode (~> 2.1) rubocop (~> 1) - rubocop-rails (~> 2.9) - ruby-progressbar (~> 1.10) - sass-rails (~> 5.0) - spring (~> 2.1) + rubocop-rails (~> 2.15) + ruby-progressbar (~> 1.11) + sass-rails (~> 6.0) + spring (~> 4.0) + sprockets (~> 4.1) + sprockets-rails (~> 3.4) stackprof (~> 0.2) - stripe (~> 5.28) + stripe (~> 5.55) term-ansicolor (~> 1.7) - thwait (~> 0.1) - tzinfo-data (~> 1.2019.3) - uglifier (>= 1.3.0) - web-console (~> 3.7) + terser (~> 1.1) + thwait (~> 0.2) + tzinfo-data (~> 1.2022.3) + web-console (~> 4.2) whenever (~> 1.0) will_paginate (~> 3.3) will_paginate-bootstrap (~> 1.0) @@ -370,4 +420,4 @@ RUBY VERSION ruby 2.7.6p219 BUNDLED WITH - 2.2.3 + 2.3.21 diff --git a/INSTALLATION.md b/INSTALLATION.md index 49d96e560a0910b290e62439acc791a0b6de4d40..93e42a159ffaa3fad53c1fa1e4f649489e6f179a 100644 --- a/INSTALLATION.md +++ b/INSTALLATION.md @@ -43,6 +43,8 @@ brew install mysql bison openssl mysql-client bundle config --global build.mysql2 --with-opt-dir="$(brew --prefix openssl)" ``` +QPixel requires Ruby 2.7+. + ### Install JS runtime If you already have Node.JS installed, you can skip this step. If not, @@ -54,15 +56,13 @@ If you already have Node.JS installed, you can skip this step. If not, If you haven't already got it, [download and install Redis](https://redis.io/download) or for example `sudo apt install redis-server`. -### Install Imagemagick - -If you haven't already installed Imagemagick, you'll need to [install it for -your system](https://imagemagick.org/script/download.php). +### Install Libvips -If you install Imagemagick from APT on a Debian-based system, you may need to -also install the `libmagickwand-dev` package. +If you haven't already installed Libvips, you'll need to [install it for +your system](https://www.libvips.org/). -`sudo apt install libmagick++-dev` should also work. +To install libvips from APT on a Debian-based system, use +`sudo apt install libvips` ## Install QPixel diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js new file mode 100644 index 0000000000000000000000000000000000000000..b16e53d6d56d262ebcd7692c54616a9df2a30f8b --- /dev/null +++ b/app/assets/config/manifest.js @@ -0,0 +1,3 @@ +//= link_tree ../images +//= link_directory ../javascripts .js +//= link_directory ../stylesheets .css diff --git a/app/assets/stylesheets/donations.scss b/app/assets/stylesheets/donations.scss index 9bee44acffc60d0a1c9b2a88f1edd0397e382001..bb45e10ce2c21ddf254ae51171d6bedf21ed8c3e 100644 --- a/app/assets/stylesheets/donations.scss +++ b/app/assets/stylesheets/donations.scss @@ -39,7 +39,7 @@ } p { - margin: 0 min(max(0.5em, 15%), 4em) 0.5em min(max(0.5em, 15%), 4em); + margin: 0 calc(min(max(0.5em, 15%), 4em)) 0.5em calc(min(max(0.5em, 15%), 4em)); text-align: justify; &.lede { @@ -57,7 +57,7 @@ } form { - margin: 2em min(max(0.5em, 15%), 4em) 2em min(max(0.5em, 15%), 4em); + margin: 2em calc(min(max(0.5em, 15%), 4em)) 2em calc(min(max(0.5em, 15%), 4em)); label { font-weight: bold; diff --git a/app/controllers/advertisement_controller.rb b/app/controllers/advertisement_controller.rb index bf040b8bad9e5a82d09937f7a8daede2ca1cc0c5..6e143d0dbac14634b3d157ab3ade89bd727ca3d5 100644 --- a/app/controllers/advertisement_controller.rb +++ b/app/controllers/advertisement_controller.rb @@ -89,10 +89,10 @@ class AdvertisementController < ApplicationController if category.nil? category = Category.where(use_for_advertisement: true) end - Post.undeleted.joins(:post_type).where(post_types: { is_top_level: true })\ - .where(posts: { last_activity: (Rails.env.development? ? 365 : 7).days.ago..DateTime.now })\ - .where(posts: { category: category })\ - .where('posts.score > ?', SiteSetting['HotPostsScoreThreshold'])\ + Post.undeleted.joins(:post_type).where(post_types: { is_top_level: true }) \ + .where(posts: { last_activity: (Rails.env.development? ? 365 : 7).days.ago..DateTime.now }) \ + .where(posts: { category: category }) \ + .where('posts.score > ?', SiteSetting['HotPostsScoreThreshold']) \ .order('posts.score DESC').limit(SiteSetting['HotQuestionsCount']).all.sample end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 0033307a4bd5e0daeca183de04c0638806622c1f..68cd945fbe804a805dde618a63eba9e8d2c80fcb 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -140,7 +140,7 @@ class ApplicationController < ActionController::Base "You may only suggest #{max_edits} edits per day." else "You may only suggest #{max_edits} edits per day. " \ - 'Once you have some well-received posts, that limit will increase.' + 'Once you have some well-received posts, that limit will increase.' end if recent_edits >= max_edits diff --git a/app/controllers/categories_controller.rb b/app/controllers/categories_controller.rb index 943f31b37faacc7ddb1929a76b67f017ab436bff..b8076e3663ad653d57acd3f3b090a6e6d0980618 100644 --- a/app/controllers/categories_controller.rb +++ b/app/controllers/categories_controller.rb @@ -97,9 +97,9 @@ class CategoriesController < ApplicationController # Break rep awards cache either way and regenerate. cache_key = 'network/category_post_types/rep_changes' Rails.cache.delete cache_key, include_community: false - Rails.cache.write(cache_key, CategoryPostType.all.map do |cpt| + Rails.cache.write(cache_key, CategoryPostType.all.to_h do |cpt| [[cpt.category_id, cpt.post_type_id], { 1 => cpt.upvote_rep, -1 => cpt.downvote_rep }] - end.to_h, include_community: false) + end, include_community: false) view_name = 'categories/_category_post_type_edit' render json: { status: 'success', cpt: @category_post_type, diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index 2330f450cfd9a4886f3674142a37e40e81fa394f..093b80c4f0ef108962d4c1fd003bdbee8f40fe10 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -249,7 +249,7 @@ class CommentsController < ApplicationController thread = params[:id] == '-1' ? CommentThread.new(post_id: params[:post]) : CommentThread.find(params[:id]) ids = helpers.get_pingable(thread) users = User.where(id: ids) - render json: users.map { |u| [u.username, u.id] }.to_h + render json: users.to_h { |u| [u.username, u.id] } end private @@ -309,9 +309,9 @@ class CommentsController < ApplicationController if (!@post.user_id == current_user.id || @post&.parent&.user_id == current_user.id) \ && recent_comments >= max_comments_per_day - comment_limit_msg = "You have used your daily comment limit of #{recent_comments} comments." \ - ' Come back tomorrow to continue commenting. Comments on own posts and on answers' \ - ' to own posts are exempt.' + comment_limit_msg = "You have used your daily comment limit of #{recent_comments} comments. " \ + 'Come back tomorrow to continue commenting. Comments on own posts and on answers ' \ + 'to own posts are exempt.' if recent_comments.zero? && !current_user.privilege?('unrestricted') comment_limit_msg = 'New users can only comment on their own posts and on answers to them.' diff --git a/app/controllers/flags_controller.rb b/app/controllers/flags_controller.rb index c38430750e353768ae8101ba141926f7e6aef758..a83947d37731ceae94f15c78d3efc61b425ac80c 100644 --- a/app/controllers/flags_controller.rb +++ b/app/controllers/flags_controller.rb @@ -14,9 +14,9 @@ class FlagsController < ApplicationController max_flags_per_day = SiteSetting[current_user.privilege?('unrestricted') ? 'RL_Flags' : 'RL_NewUserFlags'] if recent_flags >= max_flags_per_day - flag_limit_msg = 'Thank you. Flags from people like you help us keep this site clean.' \ - " However, you have reached your daily flag limit of #{max_flags_per_day}" \ - ' flags. Please come back tomorrow to continue flagging.' + flag_limit_msg = 'Thank you. Flags from people like you help us keep this site clean. ' \ + "However, you have reached your daily flag limit of #{max_flags_per_day} " \ + 'flags. Please come back tomorrow to continue flagging.' AuditLog.rate_limit_log(event_type: 'flag', related: Post.find(params[:post_id]), user: current_user, comment: "limit: #{max_flags_per_day}\n\ntype:#{type}\ncomment:\n#{params[:reason].to_i}") diff --git a/app/controllers/micro_auth/authentication_controller.rb b/app/controllers/micro_auth/authentication_controller.rb index 3f2e638a78be075914b09e30a83e236b6c8a4609..fa7f65f38acbff17a386328311e35cb7bf050ebc 100644 --- a/app/controllers/micro_auth/authentication_controller.rb +++ b/app/controllers/micro_auth/authentication_controller.rb @@ -77,7 +77,7 @@ class MicroAuth::AuthenticationController < ApplicationController end def clean_scope(scope) - scope = scope.is_a?(Array) ? scope : [scope] + scope = [scope] unless scope.is_a?(Array) scope.select do |s| helpers.valid_auth_scopes.keys.include? s end diff --git a/app/controllers/moderator_controller.rb b/app/controllers/moderator_controller.rb index 9070a632dff70ca27976650672b6adbb38137840..ae482cd4f0e9e33197c17e0e2e7365b76327e1af 100644 --- a/app/controllers/moderator_controller.rb +++ b/app/controllers/moderator_controller.rb @@ -48,17 +48,20 @@ class ModeratorController < ApplicationController render json: { status: 'success', success: true } end + VoteData = Struct.new(:cast, :received) + VoteSummary = Struct.new(:breakdown, :types, :total) + def user_vote_summary @user = User.find params[:id] @users = User.where(id: Vote.where(user: @user).select(:recv_user_id).distinct) .or(User.where(id: Vote.where(recv_user: @user).select(:user_id).distinct)) - @vote_data = OpenStruct.new( - cast: OpenStruct.new( + @vote_data = VoteData.new( + cast: VoteSummary.new( breakdown: Vote.where(user: @user).group(:recv_user_id, :vote_type).count, types: Vote.where(user: @user).group(:vote_type).count, total: Vote.where(user: @user).count ), - received: OpenStruct.new( + received: VoteSummary.new( breakdown: Vote.where(recv_user: @user).group(:user_id, :vote_type).count, types: Vote.where(recv_user: @user).group(:vote_type).count, total: Vote.where(recv_user: @user).count diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index f926550fbcf5963c1ea6e437e4e6cde5075a278d..f9e0e26c736813820eb11a1492cfcafb1fcf4e96 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -397,14 +397,14 @@ class PostsController < ApplicationController end def upload - content_types = ActiveStorage::Variant::WEB_IMAGE_CONTENT_TYPES + content_types = Rails.application.config.active_storage.web_image_content_types extensions = content_types.map { |ct| ct.gsub('image/', '') } unless helpers.valid_image?(params[:file]) render json: { error: "Images must be one of #{extensions.join(', ')}" }, status: :bad_request return end - @blob = ActiveStorage::Blob.create_after_upload!(io: params[:file], filename: params[:file].original_filename, - content_type: params[:file].content_type) + @blob = ActiveStorage::Blob.create_and_upload!(io: params[:file], filename: params[:file].original_filename, + content_type: params[:file].content_type) render json: { link: uploaded_url(@blob.key) } end @@ -529,14 +529,14 @@ class PostsController < ApplicationController def post_params p = params.require(:post).permit(*permitted, tags_cache: []) - p[:tags_cache] = p[:tags_cache]&.reject { |t| t.empty? } + p[:tags_cache] = p[:tags_cache]&.reject(&:empty?) p end def edit_post_params p = params.require(:post).permit(*(permitted - [:license_id, :post_type_id, :category_id, :parent_id]), tags_cache: []) - p[:tags_cache] = p[:tags_cache]&.reject { |t| t.empty? } + p[:tags_cache] = p[:tags_cache]&.reject(&:empty?) p end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 8f99451975a35cab859f89ec8d51598687335c3b..11e95df0dec4419ffe76b4588bc8aef48caa959e 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -19,7 +19,7 @@ class UsersController < ApplicationController user_scope.search(params[:search]) else user_scope.order(sort_param => :desc) - end.where.not(deleted: true, community_users: { deleted: true }) + end.where.not(deleted: true).where.not(community_users: { deleted: true }) .paginate(page: params[:page], per_page: 48) # rubocop:disable Layout/MultilineMethodCallIndentation @post_counts = Post.where(user_id: @users.pluck(:id).uniq).group(:user_id).count end @@ -44,7 +44,7 @@ class UsersController < ApplicationController end format.json do data = [:id, :username, :is_moderator, :is_admin, :is_global_moderator, :is_global_admin, :trust_level, - :se_acct_id].map { |a| [a, @user.send(a)] }.to_h + :se_acct_id].to_h { |a| [a, @user.send(a)] } render json: data end end @@ -71,7 +71,7 @@ class UsersController < ApplicationController key = params[:community].present? && params[:community] ? community_key : global_key current_user.validate_prefs! render json: { status: 'success', success: true, - count: RequestContext.redis.hset(key, params[:name], params[:value]), + count: RequestContext.redis.hset(key, params[:name], params[:value].to_s), preferences: current_user.preferences } else render json: { status: 'failed', success: false, errors: ['Both name and value parameters are required'] }, diff --git a/app/controllers/votes_controller.rb b/app/controllers/votes_controller.rb index 5ee76658f5f8b00a3b863df0492456f8de859b1b..84b57ce79d869f1e86640a06e47312d021e47043 100644 --- a/app/controllers/votes_controller.rb +++ b/app/controllers/votes_controller.rb @@ -15,9 +15,9 @@ class VotesController < ApplicationController max_votes_per_day = SiteSetting[current_user.privilege?('unrestricted') ? 'RL_Votes' : 'RL_NewUserVotes'] if !post.parent&.user_id == current_user.id && recent_votes >= max_votes_per_day - vote_limit_msg = "You have used your daily vote limit of #{recent_votes} votes." \ - ' Come back tomorrow to continue voting. Votes on answers to own posts' \ - ' are exempt.' + vote_limit_msg = "You have used your daily vote limit of #{recent_votes} votes. " \ + 'Come back tomorrow to continue voting. Votes on answers to own posts ' \ + 'are exempt.' AuditLog.rate_limit_log(event_type: 'vote', related: post, user: current_user, comment: "limit: #{max_votes_per_day}\n\nvote:\n#{params[:vote_type].to_i}") diff --git a/app/helpers/abilities_helper.rb b/app/helpers/abilities_helper.rb index d1e4eccb340243d493b908572d7707f25e0001a8..35646a3b00a635fdbf680d1a455638854c4e857f 100644 --- a/app/helpers/abilities_helper.rb +++ b/app/helpers/abilities_helper.rb @@ -9,7 +9,7 @@ module AbilitiesHelper # Solution: We transform the ideal case formula y=(x+2)/(x+4) # to x=(4y-2)/(1-y) and use that for the progress bar. def linearize_progress(score) - linear_score = (4 * score - 2) / (1 - score) + linear_score = ((4 * score) - 2) / (1 - score) [0, linear_score].max end @@ -19,18 +19,18 @@ module AbilitiesHelper if ua&.suspended? if action.nil? "Your use of the #{ability.name} ability has been temporarily suspended. " \ - "See /abilities/#{ability.internal_id} for more information." + "See /abilities/#{ability.internal_id} for more information." else "Your use of the #{ability.name} ability has been temporarily suspended, so you cannot #{action}." \ - "See /abilities/#{ability.internal_id} for more information." + "See /abilities/#{ability.internal_id} for more information." end else if action.nil? "You need the #{ability.name} ability to do this." \ - "See /abilities/#{ability.internal_id} for more information." + "See /abilities/#{ability.internal_id} for more information." else "You need the #{ability.name} ability to #{action}." \ - "See /abilities/#{ability.internal_id} for more information." + "See /abilities/#{ability.internal_id} for more information." end end end diff --git a/app/helpers/advertisements/article_helper.rb b/app/helpers/advertisements/article_helper.rb index 59b1fdddacf3a6cec410c0d88fdf804e6531cc8f..80a425c75c0fe1e83e0b0726834b8bda2205fb58 100644 --- a/app/helpers/advertisements/article_helper.rb +++ b/app/helpers/advertisements/article_helper.rb @@ -62,14 +62,14 @@ module Advertisements::ArticleHelper if article.title.length > 60 title.pointsize = 35 wrap_text(do_rtl_witchcraft(article.title), 500, 35).split("\n").each do |line| - title.annotate ad, 500, 100, 50, 135 + position * 55, line do + title.annotate ad, 500, 100, 50, 135 + (position * 55), line do self.fill = '#333333' end position += 1 end else wrap_text(do_rtl_witchcraft(article.title), 500, 55).split("\n").each do |line| - title.annotate ad, 500, 100, 50, 160 + position * 70, line do + title.annotate ad, 500, 100, 50, 160 + (position * 70), line do self.fill = '#333333' end position += 1 diff --git a/app/helpers/advertisements/codidact_helper.rb b/app/helpers/advertisements/codidact_helper.rb index ef63fd17cc000cfdb20cdac429d7332bb37961ec..aff74c2154a9ec8d5e9a56a464cfd08194c1d4f8 100644 --- a/app/helpers/advertisements/codidact_helper.rb +++ b/app/helpers/advertisements/codidact_helper.rb @@ -20,8 +20,8 @@ module Advertisements::CodidactHelper community_url.font_weight = 700 community_url.pointsize = 20 community_url.gravity = CenterGravity - community_url.annotate ad, 600, 50, 0, 450, 'Try on codidact.com' do - self.fill = 'white' + community_url.annotate ad, 600, 50, 0, 450, 'Try on codidact.com' do |img| + img.fill = 'white' end icon = ::Magick::ImageList.new('./app/assets/images/codidact.png') @@ -34,8 +34,8 @@ module Advertisements::CodidactHelper on_codidact.font = './app/assets/imgfonts/Roboto-Bold.ttf' on_codidact.pointsize = 25 on_codidact.gravity = CenterGravity - on_codidact.annotate ad, 400, 50, 100, 200, 'The Open Source Q&A Platform.' do - self.fill = '#666666' + on_codidact.annotate ad, 400, 50, 100, 200, 'The Open Source Q&A Platform.' do |img| + img.fill = '#666666' end slogan = Draw.new @@ -46,8 +46,8 @@ module Advertisements::CodidactHelper slogan.gravity = NorthGravity position = 0 wrap_text('Join our communities or build your own on codidact.com.', 500, 30).split("\n").each do |line| - slogan.annotate ad, 500, 100, 50, 300 + position * 45, line do - self.fill = '#333333' + slogan.annotate ad, 500, 100, 50, 300 + (position * 45), line do |img| + img.fill = '#333333' end position += 1 end diff --git a/app/helpers/advertisements/community_helper.rb b/app/helpers/advertisements/community_helper.rb index 1ef770c0c3e976feba7ff1dc2298b59a7fb38f1a..3d21b0708355497cc30b47358ef1be06d7351de1 100644 --- a/app/helpers/advertisements/community_helper.rb +++ b/app/helpers/advertisements/community_helper.rb @@ -20,8 +20,8 @@ module Advertisements::CommunityHelper community_url.font_weight = 700 community_url.pointsize = 20 community_url.gravity = CenterGravity - community_url.annotate ad, 600, 50, 0, 450, @community.host do - self.fill = 'white' + community_url.annotate ad, 600, 50, 0, 450, @community.host do |img| + img.fill = 'white' end icon_path = SiteSetting['SiteLogoPath'] @@ -37,8 +37,8 @@ module Advertisements::CommunityHelper community_name.font = './app/assets/imgfonts/Roboto-Black.ttf' community_name.pointsize = (50 + (100.0 / name.length)) community_name.gravity = CenterGravity - community_name.annotate ad, 600, 250, 0, 0, name do - self.fill = 'black' + community_name.annotate ad, 600, 250, 0, 0, name do |img| + img.fill = 'black' end end @@ -48,8 +48,8 @@ module Advertisements::CommunityHelper on_codidact.font = './app/assets/imgfonts/Roboto-Bold.ttf' on_codidact.pointsize = 25 on_codidact.gravity = EastGravity - on_codidact.annotate ad, 0, 50, 500, 150, 'on codidact.com' do - self.fill = '#666666' + on_codidact.annotate ad, 0, 50, 500, 150, 'on codidact.com' do |img| + img.fill = '#666666' end slogan = Draw.new @@ -60,8 +60,8 @@ module Advertisements::CommunityHelper slogan.gravity = NorthGravity position = 0 wrap_text(SiteSetting['SiteAdSlogan'], 500, 30).split("\n").each do |line| - slogan.annotate ad, 500, 100, 50, 225 + position * 45, line do - self.fill = '#333333' + slogan.annotate ad, 500, 100, 50, 225 + (position * 45), line do |img| + img.fill = '#333333' end position += 1 end diff --git a/app/helpers/advertisements/question_helper.rb b/app/helpers/advertisements/question_helper.rb index 20dc931e4247c4de4defa5c6e8cc81d0b5089d35..39dea137dfedb25737a21d2213b86f2891facf40 100644 --- a/app/helpers/advertisements/question_helper.rb +++ b/app/helpers/advertisements/question_helper.rb @@ -21,11 +21,11 @@ module Advertisements::QuestionHelper answer.font = './app/assets/imgfonts/Roboto-Bold.ttf' answer.pointsize = 40 answer.gravity = CenterGravity - answer.annotate ad, 600, 50, 0, 10, 'Could you answer' do - self.fill = 'white' + answer.annotate ad, 600, 50, 0, 10, 'Could you answer' do |img| + img.fill = 'white' end - answer.annotate ad, 600, 50, 0, 70, 'this question?' do - self.fill = 'white' + answer.annotate ad, 600, 50, 0, 70, 'this question?' do |img| + img.fill = 'white' end icon_path = SiteSetting.find_by(name: 'SiteLogoPath', community: question.community).typed @@ -40,8 +40,8 @@ module Advertisements::QuestionHelper community_name.font = './app/assets/imgfonts/Roboto-Bold.ttf' community_name.pointsize = 25 community_name.gravity = SouthWestGravity - community_name.annotate ad, 0, 0, 20, 20, question.community.name do - self.fill = '#4B68FF' + community_name.annotate ad, 0, 0, 20, 20, question.community.name do |img| + img.fill = '#4B68FF' end end @@ -51,8 +51,8 @@ module Advertisements::QuestionHelper community_url.font = './app/assets/imgfonts/Roboto-Bold.ttf' community_url.pointsize = 20 community_url.gravity = SouthEastGravity - community_url.annotate ad, 0, 0, 20, 20, question.community.host do - self.fill = '#666666' + community_url.annotate ad, 0, 0, 20, 20, question.community.host do |img| + img.fill = '#666666' end title = Draw.new @@ -65,15 +65,15 @@ module Advertisements::QuestionHelper if question.title.length > 60 title.pointsize = 35 wrap_text(do_rtl_witchcraft(question.title), 500, 35).split("\n").each do |line| - title.annotate ad, 500, 100, 50, 135 + position * 55, line do - self.fill = '#333333' + title.annotate ad, 500, 100, 50, 135 + (position * 55), line do |img| + img.fill = '#333333' end position += 1 end else wrap_text(do_rtl_witchcraft(question.title), 500, 55).split("\n").each do |line| - title.annotate ad, 500, 100, 50, 160 + position * 70, line do - self.fill = '#333333' + title.annotate ad, 500, 100, 50, 160 + (position * 70), line do |img| + img.fill = '#333333' end position += 1 end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index cb05d3324afd49f4971b164f94640587e6c898d1..175469b04e4b9625388ac2e90fb7463f91109fe6 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -29,7 +29,7 @@ module ApplicationHelper uri.path = base_uri.path end - query = query.merge(params.map { |k, v| [k.to_s, v.to_s] }.to_h) + query = query.merge(params.to_h { |k, v| [k.to_s, v.to_s] }) uri.query = query.map { |k, v| "#{k}=#{v}" }.join('&') uri.to_s end diff --git a/app/helpers/micro_auth/authentication_helper.rb b/app/helpers/micro_auth/authentication_helper.rb index 522c12799bd575e35694fbfa9a69f8dd985490d0..476daab8217552a6c09c6966f9d715cf90554ea6 100644 --- a/app/helpers/micro_auth/authentication_helper.rb +++ b/app/helpers/micro_auth/authentication_helper.rb @@ -21,6 +21,6 @@ module MicroAuth::AuthenticationHelper fields = [:id, :created_at, :is_global_moderator, :is_global_admin, :username, :website, :twitter, :staff, :developer, :discord] fields << :email if token.scope.include? 'pii' - fields.map { |f| [f, token.user.send(f)] }.to_h + fields.to_h { |f| [f, token.user.send(f)] } end end diff --git a/app/helpers/uploads_helper.rb b/app/helpers/uploads_helper.rb index 135bb34ba0db0b6691337f7b66ae1586e722465a..87d9daa0aaa95189e7bf5c0e8543429ef7cfdde5 100644 --- a/app/helpers/uploads_helper.rb +++ b/app/helpers/uploads_helper.rb @@ -7,7 +7,7 @@ module UploadsHelper end def valid_image?(io) - content_types = ActiveStorage::Variant::WEB_IMAGE_CONTENT_TYPES + content_types = Rails.application.config.active_storage.web_image_content_types extensions = content_types.map { |ct| ct.gsub('image/', '') } submitted_extension = io.original_filename.split('.')[-1].downcase content_types.include?(io.content_type) && extensions.include?(submitted_extension) && diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb index be9fa26b34dc7c248efc6e792595eb6f3b8b7298..2ebc8c27cacda0954185d3f31676527881ec197d 100644 --- a/app/helpers/users_helper.rb +++ b/app/helpers/users_helper.rb @@ -12,7 +12,7 @@ module UsersHelper def stack_oauth_url "https://stackoverflow.com/oauth?client_id=#{SiteSetting['SEApiClientId']}" \ - "&scope=&redirect_uri=#{stack_redirect_url}" + "&scope=&redirect_uri=#{stack_redirect_url}" end def can_change_category(user, target) diff --git a/app/models/ability.rb b/app/models/ability.rb index f0b7abb5cb9963d74dfbe1b567689d69248bece6..a3160b57dcaf8705fd3e8afdbc3d23e7580d984f 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -1,7 +1,7 @@ class Ability < ApplicationRecord include CommunityRelated - validates :internal_id, uniqueness: { scope: [:community_id] } + validates :internal_id, uniqueness: { scope: [:community_id], case_sensitive: false } def manual? post_score_threshold.nil? && edit_score_threshold.nil? && flag_score_threshold.nil? diff --git a/app/models/application_record.rb b/app/models/application_record.rb index c5299443ddc6656e654be74c792781a910074d98..0e552701f6f5cd9c2a9182f716b16f79ad79b75f 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -58,28 +58,28 @@ class ApplicationRecord < ActiveRecord::Base def self.useful_err_msg [ 'The inverted database guide has found an insurmountable problem. Please poke it with a ' \ - 'paperclip before anyone finds out.', + 'paperclip before anyone finds out.', 'The modular cable meter has found a problem. You need to kick your IT technician in the ' \ - 'shins immediately.', + 'shins immediately.', 'The integral output port has found a problem. Please take it back to the shop and take ' \ - 'the rest of the day off.', + 'the rest of the day off.', 'The integral expansion converter has encountered a terminal error. You must take legal ' \ - 'advice urgently.', + 'advice urgently.', 'Congratulations. You have reached the end of the internet.', 'The Spanish Inquisition raised an unexpected error. Cannot continue without comfy-chair-interrogation.', 'The server halted in an after-you loop.', 'A five-level precedence operation shifted too long and cannot be recovered without data loss. ' \ - 'Please re-enable the encryption protocol.', + 'Please re-enable the encryption protocol.', 'The server\'s headache has not improved in the last 24 hours. It needs to be rebooted.', 'The primary LIFO data recipient is currently on a holiday and will not be back before next Thursday.', 'The operator is currently trying to solve their Rubik\'s cube. We will come back to you when the ' \ - 'second layer is completed.', + 'second layer is completed.', 'The encryption protocol offered by the client predates the invention of irregular logarithmic ' \ - 'functions.', + 'functions.', 'The data in the secondary (backup) user registry is corrupted and needs to be re-filled with ' \ - 'random data again.', + 'random data again.', 'This community has reached a critical mass and collapsed into a black hole. Currently trying to ' \ - 'recover using Hawking radiation.', + 'recover using Hawking radiation.', 'Operations are on pause while we attempt to recapture the codidactyl. Please hold.', 'The data center is on fire. Please hold while we activate fire suppression systems.', 'The reciprocal controller flag is set incorrectly. Please stand on your head and rickroll yourself to fix this.' diff --git a/app/models/category.rb b/app/models/category.rb index fb376994aa628ac8fa0a4104abd71607f810f5dd..9cdaea7650374ce3646ce8240c7c98569511aa67 100644 --- a/app/models/category.rb +++ b/app/models/category.rb @@ -12,7 +12,7 @@ class Category < ApplicationRecord serialize :display_post_types, Array - validates :name, uniqueness: { scope: [:community_id] } + validates :name, uniqueness: { scope: [:community_id], case_sensitive: false } def new_posts_for?(user) key = "#{community_id}/#{user.id}/#{id}/last_visit" @@ -32,14 +32,14 @@ class Category < ApplicationRecord def self.by_lowercase_name(name) categories = Rails.cache.fetch 'categories/by_lowercase_name' do - Category.all.map { |c| [c.name.downcase, c] }.to_h + Category.all.to_h { |c| [c.name.downcase, c] } end categories[name] end def self.by_id(id) categories = Rails.cache.fetch 'categories/by_id' do - Category.all.map { |c| [c.id, c] }.to_h + Category.all.to_h { |c| [c.id, c] } end categories[id] end diff --git a/app/models/category_post_type.rb b/app/models/category_post_type.rb index f2de0366bc53fa506faa9c04c894a3223a806ed3..6dcc7fb902dfebd143755501c424740e007bf8a5 100644 --- a/app/models/category_post_type.rb +++ b/app/models/category_post_type.rb @@ -6,7 +6,7 @@ class CategoryPostType < ApplicationRecord def self.rep_changes Rails.cache.fetch 'network/category_post_types/rep_changes', include_community: false do - all.map { |cpt| [[cpt.category_id, cpt.post_type_id], { 1 => cpt.upvote_rep, -1 => cpt.downvote_rep }] }.to_h + all.to_h { |cpt| [[cpt.category_id, cpt.post_type_id], { 1 => cpt.upvote_rep, -1 => cpt.downvote_rep }] } end end end diff --git a/app/models/close_reason.rb b/app/models/close_reason.rb index 3a5cba810558c2f93dd2cf03cc29b7e48253123d..04e8b0f38641b908977e26d476872214f63fa0cd 100644 --- a/app/models/close_reason.rb +++ b/app/models/close_reason.rb @@ -3,5 +3,5 @@ class CloseReason < ApplicationRecord scope :active, -> { where(active: true) } - validates :name, uniqueness: { scope: [:community_id] } + validates :name, uniqueness: { scope: [:community_id], case_sensitive: false } end diff --git a/app/models/community.rb b/app/models/community.rb index 39dc40e1ed4d93bfb168587c6b2a087b71c720d1..d6eca7ac3f0c09a76e444d1041dab455f78acf22 100644 --- a/app/models/community.rb +++ b/app/models/community.rb @@ -4,5 +4,5 @@ class Community < ApplicationRecord default_scope { where(is_fake: false) } - validates :host, uniqueness: true + validates :host, uniqueness: { case_sensitive: false } end diff --git a/app/models/community_user.rb b/app/models/community_user.rb index 689619f215113b8c092606b105bc57199e8b582c..a62926dcc7b8e55872e1f63f3dd5fb7ad404b753 100644 --- a/app/models/community_user.rb +++ b/app/models/community_user.rb @@ -6,7 +6,7 @@ class CommunityUser < ApplicationRecord has_many :user_abilities, dependent: :destroy belongs_to :deleted_by, required: false, class_name: 'User' - validates :user_id, uniqueness: { scope: [:community_id] } + validates :user_id, uniqueness: { scope: [:community_id], case_sensitive: false } scope :for_context, -> { where(community_id: RequestContext.community_id) } scope :active, -> { where(deleted: false) } diff --git a/app/models/license.rb b/app/models/license.rb index de53af1bfcc1ba94f598d9b87904ee9389f6a30d..e2977eb53272052e42a1260cbe861c21036c88f5 100644 --- a/app/models/license.rb +++ b/app/models/license.rb @@ -4,7 +4,7 @@ class License < ApplicationRecord scope :enabled, -> { where(enabled: true) } scope :disabled, -> { where(enabled: false) } - validates :name, uniqueness: { scope: [:community_id] } + validates :name, uniqueness: { scope: [:community_id], case_sensitive: false } def self.default_order(category = nil, user_default = nil) if category.present? && user_default.present? diff --git a/app/models/micro_auth/app.rb b/app/models/micro_auth/app.rb index 858da57cb52c7d7bafbf7d0500cf773f99ea3ec3..eda9db114f4543b0e53358d7fe0786b3e78d9aef 100644 --- a/app/models/micro_auth/app.rb +++ b/app/models/micro_auth/app.rb @@ -4,9 +4,9 @@ class MicroAuth::App < ApplicationRecord belongs_to :user belongs_to :deactivated_by, class_name: 'User', required: false - validates :app_id, presence: true, uniqueness: true - validates :secret_key, presence: true, uniqueness: true - validates :public_key, presence: true, uniqueness: true + validates :app_id, presence: true, uniqueness: { case_sensitive: false } + validates :secret_key, presence: true, uniqueness: { case_sensitive: false } + validates :public_key, presence: true, uniqueness: { case_sensitive: false } def valid_redirect?(redirect_uri) valid_domain = URI(auth_domain.start_with?('http') ? auth_domain : "http://#{auth_domain}").hostname diff --git a/app/models/post.rb b/app/models/post.rb index effaab1de7cf1341de05575042736fc714803193..cac04dbc84ad70deb78bd863f15afbe8e07b9058 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -1,7 +1,7 @@ class Post < ApplicationRecord include CommunityRelated - belongs_to :user + belongs_to :user, optional: true belongs_to :post_type belongs_to :parent, class_name: 'Post', optional: true belongs_to :closed_by, class_name: 'User', optional: true @@ -28,7 +28,7 @@ class Post < ApplicationRecord serialize :tags_cache, Array validates :body, presence: true, length: { minimum: 30, maximum: 30_000 } - validates :doc_slug, uniqueness: { scope: [:community_id] }, if: -> { doc_slug.present? } + validates :doc_slug, uniqueness: { scope: [:community_id], case_sensitive: false }, if: -> { doc_slug.present? } validates :title, :body, :tags_cache, presence: true, if: -> { post_type.has_tags } validate :tags_in_tag_set, if: -> { post_type.has_tags } validate :maximum_tags, if: -> { post_type.has_tags } @@ -169,7 +169,7 @@ class Post < ApplicationRecord def reaction_list reactions.includes(:reaction_type).group_by(&:reaction_type_id) - .map { |_k, v| [v.first.reaction_type, v] }.to_h + .to_h { |_k, v| [v.first.reaction_type, v] } end private diff --git a/app/models/post_flag_type.rb b/app/models/post_flag_type.rb index 0088c28dc696d915800f416c971ae6deb3d3479d..4731ee12bf69f5c046e4b8feedd5563241e210e9 100644 --- a/app/models/post_flag_type.rb +++ b/app/models/post_flag_type.rb @@ -1,7 +1,7 @@ class PostFlagType < ApplicationRecord include CommunityRelated - validates :name, uniqueness: { scope: [:community_id] } + validates :name, uniqueness: { scope: [:community_id], case_sensitive: false } scope :not_confidential, -> { where(confidential: false) } scope :confidential, -> { where(confidential: true) } diff --git a/app/models/post_history.rb b/app/models/post_history.rb index 3676be76cef352af4ebc88bdd7bae16df83421e9..2a742a99f2a4e8578f210a60d2da333e5bbbe1b0 100644 --- a/app/models/post_history.rb +++ b/app/models/post_history.rb @@ -20,7 +20,7 @@ class PostHistory < ApplicationRecord object, user = args fields = [:before, :after, :comment, :before_title, :after_title, :before_tags, :after_tags] - values = fields.map { |f| [f, nil] }.to_h.merge(opts) + values = fields.to_h { |f| [f, nil] }.merge(opts) history_type_name = name.to_s history_type = PostHistoryType.find_by(name: history_type_name) @@ -39,13 +39,13 @@ class PostHistory < ApplicationRecord history = PostHistory.create params - post_history_tags = { before_tags: 'before', after_tags: 'after' }.map do |arg, rel| + post_history_tags = { before_tags: 'before', after_tags: 'after' }.to_h do |arg, rel| if values[arg].nil? [arg, nil] else [arg, values[arg].map { |t| { post_history_id: history.id, tag_id: t.id, relationship: rel } }] end - end.to_h.values.compact.flatten + end.values.compact.flatten history.post_history_tags = PostHistoryTag.create(post_history_tags) diff --git a/app/models/post_history_tag.rb b/app/models/post_history_tag.rb index 9f0f73b5db8c5c3448c8ec520b000e682dd5c7f1..b10d6e61b3e986ab0cded71e128a46b1c15ac3a5 100644 --- a/app/models/post_history_tag.rb +++ b/app/models/post_history_tag.rb @@ -2,5 +2,5 @@ class PostHistoryTag < ApplicationRecord belongs_to :post_history belongs_to :tag - validates :relationship, uniqueness: { scope: [:tag_id, :post_history_id] } + validates :relationship, uniqueness: { scope: [:tag_id, :post_history_id], case_sensitive: false } end diff --git a/app/models/post_history_type.rb b/app/models/post_history_type.rb index 8eeffde252512cd0ab68eda2072e6efd30b25443..fd5929a60baedd5c43a340ce02428b95c75a428b 100644 --- a/app/models/post_history_type.rb +++ b/app/models/post_history_type.rb @@ -1,5 +1,5 @@ class PostHistoryType < ApplicationRecord has_many :post_histories - validates :name, uniqueness: true + validates :name, uniqueness: { case_sensitive: false } end diff --git a/app/models/post_type.rb b/app/models/post_type.rb index b8e2db3451dafa50acd587f28d3a2dd1e6afe8e2..7f3e7570b3fc372bf027820ce6d903a7c0a1d1de 100644 --- a/app/models/post_type.rb +++ b/app/models/post_type.rb @@ -4,7 +4,7 @@ class PostType < ApplicationRecord has_many :categories, through: :category_post_types belongs_to :answer_type, required: false, class_name: 'PostType' - validates :name, uniqueness: true + validates :name, uniqueness: { case_sensitive: false } validates :answer_type_id, presence: true, if: :has_answers? def reactions @@ -21,7 +21,7 @@ class PostType < ApplicationRecord def self.mapping Rails.cache.fetch 'network/post_types/post_type_ids', include_community: false do - PostType.all.map { |pt| [pt.name, pt.id] }.to_h + PostType.all.to_h { |pt| [pt.name, pt.id] } end end diff --git a/app/models/reaction.rb b/app/models/reaction.rb index 313aa665ba35ce73bba7f65f4a519d4529fd187a..28b039ced12c79070a1ab3cea340081fadd749ef 100644 --- a/app/models/reaction.rb +++ b/app/models/reaction.rb @@ -2,7 +2,7 @@ class Reaction < ApplicationRecord belongs_to :reaction_type belongs_to :user belongs_to :post - belongs_to :comment + belongs_to :comment, optional: true default_scope { joins(:reaction_type).where(reaction_types: { community_id: RequestContext.community_id }) } end diff --git a/app/models/reaction_type.rb b/app/models/reaction_type.rb index e08c368c8f0ef820c5911de94ed0cdd218bc6270..8f50b4ea1141b57d03b4adba4dfedb8543bb66ab 100644 --- a/app/models/reaction_type.rb +++ b/app/models/reaction_type.rb @@ -2,7 +2,7 @@ class ReactionType < ApplicationRecord include CommunityRelated belongs_to :post_type, class_name: 'PostType', optional: true - validates :name, uniqueness: { scope: [:community_id] } + validates :name, uniqueness: { scope: [:community_id], case_sensitive: false } scope :active, -> { where(active: true) } end diff --git a/app/models/request_context.rb b/app/models/request_context.rb index 96d49f0e731821b03cb1e1200871ff35a55c39b8..6967f1167b09269f53c263975ac3d8c294fd4ac2 100644 --- a/app/models/request_context.rb +++ b/app/models/request_context.rb @@ -13,7 +13,7 @@ class RequestContext $redis else processed = ERB.new(File.read(Rails.root.join('config', 'database.yml'))).result(binding) - $redis ||= Redis.new(YAML.safe_load(processed, [], [], true)["redis_#{Rails.env}"]) + $redis ||= Redis.new(YAML.safe_load(processed, [], [], true)["redis_#{Rails.env}"].deep_symbolize_keys) end rescue NoMethodError raise LoadError, "You don't appear to have any Redis config in config/database.yml" diff --git a/app/models/site_setting.rb b/app/models/site_setting.rb index a4e5e2f7675b027eeecfde68a16fef822f51c869..ab5c9504b75538d42a1c38b675afbb82eb4b6791 100644 --- a/app/models/site_setting.rb +++ b/app/models/site_setting.rb @@ -1,9 +1,9 @@ # Represents a site setting. Site settings control the operation and display of most aspects of the site, such as # reputation awards, additional content, and site constants such as name and logo. class SiteSetting < ApplicationRecord - belongs_to :community + belongs_to :community, optional: true - validates :name, uniqueness: { scope: [:community_id] } + validates :name, uniqueness: { scope: [:community_id], case_sensitive: false } scope :for_community_id, ->(community_id) { where(community_id: community_id) } scope :global, -> { for_community_id(nil) } @@ -50,10 +50,10 @@ class SiteSetting < ApplicationRecord settings = if missing.empty? {} else - SiteSetting.where(name: name, community_id: missing).map { |s| [s.community_id, s] }.to_h + SiteSetting.where(name: name, community_id: missing).to_h { |s| [s.community_id, s] } end - Rails.cache.write_multi missing.map { |cid| [keys[cid], settings[cid]&.typed] }.to_h - communities.map do |c| + Rails.cache.write_multi(missing.to_h { |cid| [keys[cid], settings[cid]&.typed] }) + communities.to_h do |c| [ c.id, if cached.include?(keys[c.id]) @@ -66,7 +66,7 @@ class SiteSetting < ApplicationRecord settings[nil]&.typed end ] - end.to_h + end end end diff --git a/app/models/tag.rb b/app/models/tag.rb index d7097de8a385996bdab5df3640e466dcd1d95d3b..1b78a95fe534ac04448e7b86570e3df5995fdf04 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -13,7 +13,7 @@ class Tag < ApplicationRecord validates :name, presence: true, format: { with: /[^ \t]+/, message: 'Tag names may not include spaces' } validate :parent_not_self validate :parent_not_own_child - validates :name, uniqueness: { scope: [:tag_set_id] } + validates :name, uniqueness: { scope: [:tag_set_id], case_sensitive: false } def self.search(term) where('name LIKE ?', "%#{sanitize_sql_like(term)}%") diff --git a/app/models/tag_set.rb b/app/models/tag_set.rb index 0a3d04066a8efbe4ece7b08bd9a2301f3cd92501..e71e33c89923e0366f39940f3e3e9eee39d280e7 100644 --- a/app/models/tag_set.rb +++ b/app/models/tag_set.rb @@ -4,7 +4,7 @@ class TagSet < ApplicationRecord has_many :tags_with_paths, class_name: 'TagWithPath' has_many :categories - validates :name, uniqueness: { scope: [:community_id] }, presence: true + validates :name, uniqueness: { scope: [:community_id], case_sensitive: false }, presence: true def self.meta where(name: 'Meta').first diff --git a/app/models/user.rb b/app/models/user.rb index 401a238bc57a72f8cbcdfa9e02fc21a1f6148841..84d79db011cd7b4b5fa01166e390f893027c31eb 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -27,7 +27,7 @@ class User < ApplicationRecord belongs_to :deleted_by, required: false, class_name: 'User' validates :username, presence: true, length: { minimum: 3, maximum: 50 } - validates :login_token, uniqueness: { allow_blank: true } + validates :login_token, uniqueness: { allow_blank: true, case_sensitive: false } validate :no_links_in_username validate :username_not_fake_admin validate :no_blank_unicode_in_username @@ -92,8 +92,7 @@ class User < ApplicationRecord end def create_notification(content, link) - notification = Notification.create!(content: content, link: link) - notifications << notification + notifications.create!(content: content, link: link) end def unread_count diff --git a/app/models/vote.rb b/app/models/vote.rb index 97b9c4cac30a51e451ec66c59857656e2b76203f..a7a3505ab4474cafe34ec05de066661c2ee0bb1c 100644 --- a/app/models/vote.rb +++ b/app/models/vote.rb @@ -35,7 +35,7 @@ class Vote < ApplicationRecord def rep_change(direction) change = CategoryPostType.rep_changes[[post.category_id, post.post_type_id]][vote_type] || 0 - recv_user.update!(reputation: recv_user.reputation + direction * change) + recv_user.update!(reputation: recv_user.reputation + (direction * change)) end def post_not_deleted diff --git a/app/models/warning_template.rb b/app/models/warning_template.rb index bd1d262db28195550bbfdf141b8f2828e53846e9..ec0b77dab514e712392ecf69bdcd4df59d4e7159 100644 --- a/app/models/warning_template.rb +++ b/app/models/warning_template.rb @@ -3,7 +3,7 @@ require 'base64' class WarningTemplate < ApplicationRecord include CommunityRelated - validates :name, uniqueness: { scope: [:community_id] } + validates :name, uniqueness: { scope: [:community_id], case_sensitive: false } def body_as_b64 body_with_site_replacements = body.gsub '$SiteName', SiteSetting['SiteName'] diff --git a/app/views/notifications/index.erb b/app/views/notifications/index.html.erb similarity index 100% rename from app/views/notifications/index.erb rename to app/views/notifications/index.html.erb diff --git a/app/views/users/edit_profile.erb b/app/views/users/edit_profile.html.erb similarity index 100% rename from app/views/users/edit_profile.erb rename to app/views/users/edit_profile.html.erb diff --git a/bin/rails b/bin/rails index 0138d79b751b9668a1036329a9ef29a213836162..7a8ff81e6ecb70a5e15b5d52579e330e145a9f07 100755 --- a/bin/rails +++ b/bin/rails @@ -1,9 +1,9 @@ #!/usr/bin/env ruby begin - load File.expand_path('../spring', __FILE__) + load File.expand_path('spring', __dir__) rescue LoadError => e raise unless e.message.include?('spring') end -APP_PATH = File.expand_path('../../config/application', __FILE__) +APP_PATH = File.expand_path('../config/application', __dir__) require_relative '../config/boot' require 'rails/commands' diff --git a/bin/rake b/bin/rake old mode 100644 new mode 100755 index d87d5f578104597c1d1b951b55942e37f8af1277..0ba8c48cbabd7dc484edf9a7b75bbbac1dfd47f7 --- a/bin/rake +++ b/bin/rake @@ -1,6 +1,6 @@ #!/usr/bin/env ruby begin - load File.expand_path('../spring', __FILE__) + load File.expand_path('spring', __dir__) rescue LoadError => e raise unless e.message.include?('spring') end diff --git a/bin/setup b/bin/setup old mode 100644 new mode 100755 index acdb2c1389c502f79a967384cac1c5adcea10ec2..a8e630c6ad484de81769c29d8ab32c2409fff084 --- a/bin/setup +++ b/bin/setup @@ -1,29 +1,33 @@ #!/usr/bin/env ruby -require 'pathname' +require 'fileutils' # path to your application root. -APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) +APP_ROOT = File.expand_path('..', __dir__) -Dir.chdir APP_ROOT do - # This script is a starting point to setup your application. - # Add necessary setup steps to this file: +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. - puts "== Installing dependencies ==" - system "gem install bundler --conservative" - system "bundle check || bundle install" + puts '== Installing dependencies ==' + system! 'gem install bundler --conservative' + system('bundle check') || system!('bundle install') # puts "\n== Copying sample files ==" - # unless File.exist?("config/database.yml") - # system "cp config/database.yml.sample config/database.yml" + # unless File.exist?('config/database.yml') + # FileUtils.cp 'config/database.yml.sample', 'config/database.yml' # end puts "\n== Preparing database ==" - system "bin/rake db:setup" + system! 'bin/rails db:prepare' puts "\n== Removing old logs and tempfiles ==" - system "rm -f log/*" - system "rm -rf tmp/cache" + system! 'bin/rails log:clear tmp:clear' puts "\n== Restarting application server ==" - system "touch tmp/restart.txt" + system! 'bin/rails restart' end diff --git a/bin/spring b/bin/spring old mode 100644 new mode 100755 index 7fe232c3aae5996a1d6ca1f69d10e636630f5c5c..788d33ba9f7790c87c3662b291be9230e9da5f9e --- a/bin/spring +++ b/bin/spring @@ -1,15 +1,16 @@ #!/usr/bin/env ruby -# This file loads spring without using Bundler, in order to be fast. +# This file loads Spring without using loading other gems in the Gemfile, in order to be fast. # It gets overwritten when you run the `spring binstub` command. -unless defined?(Spring) - require 'rubygems' +if !defined?(Spring) && [nil, 'development'].include?(ENV["RAILS_ENV"]) require 'bundler' - if (match = Bundler.default_lockfile.read.match(/^GEM$.*?^ (?: )*spring \((.*?)\)$.*?^$/m)) - Gem.paths = { 'GEM_PATH' => [Bundler.bundle_path.to_s, *Gem.path].uniq.join(Gem.path_separator) } - gem 'spring', match[1] + Bundler.locked_gems.specs.find { |spec| spec.name == 'spring' }&.tap do |spring| + Gem.use_paths Gem.dir, Bundler.bundle_path.to_s, *Gem.path + gem 'spring', spring.version require 'spring/binstub' + rescue Gem::LoadError + # Ignore when Spring is not installed. end end diff --git a/config.ru b/config.ru index 9797be5aedf4acdf3ccc79517e687024682d566a..ad1fbf295bb6d3223a9eefd2db2688c3363cc4b4 100644 --- a/config.ru +++ b/config.ru @@ -1,4 +1,6 @@ # This file is used by Rack-based servers to start the application. -require ::File.expand_path('config/environment', __dir__) +require_relative 'config/environment' + run Rails.application +Rails.application.load_server diff --git a/config/application.rb b/config/application.rb index c5066518952067e625d5860ec7a504b579701e0e..e5c0a400456e88b8e230f8430e880e50a73f7a14 100644 --- a/config/application.rb +++ b/config/application.rb @@ -1,4 +1,4 @@ -require File.expand_path('../boot', __FILE__) +require_relative 'boot' require 'rails/all' @@ -12,7 +12,8 @@ module Qpixel class Application < Rails::Application # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers - # -- all .rb files in that directory are automatically loaded. + # -- all .rb files in that directory are automatically loaded after loading + # the framework and any gems in your application. # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. @@ -22,6 +23,11 @@ module Qpixel # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] # config.i18n.default_locale = :de + # Initialize configuration defaults for originally generated Rails version. + config.load_defaults 7.0 + + config.autoload_paths << Rails.root.join('lib') + config.exceptions_app = -> (env) do ErrorsController.action(:error).call(env) end diff --git a/config/boot.rb b/config/boot.rb index 6b750f00b1dff4d94937b97ae0dbf76784b02164..d69bd27dca71c3e9d54603faf3f44f1a0fd03bcb 100644 --- a/config/boot.rb +++ b/config/boot.rb @@ -1,3 +1,3 @@ -ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) -require 'bundler/setup' # Set up gems listed in the Gemfile. +require "bundler/setup" # Set up gems listed in the Gemfile. diff --git a/config/cable.yml b/config/cable.yml new file mode 100644 index 0000000000000000000000000000000000000000..e2db5fdaf139a23404fb579b395f9ca8ee2b4276 --- /dev/null +++ b/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: test + +production: + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: qpixel_production diff --git a/config/environment.rb b/config/environment.rb index ee8d90dc651948269f1b869953ff04774e737307..426333bb46978d897be4cc6fac77b9fcaacf59d0 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -1,5 +1,5 @@ # Load the Rails application. -require File.expand_path('../application', __FILE__) +require_relative 'application' # Initialize the Rails application. Rails.application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb index a6bc5533e7af23a8b4bee6d9ceb4cb822adafebe..bea4950c288fd38c9809a985baf83ce313eea659 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -1,8 +1,11 @@ +require 'active_support/core_ext/integer/time' +require 'namespaced_env_cache' + Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. - # In the development environment your application's code is reloaded on - # every request. This slows down response time but is perfect for development + # In the development environment your application's code is reloaded any time + # it changes. This slows down response time but is perfect for development # since you don't have to restart the web server when you make code changes. config.cache_classes = false @@ -10,25 +13,54 @@ Rails.application.configure do config.eager_load = false # Show full error reports and disable caching. - config.consider_all_requests_local = false + config.consider_all_requests_local = true config.action_controller.perform_caching = false + # Enable server timing + config.server_timing = true + + # Set the cache store to the redis that was configured in the database.yml + processed = ERB.new(File.read(Rails.root.join('config', 'database.yml'))).result(binding) + redis_config = YAML.safe_load(processed, [], [], true)["redis_#{Rails.env}"] + config.cache_store = QPixel::NamespacedEnvCache.new( + ActiveSupport::Cache::RedisCacheStore.new( + url: "redis://#{redis_config['host']}:#{redis_config['port']}" + ) + ) + + # Store uploaded files on the local file system (see config/storage.yml for options). + config.active_storage.service = :local + # Don't care if the mailer can't send. config.action_mailer.raise_delivery_errors = false config.action_mailer.delivery_method = :ses config.action_mailer.asset_host = 'https://meta.codidact.com' + config.action_mailer.perform_caching = false + # Print deprecation notices to the Rails logger. config.active_support.deprecation = :log + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise + + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] + # Raise an error on page load if there are pending migrations. config.active_record.migration_error = :page_load + # Highlight code that triggered database queries in logs. + config.active_record.verbose_query_logs = true + # 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 + # Suppress logger output for asset requests. + config.assets.quiet = true + # Asset digests allow you to set far-future HTTP expiration dates on all assets, # yet still be able to expire them through the digest params. config.assets.digest = true @@ -38,18 +70,16 @@ Rails.application.configure do # Raises helpful error messages. config.assets.raise_runtime_errors = true - # Raises error for missing translations - # config.action_view.raise_on_missing_translations = true + # Raises error for missing translations. + config.i18n.raise_on_missing_translations = true config.action_mailer.delivery_method = :letter_opener_web config.action_mailer.default_url_options = { host: 'meta.codidact.com', protocol: 'https' } - config.active_storage.service = :local - # Ensure docker ip added to allowed, given that we are in container if File.file?('/.dockerenv') == true host_ip = `/sbin/ip route|awk '/default/ { print $3 }'`.strip - config.web_console.whitelisted_ips << host_ip + config.web_console.allowed_ips << host_ip # ==> Configuration for :confirmable # A period that the user is allowed to access the website even without @@ -57,4 +87,10 @@ Rails.application.configure do days = ENV['CONFIRMABLE_ALLOWED_ACCESS_DAYS'] || '0' config.allow_unconfirmed_access_for = (days.to_i).days end + + # Annotate rendered view with file names. + # 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 end diff --git a/config/environments/production.rb b/config/environments/production.rb index 7b0b1fa274031aa601ba16ca236aef27577a6ce3..f86b8ec2fc68b95c52eee9c337ff352d0151458e 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -1,3 +1,6 @@ +require 'active_support/core_ext/integer/time' +require 'namespaced_env_cache' + Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. @@ -14,33 +17,37 @@ Rails.application.configure do config.consider_all_requests_local = false config.action_controller.perform_caching = true - # Enable Rack::Cache to put a simple HTTP cache in front of your application - # Add `rack-cache` to your Gemfile before enabling this. - # For large-scale production use, consider using a caching reverse proxy like - # NGINX, varnish or squid. - # config.action_dispatch.rack_cache = 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). + # 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? # Compress JavaScripts and CSS. - config.assets.js_compressor = Uglifier.new(harmony: true) + config.assets.js_compressor = Terser.new + # Compress CSS using a preprocessor. # config.assets.css_compressor = :sass # Do not fallback to assets pipeline if a precompiled asset is missed. config.assets.compile = false - # Asset digests allow you to set far-future HTTP expiration dates on all assets, - # yet still be able to expire them through the digest params. - config.assets.digest = true - - # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # 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 + # Store uploaded files on Amazon S3 (see config/storage.yml for options). + config.active_storage.service = :s3 + + # 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.*/ ] + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. # config.force_ssl = true @@ -51,14 +58,14 @@ Rails.application.configure do # Prepend all log lines with the following tags. config.log_tags = [ :subdomain, :uuid ] - # Use a different logger for distributed setups. - # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) - # Use a different cache store in production. - config.cache_store = :redis_cache_store, { url: 'redis://localhost:6379/1' } + config.cache_store = QPixel::NamespacedEnvCache.new( + ActiveSupport::Cache::RedisCacheStore.new(url: 'redis://localhost:6379/1') + ) - # Enable serving of images, stylesheets, and JavaScripts from an asset server. - # config.action_controller.asset_host = 'http://assets.example.com' + # 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 = "qpixel_production" # Ignore bad email addresses and do not raise email delivery errors. # Set this to true and configure the email server for immediate delivery to raise delivery errors. @@ -68,18 +75,20 @@ 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 + # Don't log any deprecations. + config.active_support.report_deprecations = false # Use default logging formatter so that PID and timestamp are not suppressed. config.log_formatter = ::Logger::Formatter.new - # Do not dump schema after migrations. - config.active_record.dump_schema_after_migration = false - - config.active_storage.service = :s3 + # Use a different logger for distributed setups. + # require "syslog/logger" + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') config.action_mailer.delivery_method = :ses config.action_mailer.default_url_options = { host: 'meta.codidact.com', protocol: 'https' } config.action_mailer.asset_host = 'https://meta.codidact.com' + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false end diff --git a/config/environments/test.rb b/config/environments/test.rb index e266a2b00edd217d88d7541a6a5d8627fe461bb4..1b6bc80c8f81c8c77247bfba03bc40213d4af1a6 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -1,46 +1,71 @@ +require 'active_support/core_ext/integer/time' +require 'namespaced_env_cache' + +# The test environment is used exclusively to run your application's +# test suite. You never need to work with it otherwise. Remember that +# your test database is "scratch space" for the test suite and is wiped +# and recreated between test runs. Don't rely on the data there! + Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. - # The test environment is used exclusively to run your application's - # test suite. You never need to work with it otherwise. Remember that - # your test database is "scratch space" for the test suite and is wiped - # and recreated between test runs. Don't rely on the data there! - config.cache_classes = true + # Turn false under Spring and add config.action_view.cache_template_loading = true. + config.cache_classes = false + config.action_view.cache_template_loading = true # 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 - # Configure static file server for tests with Cache-Control for performance. + # Configure public file server for tests with Cache-Control for performance. config.public_file_server.enabled = true - config.public_file_server.headers = { 'Cache-Control' => 'public, max-age=3600' } + config.public_file_server.headers = { + 'Cache-Control' => "public, max-age=#{1.hour.to_i}" + } # Show full error reports and disable caching. config.consider_all_requests_local = true config.action_controller.perform_caching = false + processed = ERB.new(File.read(Rails.root.join('config', 'database.yml'))).result(binding) + redis_config = YAML.safe_load(processed, [], [], true)["redis_#{Rails.env}"] + config.cache_store = QPixel::NamespacedEnvCache.new( + ActiveSupport::Cache::RedisCacheStore.new( + url: "redis://#{redis_config['host']}:#{redis_config['port']}" + ) + ) + # Raise exceptions instead of rendering exception templates. config.action_dispatch.show_exceptions = false # Disable request forgery protection in test environment. config.action_controller.allow_forgery_protection = false + # Store uploaded files on the local file system in a temporary directory. + config.active_storage.service = :test + + config.action_mailer.perform_caching = false + # Tell Action Mailer not to deliver emails to the real world. # The :test delivery method accumulates sent emails in the # ActionMailer::Base.deliveries array. config.action_mailer.delivery_method = :test - # Randomize the order test cases are executed. - config.active_support.test_order = :random + config.action_mailer.default_url_options = { host: 'test.host' } # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr - # Raises error for missing translations - # config.action_view.raise_on_missing_translations = true + # Raise exceptions for disallowed deprecations. + config.active_support.disallowed_deprecation = :raise - config.active_storage.service = :test + # Tell Active Support which deprecation messages to disallow. + config.active_support.disallowed_deprecation_warnings = [] - config.action_mailer.default_url_options = { host: 'test.host' } + # Raises error for missing translations. + config.i18n.raise_on_missing_translations = true + + # Annotate rendered view with file names. + # config.action_view.annotate_rendered_view_with_filenames = true end diff --git a/config/initializers/application_controller_renderer.rb b/config/initializers/application_controller_renderer.rb new file mode 100644 index 0000000000000000000000000000000000000000..89d2efab2ba659d7814a7665a99f7f8d7429a072 --- /dev/null +++ b/config/initializers/application_controller_renderer.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +# ActiveSupport::Reloader.to_prepare do +# ApplicationController.renderer.defaults.merge!( +# http_host: 'example.org', +# https: false +# ) +# end diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb index 01ef3e6630af133b41bd954e220f31231aa281d9..fe48fc34ee221419425f67157d0e0e99bad55a38 100644 --- a/config/initializers/assets.rb +++ b/config/initializers/assets.rb @@ -3,9 +3,10 @@ # Version of your assets, change this if you want to expire all your assets. Rails.application.config.assets.version = '1.0' -# Add additional assets to the asset load path +# Add additional assets to the asset load path. # Rails.application.config.assets.paths << Emoji.images_path # Precompile additional assets. -# application.js, application.css, and all non-JS/CSS in app/assets folder are already added. -# Rails.application.config.assets.precompile += %w( search.js ) +# 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 ) diff --git a/config/initializers/backtrace_silencers.rb b/config/initializers/backtrace_silencers.rb index 59385cdf379bd06a8d2326dcd4de6d5cd5d3f5b0..33699c30910b95ab124dc40bb9a244dac0093578 100644 --- a/config/initializers/backtrace_silencers.rb +++ b/config/initializers/backtrace_silencers.rb @@ -1,7 +1,8 @@ # Be sure to restart your server when you modify this file. # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. -# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } +# Rails.backtrace_cleaner.add_silencer { |line| /my_noisy_library/.match?(line) } -# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. -# Rails.backtrace_cleaner.remove_silencers! +# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code +# by setting BACKTRACE=1 before calling your invocation, like "BACKTRACE=1 ./bin/rails runner 'MyClass.perform'". +Rails.backtrace_cleaner.remove_silencers! if ENV["BACKTRACE"] diff --git a/config/initializers/content_security_policy.rb b/config/initializers/content_security_policy.rb new file mode 100644 index 0000000000000000000000000000000000000000..54f47cf15fe5026bede1bd6a9acb4ef815bf22ab --- /dev/null +++ b/config/initializers/content_security_policy.rb @@ -0,0 +1,25 @@ +# Be sure to restart your server when you modify this file. + +# Define an application-wide content security policy. +# See the Securing Rails Applications Guide for more information: +# https://guides.rubyonrails.org/security.html#content-security-policy-header + +# Rails.application.configure do +# config.content_security_policy do |policy| +# policy.default_src :self, :https +# policy.font_src :self, :https, :data +# policy.img_src :self, :https, :data +# policy.object_src :none +# policy.script_src :self, :https +# policy.style_src :self, :https +# # Specify URI for violation reports +# # policy.report_uri "/csp-violation-report-endpoint" +# end +# +# # Generate session nonces for permitted importmap and inline scripts +# config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s } +# config.content_security_policy_nonce_directives = %w(script-src) +# +# # Report violations without enforcing the policy. +# # config.content_security_policy_report_only = true +# end diff --git a/config/initializers/cookie_rotator.rb b/config/initializers/cookie_rotator.rb new file mode 100644 index 0000000000000000000000000000000000000000..0528cb3f57b8d1718bb05f834fbbd05c8ee79072 --- /dev/null +++ b/config/initializers/cookie_rotator.rb @@ -0,0 +1,22 @@ +# Rails 7 changes the cookie encryption, which means old cookies can no longer be read by it. +# To fix this, this file provides a so-called cookie rotator to be able to understand older cookies +# This file was provided by the official migration guide from rails 6.1 to rails 7.0 +Rails.application.config.after_initialize do + Rails.application.config.action_dispatch.cookies_rotations.tap do |cookies| + authenticated_encrypted_cookie_salt = Rails.application.config.action_dispatch.authenticated_encrypted_cookie_salt + signed_cookie_salt = Rails.application.config.action_dispatch.signed_cookie_salt + + secret_key_base = Rails.application.secret_key_base + + key_generator = ActiveSupport::KeyGenerator.new( + secret_key_base, iterations: 1000, hash_digest_class: OpenSSL::Digest::SHA1 + ) + key_len = ActiveSupport::MessageEncryptor.key_len + + old_encrypted_secret = key_generator.generate_key(authenticated_encrypted_cookie_salt, key_len) + old_signed_secret = key_generator.generate_key(signed_cookie_salt) + + cookies.rotate :encrypted, old_encrypted_secret + cookies.rotate :signed, old_signed_secret + end +end diff --git a/config/initializers/cookies_serializer.rb b/config/initializers/cookies_serializer.rb index 7f70458dee62b4a0f5233e4be7b8838b8400cbe8..5a6a32d371fe575acf9f87e2ab7e8ae4d0f11e69 100644 --- a/config/initializers/cookies_serializer.rb +++ b/config/initializers/cookies_serializer.rb @@ -1,3 +1,5 @@ # Be sure to restart your server when you modify this file. +# Specify a serializer for the signed and encrypted cookie jars. +# Valid options are :json, :marshal, and :hybrid. Rails.application.config.action_dispatch.cookies_serializer = :json diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 490e5161cc438cd0f4c70a018e9a0a8d8d6f61dc..2b2af4c0525ddbe9bc004152b68618bc1f65d1d7 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -1,3 +1,5 @@ +require 'devise/mailer' + Devise::Mailer.layout 'devise_mailer' # Use this hook to configure devise mailer, warden hooks and so forth. diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb index 4a994e1e7bb7ce28dcec98bad48b9a891d7dec51..adc6568ce83724d2b01d7232b0873bda7c249b11 100644 --- a/config/initializers/filter_parameter_logging.rb +++ b/config/initializers/filter_parameter_logging.rb @@ -1,4 +1,8 @@ # Be sure to restart your server when you modify this file. -# Configure sensitive parameters which will be filtered from the log file. -Rails.application.config.filter_parameters += [:password] +# 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. +Rails.application.config.filter_parameters += [ + :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +] diff --git a/config/initializers/permissions_policy.rb b/config/initializers/permissions_policy.rb new file mode 100644 index 0000000000000000000000000000000000000000..00f64d71b03e029116af7b1713f450e9635fb10f --- /dev/null +++ b/config/initializers/permissions_policy.rb @@ -0,0 +1,11 @@ +# 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" +# end diff --git a/config/initializers/wrap_parameters.rb b/config/initializers/wrap_parameters.rb index 33725e95fd22b9053f75ef6626aa1af781ebe947..6b3f5353d0862e1c7028a77d9798dfd0030216ac 100644 --- a/config/initializers/wrap_parameters.rb +++ b/config/initializers/wrap_parameters.rb @@ -10,5 +10,5 @@ end # To enable root element in JSON for ActiveRecord objects. # ActiveSupport.on_load(:active_record) do -# self.include_root_in_json = true +# self.include_root_in_json = true # end diff --git a/config/initializers/zz_codidact_sites.rb b/config/initializers/zz_codidact_sites.rb index 56b2c18a1aebd695a0b96e9fbd0f984dff76dd82..b745b63de8f4d4c3529444aa00df82f851535d3b 100644 --- a/config/initializers/zz_codidact_sites.rb +++ b/config/initializers/zz_codidact_sites.rb @@ -1,7 +1,7 @@ Rails.cache.persistent 'codidact_sites', clear: true do - # Do not show codidact_sites for development - # (allows offline dev) - if Rails.env.development? + # Do not show codidact_sites for development (allows offline dev) + # Do not spam codidact.com while running the tests. + if Rails.env.development? || Rails.env.test? [] else response = Net::HTTP.get_response(URI('https://codidact.com/communities.json')) diff --git a/config/locales/strings/en.g.yml b/config/locales/strings/en.g.yml index cfb820a363129770889e0a1a39fcc84014ed5533..53590fa2f32a4013a241e421fccf74693496e52b 100644 --- a/config/locales/strings/en.g.yml +++ b/config/locales/strings/en.g.yml @@ -1,6 +1,7 @@ en: g: # Alphabetical order please! + age: 'age' at: 'at' body: 'body' cancel: 'cancel' diff --git a/config/puma.rb b/config/puma.rb new file mode 100644 index 0000000000000000000000000000000000000000..9e81e8cc005e1d8dc71983ab182e521b91b03943 --- /dev/null +++ b/config/puma.rb @@ -0,0 +1,42 @@ +# 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 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" + +# 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" } + +# 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. +plugin :tmp_restart diff --git a/config/spring.rb b/config/spring.rb new file mode 100644 index 0000000000000000000000000000000000000000..db5bf1307a377a1bd95936c88c3d9bc338ab2319 --- /dev/null +++ b/config/spring.rb @@ -0,0 +1,6 @@ +Spring.watch( + ".ruby-version", + ".rbenv-vars", + "tmp/restart.txt", + "tmp/caching-dev.txt" +) diff --git a/db/migrate/20220815130313_add_foreign_key_constraint_to_active_storage_attachments_for_blob_id.active_storage.rb b/db/migrate/20220815130313_add_foreign_key_constraint_to_active_storage_attachments_for_blob_id.active_storage.rb new file mode 100644 index 0000000000000000000000000000000000000000..ff5d72c7ea6e651d1c14387086a79bd527ab6aa9 --- /dev/null +++ b/db/migrate/20220815130313_add_foreign_key_constraint_to_active_storage_attachments_for_blob_id.active_storage.rb @@ -0,0 +1,10 @@ +# This migration comes from active_storage (originally 20180723000244) +class AddForeignKeyConstraintToActiveStorageAttachmentsForBlobId < ActiveRecord::Migration[6.0] + def up + return if foreign_key_exists?(:active_storage_attachments, column: :blob_id) + + if table_exists?(:active_storage_blobs) + add_foreign_key :active_storage_attachments, :active_storage_blobs, column: :blob_id + end + end +end diff --git a/db/migrate/20220901194344_add_service_name_to_active_storage_blobs.active_storage.rb b/db/migrate/20220901194344_add_service_name_to_active_storage_blobs.active_storage.rb new file mode 100644 index 0000000000000000000000000000000000000000..9967a1323707f5a6a17135422feb9598884e9e15 --- /dev/null +++ b/db/migrate/20220901194344_add_service_name_to_active_storage_blobs.active_storage.rb @@ -0,0 +1,18 @@ +# This migration comes from active_storage (originally 20190112182829) +class AddServiceNameToActiveStorageBlobs < ActiveRecord::Migration[6.0] + def up + 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 + remove_column :active_storage_blobs, :service_name + end +end diff --git a/db/migrate/20220901194345_create_active_storage_variant_records.active_storage.rb b/db/migrate/20220901194345_create_active_storage_variant_records.active_storage.rb new file mode 100644 index 0000000000000000000000000000000000000000..a2862695e117fc578132418eb07a59e74373e227 --- /dev/null +++ b/db/migrate/20220901194345_create_active_storage_variant_records.active_storage.rb @@ -0,0 +1,12 @@ +# This migration comes from active_storage (originally 20191206030411) +class CreateActiveStorageVariantRecords < ActiveRecord::Migration[6.0] + def change + create_table :active_storage_variant_records do |t| + t.belongs_to :blob, null: false, index: false + 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 +end diff --git a/db/migrate/20220903174045_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb b/db/migrate/20220903174045_remove_not_null_on_active_storage_blobs_checksum.active_storage.rb new file mode 100644 index 0000000000000000000000000000000000000000..93c8b85ade5aff50be236c33ca8f349905aca73d --- /dev/null +++ b/db/migrate/20220903174045_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/schema.rb b/db/schema.rb index 210b5d0d995ba0661889d9b5033c155c72bba4a5..fc21d0c60ca29438b50c155b0cef05dc6557895a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -2,17 +2,17 @@ # of editing this file, please use the migrations feature of Active Record to # incrementally modify your database, and then regenerate this schema definition. # -# Note that this schema.rb definition is the authoritative source for your -# database schema. If you need to create the application database on another -# system, you should be using db:schema:load, not running all the migrations -# from scratch. The latter is a flawed and unsustainable approach (the more migrations -# you'll amass, the slower it'll run and the greater likelihood for issues). +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2021_11_21_195100) do +ActiveRecord::Schema[6.1].define(version: 2022_09_03_174045) do - create_table "abilities", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", force: :cascade do |t| + create_table "abilities", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| t.bigint "community_id" t.string "name" t.text "description" @@ -27,7 +27,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["community_id"], name: "index_abilities_on_community_id" end - create_table "ability_queues", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", force: :cascade do |t| + create_table "ability_queues", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| t.bigint "community_user_id" t.text "comment" t.boolean "completed" @@ -36,7 +36,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["community_user_id"], name: "index_ability_queues_on_community_user_id" end - create_table "active_storage_attachments", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "active_storage_attachments", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.string "name", null: false t.string "record_type", null: false t.bigint "record_id", null: false @@ -46,18 +46,25 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true end - create_table "active_storage_blobs", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "active_storage_blobs", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.string "key", null: false t.string "filename", null: false t.string "content_type" t.text "metadata" t.bigint "byte_size", null: false - t.string "checksum", null: false + t.string "checksum" t.datetime "created_at", null: false + t.string "service_name", null: false t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true end - create_table "audit_logs", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "active_storage_variant_records", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| + t.bigint "blob_id", null: false + t.string "variation_digest", null: false + t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true + end + + create_table "audit_logs", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.string "log_type" t.string "event_type" t.string "related_type" @@ -74,7 +81,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["user_id"], name: "index_audit_logs_on_user_id" end - create_table "blocked_items", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "blocked_items", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.string "item_type" t.text "value" t.datetime "expires" @@ -84,20 +91,20 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.datetime "updated_at", null: false end - create_table "categories", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "categories", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.string "name" - t.text "short_wiki", limit: 16777215 + t.text "short_wiki", size: :medium t.bigint "community_id" t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.text "display_post_types", limit: 16777215 + t.text "display_post_types", size: :medium t.boolean "is_homepage" t.bigint "tag_set_id" t.integer "min_trust_level" t.string "button_text" t.string "color_code" - t.text "asking_guidance_override", limit: 16777215 - t.text "answering_guidance_override", limit: 16777215 + t.text "asking_guidance_override", size: :medium + t.text "answering_guidance_override", size: :medium t.integer "min_view_trust_level" t.bigint "license_id" t.integer "sequence" @@ -109,12 +116,12 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["tag_set_id"], name: "index_categories_on_tag_set_id" end - create_table "categories_moderator_tags", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "categories_moderator_tags", id: false, charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.bigint "category_id" t.bigint "tag_id" end - create_table "categories_post_types", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "categories_post_types", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.bigint "category_id", null: false t.bigint "post_type_id", null: false t.integer "upvote_rep", default: 0, null: false @@ -122,26 +129,26 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["category_id", "post_type_id"], name: "index_categories_post_types_on_category_id_and_post_type_id", unique: true end - create_table "categories_required_tags", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "categories_required_tags", id: false, charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.bigint "category_id" t.bigint "tag_id" end - create_table "categories_topic_tags", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "categories_topic_tags", id: false, charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.bigint "category_id" t.bigint "tag_id" end - create_table "close_reasons", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "close_reasons", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.string "name" - t.text "description", limit: 16777215 + t.text "description", size: :medium t.boolean "active" t.boolean "requires_other_post" t.bigint "community_id" t.index ["community_id"], name: "index_close_reasons_on_community_id" end - create_table "comment_threads", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "comment_threads", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.string "title" t.integer "reply_count", default: 0, null: false t.bigint "post_id" @@ -163,7 +170,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["post_id"], name: "index_comment_threads_on_post_id" end - create_table "comments", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "comments", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.datetime "created_at", null: false t.datetime "updated_at", null: false t.integer "post_id" @@ -182,7 +189,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["user_id"], name: "index_comments_on_user_id" end - create_table "communities", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "communities", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.string "name", null: false t.string "host", null: false t.datetime "created_at", null: false @@ -192,7 +199,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["host"], name: "index_communities_on_host" end - create_table "community_users", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "community_users", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.bigint "community_id", null: false t.bigint "user_id", null: false t.boolean "is_moderator" @@ -212,13 +219,13 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["user_id"], name: "index_community_users_on_user_id" end - create_table "error_logs", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "error_logs", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.bigint "community_id" t.bigint "user_id" t.string "klass" - t.text "message", limit: 16777215 - t.text "backtrace", limit: 16777215 - t.text "request_uri", limit: 16777215, null: false + t.text "message", size: :medium + t.text "backtrace", size: :medium + t.text "request_uri", size: :medium, null: false t.string "host", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false @@ -228,7 +235,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["user_id"], name: "index_error_logs_on_user_id" end - create_table "flags", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "flags", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.text "reason" t.datetime "created_at", null: false t.datetime "updated_at", null: false @@ -253,7 +260,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["user_id"], name: "index_flags_on_user_id" end - create_table "licenses", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "licenses", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.string "name" t.string "url" t.boolean "default" @@ -266,7 +273,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["name"], name: "index_licenses_on_name" end - create_table "micro_auth_apps", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "micro_auth_apps", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.string "name" t.string "app_id" t.string "public_key" @@ -287,7 +294,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["user_id"], name: "index_micro_auth_apps_on_user_id" end - create_table "micro_auth_tokens", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "micro_auth_tokens", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.bigint "app_id" t.bigint "user_id" t.string "token" @@ -302,7 +309,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["user_id"], name: "index_micro_auth_tokens_on_user_id" end - create_table "notifications", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "notifications", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.text "content" t.string "link" t.boolean "is_read", default: false @@ -314,7 +321,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["user_id"], name: "index_notifications_on_user_id" end - create_table "pinned_links", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "pinned_links", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.bigint "community_id" t.string "label" t.string "link" @@ -328,7 +335,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["post_id"], name: "index_pinned_links_on_post_id" end - create_table "post_flag_types", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", force: :cascade do |t| + create_table "post_flag_types", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| t.bigint "community_id" t.string "name" t.text "description" @@ -342,7 +349,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["post_type_id"], name: "index_post_flag_types_on_post_type_id" end - create_table "post_histories", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "post_histories", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.integer "post_history_type_id" t.integer "user_id" t.datetime "created_at", null: false @@ -360,7 +367,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["user_id"], name: "index_post_histories_on_user_id" end - create_table "post_history_tags", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "post_history_tags", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.bigint "post_history_id" t.bigint "tag_id" t.string "relationship" @@ -370,7 +377,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["tag_id"], name: "index_post_history_tags_on_tag_id" end - create_table "post_history_types", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "post_history_types", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.string "name" t.string "description" t.datetime "created_at", null: false @@ -378,7 +385,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["name"], name: "index_post_history_types_on_name" end - create_table "post_types", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "post_types", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.string "name" t.text "description" t.boolean "has_answers", default: false, null: false @@ -399,7 +406,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["name"], name: "index_post_types_on_name" end - create_table "posts", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "posts", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.string "title" t.text "body" t.string "tags_cache" @@ -460,7 +467,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["user_id"], name: "index_posts_on_user_id" end - create_table "posts_tags", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "posts_tags", id: false, charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.bigint "tag_id" t.bigint "post_id" t.index ["post_id", "tag_id"], name: "index_posts_tags_on_post_id_and_tag_id", unique: true @@ -468,7 +475,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["tag_id"], name: "index_posts_tags_on_tag_id" end - create_table "privileges", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "privileges", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.datetime "created_at", null: false t.datetime "updated_at", null: false t.string "name" @@ -478,14 +485,14 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["name"], name: "index_privileges_on_name" end - create_table "privileges_users", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "privileges_users", id: false, charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.integer "privilege_id", null: false t.integer "user_id", null: false t.index ["privilege_id", "user_id"], name: "index_privileges_users_on_privilege_id_and_user_id" t.index ["user_id", "privilege_id"], name: "index_privileges_users_on_user_id_and_privilege_id" end - create_table "reaction_types", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "reaction_types", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.string "name" t.text "description" t.string "on_post_label" @@ -502,7 +509,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["post_type_id"], name: "index_reaction_types_on_post_type_id" end - create_table "reactions", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "reactions", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.bigint "user_id" t.bigint "reaction_type_id" t.bigint "post_id" @@ -515,7 +522,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["user_id"], name: "index_reactions_on_user_id" end - create_table "site_settings", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "site_settings", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.string "name" t.text "value" t.datetime "created_at", null: false @@ -529,7 +536,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["name"], name: "index_site_settings_on_name" end - create_table "subscriptions", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "subscriptions", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.string "type", null: false t.string "qualifier" t.bigint "user_id" @@ -544,7 +551,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["user_id"], name: "index_subscriptions_on_user_id" end - create_table "suggested_edits", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "suggested_edits", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.bigint "post_id" t.bigint "user_id" t.bigint "community_id" @@ -570,17 +577,17 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["user_id"], name: "index_suggested_edits_on_user_id" end - create_table "suggested_edits_before_tags", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "suggested_edits_before_tags", id: false, charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.bigint "suggested_edit_id", null: false t.bigint "tag_id", null: false end - create_table "suggested_edits_tags", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "suggested_edits_tags", id: false, charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.bigint "suggested_edit_id", null: false t.bigint "tag_id", null: false end - create_table "tag_sets", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "tag_sets", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.string "name" t.bigint "community_id", null: false t.datetime "created_at", null: false @@ -588,7 +595,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["community_id"], name: "index_tag_sets_on_community_id" end - create_table "tags", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "tags", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.string "name" t.datetime "created_at", null: false t.datetime "updated_at", null: false @@ -603,7 +610,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["tag_set_id"], name: "index_tags_on_tag_set_id" end - create_table "thread_followers", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "thread_followers", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.bigint "comment_thread_id" t.bigint "user_id" t.datetime "created_at", null: false @@ -612,7 +619,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["user_id"], name: "index_thread_followers_on_user_id" end - create_table "user_abilities", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci", force: :cascade do |t| + create_table "user_abilities", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| t.bigint "community_user_id" t.bigint "ability_id" t.boolean "is_suspended", default: false @@ -624,7 +631,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["community_user_id"], name: "index_user_abilities_on_community_user_id" end - create_table "users", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "users", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.string "email" t.string "encrypted_password" t.string "reset_password_token" @@ -673,7 +680,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["username"], name: "index_users_on_username" end - create_table "votes", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "votes", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.integer "vote_type" t.datetime "created_at", null: false t.datetime "updated_at", null: false @@ -686,7 +693,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["user_id"], name: "index_votes_on_user_id" end - create_table "warning_templates", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "warning_templates", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.bigint "community_id" t.string "name" t.text "body" @@ -696,7 +703,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do t.index ["community_id"], name: "index_warning_templates_on_community_id" end - create_table "warnings", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci", force: :cascade do |t| + create_table "warnings", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t| t.bigint "community_user_id" t.text "body" t.boolean "is_suspension" @@ -712,6 +719,7 @@ ActiveRecord::Schema.define(version: 2021_11_21_195100) do add_foreign_key "abilities", "communities" add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id" + add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id" add_foreign_key "audit_logs", "communities" add_foreign_key "audit_logs", "users" add_foreign_key "categories", "licenses" diff --git a/docker/create_admin_and_community.rb b/docker/create_admin_and_community.rb index 90e785a84263304befc88910d76204082bca7dba..7c152b8e253399597254b54b5b9d84198d1c31f2 100644 --- a/docker/create_admin_and_community.rb +++ b/docker/create_admin_and_community.rb @@ -1,6 +1,6 @@ # 1. Create the community community_name = ENV['COMMUNITY_NAME'] || 'Dinosaur Community' -Community.create(name: community_name, host: "localhost:#{ENV['LOCAL_DEV_PORT']}") +Community.create(name: community_name, host: "localhost:#{ENV.fetch('LOCAL_DEV_PORT', nil)}") Rails.cache.clear # 2. Create the admin user, ensure doesn't require confirmation diff --git a/config/initializers/namespaced_cache.rb b/lib/namespaced_env_cache.rb similarity index 87% rename from config/initializers/namespaced_cache.rb rename to lib/namespaced_env_cache.rb index c19b7efd1404bb5d1fed274c6c14b248f774ab77..af5130e70f6fae819ba0450ea592005b341ac455 100644 --- a/config/initializers/namespaced_cache.rb +++ b/lib/namespaced_env_cache.rb @@ -63,12 +63,18 @@ module QPixel end end + # We have to statically report that we support cache versioning even though this depends on the underlying class. + # However, this is not really a problem since all cache stores provided by activesupport support the feature and + # we only use the redis cache (by activesupport) for QPixel. + def self.supports_cache_versioning? + true + end + private + def construct_ns_key(key, include_community: true) c_id = RequestContext.community_id if include_community "#{Rails.env}://#{[c_id, key].compact.join('/')}" end end end - -Rails.cache = QPixel::NamespacedEnvCache.new(Rails.cache) diff --git a/test/controllers/advertisement_controller_test.rb b/test/controllers/advertisement_controller_test.rb index 43f5704a73ab76a518087b5bdc8e2430ced32cf6..eed236ff76a0a2153c2df77c0c0a7d7664448901 100644 --- a/test/controllers/advertisement_controller_test.rb +++ b/test/controllers/advertisement_controller_test.rb @@ -6,7 +6,7 @@ class AdvertisementControllerTest < ActionController::TestCase test 'index should return html' do get :index assert_response(200) - assert_equal response.content_type, 'text/html' + assert_equal 'text/html', response.media_type end test 'image paths should return png' do @@ -15,13 +15,13 @@ class AdvertisementControllerTest < ActionController::TestCase [:codidact, :community].each do |path| get path assert_response(200) - assert_equal response.content_type, 'image/png' + assert_equal 'image/png', response.media_type end end test 'post image path should return png' do get :specific_question, params: { id: posts(:question_one).id } assert_response(200) - assert_equal response.content_type, 'image/png' + assert_equal 'image/png', response.media_type end end diff --git a/test/controllers/categories_controller_test.rb b/test/controllers/categories_controller_test.rb index 61ae07734b74cfdbf0765b59f1480fb92e0ec70f..3f207197453a559b15d834880ef2d70cbb842be3 100644 --- a/test/controllers/categories_controller_test.rb +++ b/test/controllers/categories_controller_test.rb @@ -65,7 +65,7 @@ class CategoriesControllerTest < ActionController::TestCase sign_in users(:admin) post :create, params: { category: { name: 'test', short_wiki: 'test', display_post_types: [Question.post_type_id], post_type_ids: [Question.post_type_id, Answer.post_type_id], - tag_set: tag_sets(:main).id, color_code: 'blue', + tag_set_id: tag_sets(:main).id, color_code: 'blue', license_id: licenses(:cc_by_sa).id } } assert_response 302 assert_not_nil assigns(:category) diff --git a/test/fixtures/flags.yml b/test/fixtures/flags.yml index c6c1c3020657078fbef009365bd7e9e17934d39c..64a57be06f00267335615c00975f43d952fd8cd5 100644 --- a/test/fixtures/flags.yml +++ b/test/fixtures/flags.yml @@ -1,5 +1,5 @@ one: reason: ABCDEF GHIJKL MNOPQR STUVWX YZ - post: answer_two + post: answer_two (Post) user: standard_user community: sample diff --git a/test/models/vote_test.rb b/test/models/vote_test.rb index 5fd34543b6287766f73247a81620d727c0775793..69cffe1968e38f91c9c9ac8bb105e1a02aca0a32 100644 --- a/test/models/vote_test.rb +++ b/test/models/vote_test.rb @@ -24,7 +24,7 @@ class VoteTest < ActiveSupport::TestCase cpt = CategoryPostType.find_by(category: posts(:question_two).category, post_type: posts(:question_two).post_type) rep_change_up = cpt.upvote_rep rep_change_down = cpt.downvote_rep - expected_rep_change = 3 * rep_change_up + 2 * rep_change_down + expected_rep_change = (3 * rep_change_up) + (2 * rep_change_down) post.votes.create([ { user: users(:standard_user), recv_user: author, vote_type: 1 }, @@ -45,7 +45,7 @@ class VoteTest < ActiveSupport::TestCase cpt = CategoryPostType.find_by(category: posts(:answer_one).category, post_type: posts(:answer_one).post_type) rep_change_up = cpt.upvote_rep rep_change_down = cpt.downvote_rep - expected = 4 * rep_change_up + 1 * rep_change_down + expected = (4 * rep_change_up) + (1 * rep_change_down) assert_equal expected, Vote.total_rep_change(post.votes) end end diff --git a/test/test_helper.rb b/test/test_helper.rb index cab55a4fef2de24cf658f5dd684db4eb615fb07e..c41d9b27cb6b2dfb3db4aeaf003e4aca620fc94d 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -36,17 +36,20 @@ class ActiveSupport::TestCase end end + PostMock = Struct.new(:title, :body_markdown, :body, :tags_cache, :edit, keyword_init: true) + def sample - OpenStruct.new( + PostMock.new( title: 'This is a sample title', body_markdown: 'This is a sample post with some **Markdown** and [a link](/).', body: '<p>This is a sample post with some <b>Markdown</b> and <a href="/">a link</a></p>', tags_cache: ['discussion', 'posts', 'tags'], - edit: OpenStruct.new( + edit: PostMock.new( title: 'This is another sample title', body_markdown: 'This is a sample post with some more **Markdown** and [a link](/).', body: '<p>This is a sample post with some more <b>Markdown</b> and <a href="/">a link</a></p>', - tags_cache: ['discussion', 'posts', 'tags', 'edits'] + tags_cache: ['discussion', 'posts', 'tags', 'edits'], + edit: nil ) ) end