From 26030c71c7b300c30367222f263d74b8d2142ecf Mon Sep 17 00:00:00 2001 From: erdgeist Date: Thu, 25 Jun 2026 17:50:55 +0200 Subject: Rails 5.2 application fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Rename before_filter → before_action across all controllers - Fix string conditions in validators to lambda syntax (node.rb) - Fix publish_draft!: move staged slug/parent logic outside draft guard, use move_to_child_of for parent changes, add nil guard for no-op calls - Fix update_unique_names_of_children: use parent_id traversal instead of lft/rgt descendants (awesome_nested_set 3.x lft/rgt update bug) - Fix unique_path to return Array instead of String - Fix Occurrence.delete_all syntax for Rails 5 - Fix Page.find_with_outdated_translations: use includes instead of all - Fix outdated_translations?: use find instead of splat array --- app/controllers/pages_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/controllers/pages_controller.rb') diff --git a/app/controllers/pages_controller.rb b/app/controllers/pages_controller.rb index a684327..f5609eb 100644 --- a/app/controllers/pages_controller.rb +++ b/app/controllers/pages_controller.rb @@ -2,7 +2,7 @@ class PagesController < ApplicationController # Private - before_filter :login_required + before_action :login_required def preview @page = Page.find(params[:id]) -- cgit v1.3 From c06723ee715512c2033c7786c48f15674585b56b Mon Sep 17 00:00:00 2001 From: erdgeist Date: Fri, 26 Jun 2026 01:59:57 +0200 Subject: Stage 4: Rails 5.2 -> 6.1 on Ruby 2.7.2 - routing-filter 0.6.3 -> 0.7.0 (Rails 6.1 compatibility) - RSS named routes rss_xml/rss_rdf added - RouteWithParams workarounds: will_paginate_patch, content_path shim, safe_path helper - Paperclip removed, replaced with FileAttachment concern (preserves URL scheme) - Assets resource moved to /admin/assets (Sprockets middleware conflict) - ApplicationRecord base class added, all models migrated - Strong parameters added to Assets, Occurrences, Events, MenuItems controllers - update_attributes -> update throughout - render :nothing -> head :ok/:not_found throughout - language_selector rewritten (removes :overwrite_params) - Environment files updated for Rails 6.1 (eager_load, public_file_server, ActionMailer) - Arel::Visitors::DepthFirst and Integer/Float duration patches removed from test_helper - AssetsController tests added (10 tests covering upload, variants, destroy, auth) - ImageMagick geometry: 460x250! for headline crop (not # which is invalid in IM6) 129 runs, 311 assertions, 5 failures (all pre-existing), 0 errors --- .ruby-gemset | 2 +- .ruby-version | 2 +- Gemfile | 16 +- Gemfile.lock | 230 +++++++++++++------------- app/assets/config/manifest.js | 0 app/controllers/assets_controller.rb | 17 +- app/controllers/content_controller.rb | 9 +- app/controllers/events_controller.rb | 10 +- app/controllers/menu_items_controller.rb | 15 +- app/controllers/nodes_controller.rb | 6 +- app/controllers/occurrences_controller.rb | 11 +- app/controllers/pages_controller.rb | 2 +- app/controllers/users_controller.rb | 2 +- app/helpers/admin_helper.rb | 6 +- app/helpers/link_helper.rb | 25 ++- app/models/application_record.rb | 3 + app/models/asset.rb | 17 +- app/models/concerns/file_attachment.rb | 124 ++++++++++++++ app/models/event.rb | 2 +- app/models/menu_item.rb | 2 +- app/models/node.rb | 2 +- app/models/occurrence.rb | 2 +- app/models/page.rb | 2 +- app/models/permission.rb | 2 +- app/models/related_asset.rb | 2 +- app/models/user.rb | 2 +- app/views/content/_search.html.erb | 2 +- app/views/content/_tags.html.erb | 2 +- app/views/layouts/application.html.erb | 9 +- app/views/layouts/application.html.erb.bak | 54 ------ config/environments/development.rb | 7 +- config/environments/production.rb | 14 +- config/environments/test.rb | 7 +- config/initializers/arel_patch.rb | 12 -- config/initializers/will_paginate_patch.rb | 13 ++ config/routes.rb | 11 +- lib/chaos_importer.rb | 4 +- lib/update_importer.rb | 4 +- test/controllers/assets_controller_test.rb | 170 +++++++++++++++++++ test/controllers/revisions_controller_test.rb | 2 +- test/fixtures/files/test_document.pdf | Bin 0 -> 9246 bytes test/fixtures/files/test_image.png | Bin 0 -> 49854 bytes test/models/page_test.rb | 2 +- test/models/user_test.rb | 4 +- test/test_helper.rb | 67 -------- 45 files changed, 557 insertions(+), 340 deletions(-) create mode 100644 app/assets/config/manifest.js create mode 100644 app/models/application_record.rb create mode 100644 app/models/concerns/file_attachment.rb delete mode 100644 app/views/layouts/application.html.erb.bak delete mode 100644 config/initializers/arel_patch.rb create mode 100644 config/initializers/will_paginate_patch.rb create mode 100644 test/fixtures/files/test_document.pdf create mode 100644 test/fixtures/files/test_image.png (limited to 'app/controllers/pages_controller.rb') diff --git a/.ruby-gemset b/.ruby-gemset index 48fed33..a363b74 100644 --- a/.ruby-gemset +++ b/.ruby-gemset @@ -1 +1 @@ -rails5-upgrade +rails6-upgrade diff --git a/.ruby-version b/.ruby-version index 56b1397..2eb2fe9 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -ruby-2.5.8 +ruby-2.7.2 diff --git a/Gemfile b/Gemfile index b43b986..3184db4 100644 --- a/Gemfile +++ b/Gemfile @@ -1,28 +1,26 @@ source 'https://rubygems.org' -gem 'rails', '5.2.8.1' +gem 'rails', '6.1.7.10' +gem 'concurrent-ruby', '1.3.4' gem 'pg', '~> 1.0' -gem 'acts-as-taggable-on', '~> 6.0' +gem 'acts-as-taggable-on', '~> 7.0' gem 'awesome_nested_set', '~> 3.4.0' gem 'acts_as_list' -gem 'globalize', '~> 5.2.0' -gem 'routing-filter', '~> 0.6' -gem 'paperclip', '~> 3.5' +gem 'globalize', '~> 6.0' +gem 'routing-filter', '~> 0.7.0' gem 'will_paginate', '~> 3.0' gem 'exception_notification', '~> 4.5' gem 'libxml-ruby', '~> 3.2', :require => 'xml' -gem 'nokogiri', '~> 1.10.10' -gem 'loofah', '~> 2.20.0' -gem 'rails-html-sanitizer', '~> 1.4.4' +gem 'nokogiri', '~> 1.13' gem 'jquery-rails' gem 'unicorn', '~> 1.1' group :assets do - gem 'sass-rails', '~> 5.0' + gem 'sass-rails', '~> 6.0' gem 'coffee-rails', '~> 4.0' gem 'uglifier', '>= 1.0.3' end diff --git a/Gemfile.lock b/Gemfile.lock index 74b71e7..d8294bd 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -8,59 +8,73 @@ GIT GEM remote: https://rubygems.org/ specs: - actioncable (5.2.8.1) - actionpack (= 5.2.8.1) + actioncable (6.1.7.10) + actionpack (= 6.1.7.10) + activesupport (= 6.1.7.10) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailer (5.2.8.1) - actionpack (= 5.2.8.1) - actionview (= 5.2.8.1) - activejob (= 5.2.8.1) + actionmailbox (6.1.7.10) + actionpack (= 6.1.7.10) + activejob (= 6.1.7.10) + activerecord (= 6.1.7.10) + activestorage (= 6.1.7.10) + activesupport (= 6.1.7.10) + mail (>= 2.7.1) + actionmailer (6.1.7.10) + actionpack (= 6.1.7.10) + actionview (= 6.1.7.10) + activejob (= 6.1.7.10) + activesupport (= 6.1.7.10) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (5.2.8.1) - actionview (= 5.2.8.1) - activesupport (= 5.2.8.1) - rack (~> 2.0, >= 2.0.8) + actionpack (6.1.7.10) + actionview (= 6.1.7.10) + activesupport (= 6.1.7.10) + rack (~> 2.0, >= 2.0.9) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.2.8.1) - activesupport (= 5.2.8.1) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (6.1.7.10) + actionpack (= 6.1.7.10) + activerecord (= 6.1.7.10) + activestorage (= 6.1.7.10) + activesupport (= 6.1.7.10) + nokogiri (>= 1.8.5) + actionview (6.1.7.10) + activesupport (= 6.1.7.10) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.0.3) - activejob (5.2.8.1) - activesupport (= 5.2.8.1) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (6.1.7.10) + activesupport (= 6.1.7.10) globalid (>= 0.3.6) - activemodel (5.2.8.1) - activesupport (= 5.2.8.1) - activerecord (5.2.8.1) - activemodel (= 5.2.8.1) - activesupport (= 5.2.8.1) - arel (>= 9.0) - activestorage (5.2.8.1) - actionpack (= 5.2.8.1) - activerecord (= 5.2.8.1) - marcel (~> 1.0.0) - activesupport (5.2.8.1) + activemodel (6.1.7.10) + activesupport (= 6.1.7.10) + activerecord (6.1.7.10) + activemodel (= 6.1.7.10) + activesupport (= 6.1.7.10) + activestorage (6.1.7.10) + actionpack (= 6.1.7.10) + activejob (= 6.1.7.10) + activerecord (= 6.1.7.10) + activesupport (= 6.1.7.10) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (6.1.7.10) concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) - minitest (~> 5.1) - tzinfo (~> 1.1) - acts-as-taggable-on (6.5.0) - activerecord (>= 5.0, < 6.1) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + zeitwerk (~> 2.3) + acts-as-taggable-on (7.0.0) + activerecord (>= 5.0, < 6.2) acts_as_list (1.1.0) activerecord (>= 4.2) - arel (9.0.0) awesome_nested_set (3.4.0) activerecord (>= 4.0.0, < 7.0) base64 (0.3.0) builder (3.3.0) - climate_control (0.2.0) - cocaine (0.5.8) - climate_control (>= 0.0.3, < 1.0) coffee-rails (4.2.2) coffee-script (>= 2.2.0) railties (>= 4.0.0) @@ -68,8 +82,8 @@ GEM coffee-script-source execjs coffee-script-source (1.12.2) - concurrent-ruby (1.3.7) - crass (1.0.6) + concurrent-ruby (1.3.4) + crass (1.0.7) digest (3.2.1) erubi (1.13.1) exception_notification (4.6.0) @@ -79,9 +93,9 @@ GEM ffi (1.17.4) globalid (1.1.0) activesupport (>= 5.0) - globalize (5.2.0) - activemodel (>= 4.2, < 5.3) - activerecord (>= 4.2, < 5.3) + globalize (6.3.0) + activemodel (>= 4.2, < 7.2) + activerecord (>= 4.2, < 7.2) request_store (~> 1.0) i18n (1.14.8) concurrent-ruby (~> 1.0) @@ -92,24 +106,20 @@ GEM thor (>= 0.14, < 2.0) libxml-ruby (3.2.4) logger (1.7.0) - loofah (2.20.0) + loofah (2.25.1) crass (~> 1.0.2) - nokogiri (>= 1.5.9) + nokogiri (>= 1.12.0) mail (2.9.0) logger mini_mime (>= 0.1.1) net-imap net-pop net-smtp - marcel (1.0.4) + marcel (1.2.1) method_source (1.1.0) - mime-types (3.7.0) - logger - mime-types-data (~> 3.2025, >= 3.2025.0507) - mime-types-data (3.2026.0414) mini_mime (1.1.2) - mini_portile2 (2.4.0) - minitest (5.15.0) + mini_portile2 (2.8.9) + minitest (5.26.1) net-imap (0.2.2) digest net-protocol @@ -123,31 +133,30 @@ GEM digest net-protocol timeout - nio4r (2.7.3) - nokogiri (1.10.10) - mini_portile2 (~> 2.4.0) - paperclip (3.5.4) - activemodel (>= 3.0.0) - activesupport (>= 3.0.0) - cocaine (~> 0.5.3) - mime-types + nio4r (2.7.5) + nokogiri (1.15.7) + mini_portile2 (~> 2.8.2) + racc (~> 1.4) pg (1.5.9) power_assert (3.0.1) + racc (1.8.1) rack (2.2.23) rack-test (2.2.0) rack (>= 1.3) - rails (5.2.8.1) - actioncable (= 5.2.8.1) - actionmailer (= 5.2.8.1) - actionpack (= 5.2.8.1) - actionview (= 5.2.8.1) - activejob (= 5.2.8.1) - activemodel (= 5.2.8.1) - activerecord (= 5.2.8.1) - activestorage (= 5.2.8.1) - activesupport (= 5.2.8.1) - bundler (>= 1.3.0) - railties (= 5.2.8.1) + rails (6.1.7.10) + actioncable (= 6.1.7.10) + actionmailbox (= 6.1.7.10) + actionmailer (= 6.1.7.10) + actionpack (= 6.1.7.10) + actiontext (= 6.1.7.10) + actionview (= 6.1.7.10) + activejob (= 6.1.7.10) + activemodel (= 6.1.7.10) + activerecord (= 6.1.7.10) + activestorage (= 6.1.7.10) + activesupport (= 6.1.7.10) + bundler (>= 1.15.0) + railties (= 6.1.7.10) sprockets-rails (>= 2.0.0) rails-controller-testing (1.0.5) actionpack (>= 5.0.1.rc1) @@ -157,51 +166,47 @@ GEM activesupport (>= 5.0.0) minitest nokogiri (>= 1.6) - rails-html-sanitizer (1.4.4) - loofah (~> 2.19, >= 2.19.1) - railties (5.2.8.1) - actionpack (= 5.2.8.1) - activesupport (= 5.2.8.1) + rails-html-sanitizer (1.7.0) + loofah (~> 2.25) + nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) + railties (6.1.7.10) + actionpack (= 6.1.7.10) + activesupport (= 6.1.7.10) method_source - rake (>= 0.8.7) - thor (>= 0.19.0, < 2.0) + rake (>= 12.2) + thor (~> 1.0) rake (13.4.2) - rb-fsevent (0.11.2) - rb-inotify (0.11.1) - ffi (~> 1.0) request_store (1.7.0) rack (>= 1.4) - routing-filter (0.6.3) - actionpack (>= 4.2) - activesupport (>= 4.2) - 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) - sprockets (3.7.5) - base64 + routing-filter (0.7.0) + actionpack (>= 6.1) + activesupport (>= 6.1) + 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 + sprockets (4.2.2) concurrent-ruby (~> 1.0) - rack (> 1, < 3) - sprockets-rails (3.4.2) - actionpack (>= 5.2) - activesupport (>= 5.2) + logger + rack (>= 2.2.4, < 4) + sprockets-rails (3.5.2) + actionpack (>= 6.1) + activesupport (>= 6.1) sprockets (>= 3.0.0) strscan (3.1.8) test-unit (3.7.8) power_assert thor (1.2.2) - thread_safe (0.3.6) tilt (2.7.0) timeout (0.4.0) - tzinfo (1.2.11) - thread_safe (~> 0.1) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) uglifier (4.2.1) execjs (>= 0.3.0, < 3) unicorn (1.1.7) @@ -211,33 +216,32 @@ GEM websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) will_paginate (3.3.1) + zeitwerk (2.6.18) PLATFORMS ruby DEPENDENCIES - acts-as-taggable-on (~> 6.0) + acts-as-taggable-on (~> 7.0) acts_as_list awesome_nested_set (~> 3.4.0) chaos_calendar! coffee-rails (~> 4.0) + concurrent-ruby (= 1.3.4) exception_notification (~> 4.5) - globalize (~> 5.2.0) + globalize (~> 6.0) jquery-rails libxml-ruby (~> 3.2) - loofah (~> 2.20.0) - nokogiri (~> 1.10.10) - paperclip (~> 3.5) + nokogiri (~> 1.13) pg (~> 1.0) - rails (= 5.2.8.1) + rails (= 6.1.7.10) rails-controller-testing - rails-html-sanitizer (~> 1.4.4) - routing-filter (~> 0.6) - sass-rails (~> 5.0) + routing-filter (~> 0.7.0) + sass-rails (~> 6.0) test-unit (~> 3.5) uglifier (>= 1.0.3) unicorn (~> 1.1) will_paginate (~> 3.0) BUNDLED WITH - 2.3.27 + 2.4.22 diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js new file mode 100644 index 0000000..e69de29 diff --git a/app/controllers/assets_controller.rb b/app/controllers/assets_controller.rb index a11bbdd..d150e06 100644 --- a/app/controllers/assets_controller.rb +++ b/app/controllers/assets_controller.rb @@ -7,10 +7,9 @@ class AssetsController < ApplicationController layout 'admin' def index - @assets = Asset.all.paginate( - :page => params[:page], - :per_page => 20, - :order => 'id DESC' + @assets = Asset.order('id DESC').paginate( + :page => params[:page], + :per_page => 20 ) end @@ -44,7 +43,7 @@ class AssetsController < ApplicationController # POST /assets # POST /assets.xml def create - @asset = Asset.new(params[:asset]) + @asset = Asset.new(asset_params) respond_to do |format| if @asset.save @@ -64,7 +63,7 @@ class AssetsController < ApplicationController @asset = Asset.find(params[:id]) respond_to do |format| - if @asset.update_attributes(params[:asset]) + if @asset.update(asset_params) flash[:notice] = 'Asset was successfully updated.' format.html { redirect_to(@asset) } format.xml { head :ok } @@ -86,4 +85,10 @@ class AssetsController < ApplicationController format.xml { head :ok } end end + + private + + def asset_params + params.require(:asset).permit(:name, :upload) + end end diff --git a/app/controllers/content_controller.rb b/app/controllers/content_controller.rb index 876bccf..8d33105 100644 --- a/app/controllers/content_controller.rb +++ b/app/controllers/content_controller.rb @@ -15,13 +15,14 @@ class ContentController < ApplicationController if @page and @page.public? render( - :file => @page.valid_template, + :template => @page.valid_template, :layout => true ) else render( - :file => Rails.root.join('public', '404.html'), - :status => 404 + :file => Rails.root.join('public', '404.html').to_s, + :status => 404, + :layout => false ) end @@ -32,7 +33,7 @@ class ContentController < ApplicationController @images = @page.assets.images render :file => "content/gallery" else - render :nothing => true, :status => 404 + head :not_found end end diff --git a/app/controllers/events_controller.rb b/app/controllers/events_controller.rb index 6eba476..7695e9b 100644 --- a/app/controllers/events_controller.rb +++ b/app/controllers/events_controller.rb @@ -47,7 +47,7 @@ class EventsController < ApplicationController # POST /events # POST /events.xml def create - @event = Event.new(params[:event]) + @event = Event.new(event_params) respond_to do |format| if @event.save @@ -67,7 +67,7 @@ class EventsController < ApplicationController @event = Event.find(params[:id]) respond_to do |format| - if @event.update_attributes(params[:event]) + if @event.update(event_params) flash[:notice] = 'Event was successfully updated.' format.html { redirect_to(edit_node_path(@event.node)) } format.xml { head :ok } @@ -89,4 +89,10 @@ class EventsController < ApplicationController format.xml { head :ok } end end + + private + + def event_params + params.require(:event).permit(:start_time, :end_time, :rrule, :custom_rrule, :allday, :url, :latitude, :longitude, :node_id, :location) + end end diff --git a/app/controllers/menu_items_controller.rb b/app/controllers/menu_items_controller.rb index 4018693..1b1eb59 100644 --- a/app/controllers/menu_items_controller.rb +++ b/app/controllers/menu_items_controller.rb @@ -14,11 +14,11 @@ class MenuItemsController < ApplicationController end def new - @menu_item = MenuItem.new params[:menu_item] + @menu_item = MenuItem.new menu_item_params end def create - if MenuItem.create( params[:menu_item] ) + if MenuItem.create( menu_item_params ) redirect_to menu_items_path else render :new @@ -32,7 +32,7 @@ class MenuItemsController < ApplicationController def update @menu_item = MenuItem.find( params[:id] ) - if @menu_item.update_attributes( params[:menu_item] ) + if @menu_item.update( menu_item_params ) redirect_to menu_items_path else render :edit @@ -48,10 +48,15 @@ class MenuItemsController < ApplicationController def sort params[:menu_items].each_with_index do |item_id, index| menu_item = MenuItem.find(item_id) - menu_item.update_attributes(:position => index + 1) + menu_item.update(:position => index + 1) end - render :nothing => true + head :ok end + private + + def menu_item_params + params.require(:menu_item).permit(:node_id, :path, :position, :type, :type_id) + end end diff --git a/app/controllers/nodes_controller.rb b/app/controllers/nodes_controller.rb index 482d0ac..bd60b27 100644 --- a/app/controllers/nodes_controller.rb +++ b/app/controllers/nodes_controller.rb @@ -36,7 +36,7 @@ class NodesController < ApplicationController @node.slug = params[:title].parameterize.to_s if @node.save - @node.draft.update_attributes(:title => params[:title]) + @node.draft.update(:title => params[:title]) case params[:kind] when "update" @node.draft.tag_list.add("update") @@ -70,10 +70,10 @@ class NodesController < ApplicationController end def update - @node.update_attributes(node_params) + @node.update(node_params) @draft = @node.find_or_create_draft current_user @draft.tag_list = params[:tag_list] - if @draft.update_attributes( page_params ) + if @draft.update( page_params ) flash[:notice] = "Draft has been saved: #{Time.now}" respond_to do |format| format.html { redirect_to edit_node_path(@node) } diff --git a/app/controllers/occurrences_controller.rb b/app/controllers/occurrences_controller.rb index 61b42ff..0f30ce3 100644 --- a/app/controllers/occurrences_controller.rb +++ b/app/controllers/occurrences_controller.rb @@ -45,7 +45,7 @@ class OccurrencesController < ApplicationController # POST /occurrences # POST /occurrences.xml def create - @occurrence = Occurrence.new(params[:occurrence]) + @occurrence = Occurrence.new(occurrence_params) respond_to do |format| if @occurrence.save @@ -65,7 +65,7 @@ class OccurrencesController < ApplicationController @occurrence = Occurrence.find(params[:id]) respond_to do |format| - if @occurrence.update_attributes(params[:occurrence]) + if @occurrence.update(occurrence_params) flash[:notice] = 'Occurrence was successfully updated.' format.html { redirect_to(@occurrence) } format.xml { head :ok } @@ -87,4 +87,11 @@ class OccurrencesController < ApplicationController format.xml { head :ok } end end + + private + + def occurrence_params + params.require(:occurrence).permit(:start_time, :end_time, :node_id, :event_id) + end + end diff --git a/app/controllers/pages_controller.rb b/app/controllers/pages_controller.rb index f5609eb..a40bf10 100644 --- a/app/controllers/pages_controller.rb +++ b/app/controllers/pages_controller.rb @@ -22,6 +22,6 @@ class PagesController < ApplicationController page = Page.find(params[:id]) page.update_assets(params[:images]) - render :nothing => true, :status => 200 + head :ok end end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 72e6058..98fd534 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -36,7 +36,7 @@ class UsersController < ApplicationController permitted = user_params permitted.delete(:admin) unless current_user.is_admin? - if @user.update_attributes(permitted) + if @user.update(permitted) flash[:notice] = "Updated user #{@user.login}" redirect_to user_path(@user) else diff --git a/app/helpers/admin_helper.rb b/app/helpers/admin_helper.rb index 389f6dc..e5c3d5c 100644 --- a/app/helpers/admin_helper.rb +++ b/app/helpers/admin_helper.rb @@ -1,11 +1,11 @@ module AdminHelper - + def language_selector case I18n.locale when :de - link_to raw('English'), url_for(:overwrite_params => {:locale => :en}) + link_to raw('English'), url_for(params.permit!.to_h.merge('locale' => 'en')) when :en - link_to raw('Deutsch'), url_for(:overwrite_params => {:locale => :de}) + link_to raw('Deutsch'), url_for(params.permit!.to_h.merge('locale' => 'de')) end end end diff --git a/app/helpers/link_helper.rb b/app/helpers/link_helper.rb index 85d8fbe..39ec495 100644 --- a/app/helpers/link_helper.rb +++ b/app/helpers/link_helper.rb @@ -45,9 +45,28 @@ module LinkHelper "Locked by #{@node.lock_owner.login}\n" + "Last modified #{@page.updated_at.to_s(:db)}" - link_to( - 'Unlock', unlock_node_path(@node), :method => :put, :data => { :confirm => message } + link_to 'Unlock', safe_path(:unlock_node_path, @node), :method => :put, :data => { :confirm => message } + end + + # Rails 6.1 workaround: content_path named helper returns RouteWithParams + # when called from within a catch-all glob route request context. + # Rails 6.1 workaround: named route helpers return RouteWithParams when called + # from within a catch-all glob route request context. + # Remove this method when upgrading to Rails 7.0+, where this is fixed. + def safe_path(name, *args) + Rails.application.routes.url_helpers.send(name, *args) + end + + def content_path(page_path = nil, options = {}) + if page_path.is_a?(Hash) + options = page_path + page_path = options.delete(:page_path) + end + options[:locale] ||= params[:locale] || I18n.locale + Rails.application.routes.url_helpers.content_path( + Array(page_path).join("/").sub(/^\//, ""), + options ) end - + end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 0000000..10a4cba --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + self.abstract_class = true +end diff --git a/app/models/asset.rb b/app/models/asset.rb index f6526f2..aca0ee8 100644 --- a/app/models/asset.rb +++ b/app/models/asset.rb @@ -1,20 +1,11 @@ -class Asset < ActiveRecord::Base +class Asset < ApplicationRecord + + include FileAttachment has_many :related_assets, :dependent => :destroy has_many :pages, :through => :related_assets - has_attached_file( - :upload, - :path => ":rails_root/public/system/:attachment/:id/:style/:filename", - :url => "/system/:attachment/:id/:style/:filename", - :styles => { - :medium => "300x300", - :thumb => "100x100", - :headline => "460x250#" - } - ) - - scope :images, -> { where(:upload_content_type => ["image/gif", "image/jpeg", "image/png"]) } + scope :images, -> { where(:upload_content_type => ["image/gif", "image/jpeg", "image/png", "image/webp"]) } scope :documents, -> { where(:upload_content_type => ["application/pdf", "text/plain", "text/rtf"]) } scope :audio, -> { where(:upload_content_type => ["audio/mpeg", "audio/x-m4a", "audio/wav", "audio/x-wav"]) } diff --git a/app/models/concerns/file_attachment.rb b/app/models/concerns/file_attachment.rb new file mode 100644 index 0000000..b3ff0f1 --- /dev/null +++ b/app/models/concerns/file_attachment.rb @@ -0,0 +1,124 @@ +# FileAttachment — minimal drop-in replacement for Paperclip's has_attached_file. +# +# Provides the same interface used throughout this codebase: +# asset.upload.url -> "/system/uploads/:id/original/:filename" +# asset.upload.url(:thumb) -> "/system/uploads/:id/thumb/:filename" +# asset.upload.content_type -> string +# asset.upload.size -> integer (bytes) +# +# Files are stored at: +# Rails.root/public/system/uploads/:id/:style/:filename +# +# Image variants are generated via ImageMagick (convert) on upload. +# Non-image files get only an original, no variants. +# +# To replace an asset: assign a new file to asset.upload= and save. +# The filename is fixed on first upload and preserved on replacement, +# keeping all public URLs stable. +# +# Future: if more sophisticated asset management is needed (versioning, +# S3, on-demand resizing), replace this module and keep the interface. + +module FileAttachment + extend ActiveSupport::Concern + + STYLES = { + medium: { geometry: "300x300>", format: nil }, + thumb: { geometry: "100x100>", format: nil }, + headline: { geometry: "460x250!", format: nil } + }.freeze + + IMAGE_CONTENT_TYPES = %w[image/jpeg image/gif image/png image/webp].freeze + + included do + attr_reader :upload + + after_initialize :build_upload_proxy + after_save :process_upload + before_destroy :delete_upload_files + end + + def upload=(uploaded_file) + return if uploaded_file.blank? + @pending_upload = uploaded_file + # Populate the database columns immediately so validations can use them + self.upload_file_name = sanitize_filename(uploaded_file.original_filename) + self.upload_content_type = uploaded_file.content_type.to_s.split(';').first.strip + self.upload_file_size = uploaded_file.size + self.upload_updated_at = Time.current + build_upload_proxy + end + + private + + def build_upload_proxy + @upload = UploadProxy.new(self) + end + + def process_upload + return unless @pending_upload + uploaded_file = @pending_upload + @pending_upload = nil + + original_path = file_path(:original) + FileUtils.mkdir_p(File.dirname(original_path)) + FileUtils.cp(uploaded_file.tempfile.path, original_path) + + if IMAGE_CONTENT_TYPES.include?(upload_content_type) + generate_variants(original_path) + end + end + + def generate_variants(original_path) + STYLES.each do |style, options| + dest_path = file_path(style) + FileUtils.mkdir_p(File.dirname(dest_path)) + system("convert", original_path, "-resize", options[:geometry], dest_path) + end + end + + def delete_upload_files + dir = Rails.root.join("public", "system", "uploads", id.to_s) + FileUtils.rm_rf(dir) if Dir.exist?(dir) + end + + def file_path(style) + Rails.root.join( + "public", "system", "uploads", + id.to_s, style.to_s, upload_file_name + ).to_s + end + + def sanitize_filename(filename) + File.basename(filename).gsub(/[^\w\.\-]/, '_') + end + + # Proxy object returned by asset.upload, providing the Paperclip-compatible + # interface used in views: .url, .url(:style), .content_type, .size + class UploadProxy + def initialize(record) + @record = record + end + + def url(style = :original) + return "" if @record.upload_file_name.blank? + "/system/uploads/#{@record.id}/#{style}/#{@record.upload_file_name}" + end + + def content_type + @record.upload_content_type.to_s + end + + def size + @record.upload_file_size.to_i + end + + def present? + @record.upload_file_name.present? + end + + def blank? + !present? + end + end +end diff --git a/app/models/event.rb b/app/models/event.rb index 23deed6..94a22e3 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -1,4 +1,4 @@ -class Event < ActiveRecord::Base +class Event < ApplicationRecord # Associations diff --git a/app/models/menu_item.rb b/app/models/menu_item.rb index eb82347..7769b7f 100644 --- a/app/models/menu_item.rb +++ b/app/models/menu_item.rb @@ -1,4 +1,4 @@ -class MenuItem < ActiveRecord::Base +class MenuItem < ApplicationRecord default_scope -> { where(:type => "MenuItem") } diff --git a/app/models/node.rb b/app/models/node.rb index d760f0a..f7a70d0 100644 --- a/app/models/node.rb +++ b/app/models/node.rb @@ -1,4 +1,4 @@ -class Node < ActiveRecord::Base +class Node < ApplicationRecord # Mixins and Plugins acts_as_nested_set diff --git a/app/models/occurrence.rb b/app/models/occurrence.rb index 8457ffd..3baf447 100644 --- a/app/models/occurrence.rb +++ b/app/models/occurrence.rb @@ -1,7 +1,7 @@ # TODO Make a gem out of the c wrapper require 'chaos_calendar' -class Occurrence < ActiveRecord::Base +class Occurrence < ApplicationRecord # Associations diff --git a/app/models/page.rb b/app/models/page.rb index 93debf8..d1e7439 100644 --- a/app/models/page.rb +++ b/app/models/page.rb @@ -1,6 +1,6 @@ require 'xml' -class Page < ActiveRecord::Base +class Page < ApplicationRecord PUBLIC_TEMPLATE_PATH = File.join(%w(custom page_templates public)) FULL_PUBLIC_TEMPLATE_PATH = Rails.root.join('app', 'views', PUBLIC_TEMPLATE_PATH) diff --git a/app/models/permission.rb b/app/models/permission.rb index f304538..1383a4b 100644 --- a/app/models/permission.rb +++ b/app/models/permission.rb @@ -1,4 +1,4 @@ -class Permission < ActiveRecord::Base +class Permission < ApplicationRecord # Validations validates_presence_of :user_id, :node_id, :granted validates_inclusion_of :granted, :in => [true, false] diff --git a/app/models/related_asset.rb b/app/models/related_asset.rb index 2b61c51..8f16460 100644 --- a/app/models/related_asset.rb +++ b/app/models/related_asset.rb @@ -1,4 +1,4 @@ -class RelatedAsset < ActiveRecord::Base +class RelatedAsset < ApplicationRecord belongs_to :page belongs_to :asset diff --git a/app/models/user.rb b/app/models/user.rb index a2540b5..92ac33a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,6 +1,6 @@ require 'digest/sha1' -class User < ActiveRecord::Base +class User < ApplicationRecord # Mixins and Plugins include Authentication include Authentication::ByPassword diff --git a/app/views/content/_search.html.erb b/app/views/content/_search.html.erb index aa91424..f732fca 100644 --- a/app/views/content/_search.html.erb +++ b/app/views/content/_search.html.erb @@ -1,3 +1,3 @@ -<%= form_tag search_path, :method => 'get' do %> +<%= form_tag safe_path(:search_path), :method => 'get' do %>
<%= text_field_tag :search_term, params[:search_term], :placeholder => 'suchen', :type => 'search' %>
<% end %> diff --git a/app/views/content/_tags.html.erb b/app/views/content/_tags.html.erb index 169ae84..387f51c 100644 --- a/app/views/content/_tags.html.erb +++ b/app/views/content/_tags.html.erb @@ -3,7 +3,7 @@

Tags

diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 2a46f09..84dcdc6 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -16,8 +16,8 @@ <%= stylesheet_link_tag "shadowbox" %> <%= javascript_include_tag 'public' %> - <%= auto_discovery_link_tag(:atom, {:locale => :de, :controller => "rss", :action => "updates", :format => :xml}) %> - <%= auto_discovery_link_tag(:rss, {:locale => :de, :controller => "rss", :action => "updates", :format => :rdf}) %> + <%= auto_discovery_link_tag(:atom, '/rss/updates.xml', title: "ATOM") %> + <%= auto_discovery_link_tag(:rss, '/rss/updates.rdf', title: "RSS") %>